From 7b8939c35e2fd75445d648a89a15db2a04b9bf42 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Tue, 21 May 2024 12:31:23 -0700 Subject: [PATCH] move to NativeWindow interface, implement for other platforms --- driver/desktop/window.go | 11 --------- driver/native.go | 28 +++++++++++++++++++---- internal/driver/glfw/window_darwin.go | 24 +++++++++++++++++++ internal/driver/glfw/window_notwindows.go | 16 ------------- internal/driver/glfw/window_wayland.go | 20 ++++++++++++++++ internal/driver/glfw/window_windows.go | 7 +++--- internal/driver/glfw/window_x11.go | 23 ++++++++++++++++++- internal/driver/mobile/window_android.go | 20 ++++++++++++++++ internal/driver/mobile/window_ios.go | 15 ++++++++++++ window.go | 10 ++++++++ 10 files changed, 137 insertions(+), 37 deletions(-) delete mode 100644 driver/desktop/window.go create mode 100644 internal/driver/glfw/window_darwin.go create mode 100644 internal/driver/mobile/window_android.go create mode 100644 internal/driver/mobile/window_ios.go diff --git a/driver/desktop/window.go b/driver/desktop/window.go deleted file mode 100644 index a70f221a18..0000000000 --- a/driver/desktop/window.go +++ /dev/null @@ -1,11 +0,0 @@ -package desktop - -// Window defines the desktop specific extensions to a fyne.Window. -// -// Since: 2.5 -type Window interface { - // RunNative executes the given function, passing platform-specific context - // information related to the window. The possible contexts that may be passed - // are defined in the `driver` package and differ per OS. - RunNative(func(ctx any) error) error -} diff --git a/driver/native.go b/driver/native.go index 1688d86fa2..abd183268b 100644 --- a/driver/native.go +++ b/driver/native.go @@ -9,16 +9,34 @@ type AndroidContext struct { } // UnknownContext is passed to the RunNative callback when it is executed -// on devices without special native context. +// on devices or windows without special native context. // // Since: 2.3 type UnknownContext struct{} -// WindowsContext is passed to the `(desktop.Window).RunNative` callback -// when it is executed on a Microsoft Windows desktop device. +// WindowsWindowContext is passed to the `(fyne.NativeWindow).RunNative` callback +// when it is executed on a Microsoft Windows device. // // Since: 2.5 -type WindowsContext struct { - // HWND is the WinAPI HWND for the window. +type WindowsWindowContext struct { + // HWND is the window handle for the native window. HWND uintptr } + +// MacWindowContext is passed to the `(fyne.NativeWindow).RunNative` callback +// when it is executed on a Mac OS device. +// +// Since: 2.5 +type MacWindowContext struct { + // NSWindow is the window handle for the native window. + NSWindow uintptr +} + +// X11WindowContext is passed to the `(fyne.NativeWindow).RunNative` callback +// when it is executed on a device with the X11 windowing system. +// +// Since: 2.5 +type X11WindowContext struct { + // WindowHandle is the window handle for the native X11 window. + WindowHandle string +} diff --git a/internal/driver/glfw/window_darwin.go b/internal/driver/glfw/window_darwin.go new file mode 100644 index 0000000000..7a2f9d2052 --- /dev/null +++ b/internal/driver/glfw/window_darwin.go @@ -0,0 +1,24 @@ +//go:build darwin + +package glfw + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver" +) + +// assert we are implementing fyne.NativeWindow +var _ fyne.NativeWindow = (*window)(nil) + +func (w *window) RunNative(f func(any) error) error { + var err error + done := make(chan struct{}) + runOnMain(func() { + err = f(driver.MacWindowContext{ + NSWindow: uintptr(w.view().GetCocoaWindow()), + }) + close(done) + }) + <-done + return err +} diff --git a/internal/driver/glfw/window_notwindows.go b/internal/driver/glfw/window_notwindows.go index 8fc92c0a05..03108435c9 100644 --- a/internal/driver/glfw/window_notwindows.go +++ b/internal/driver/glfw/window_notwindows.go @@ -4,8 +4,6 @@ package glfw import ( "fyne.io/fyne/v2" - "fyne.io/fyne/v2/driver" - "fyne.io/fyne/v2/driver/desktop" "fyne.io/fyne/v2/internal/scale" ) @@ -15,17 +13,3 @@ func (w *window) setDarkMode() { func (w *window) computeCanvasSize(width, height int) fyne.Size { return fyne.NewSize(scale.ToFyneCoordinate(w.canvas, width), scale.ToFyneCoordinate(w.canvas, height)) } - -// assert we are implementing desktop.Window -var _ desktop.Window = (*window)(nil) - -func (w *window) RunNative(f func(any) error) error { - var err error - done := make(chan struct{}) - runOnMain(func() { - err = f(driver.UnknownContext{}) - close(done) - }) - <-done - return err -} diff --git a/internal/driver/glfw/window_wayland.go b/internal/driver/glfw/window_wayland.go index ea6b84f0bb..943538337f 100644 --- a/internal/driver/glfw/window_wayland.go +++ b/internal/driver/glfw/window_wayland.go @@ -2,7 +2,27 @@ package glfw +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver" +) + // GetWindowHandle returns the window handle. Only implemented for X11 currently. func (w *window) GetWindowHandle() string { return "" // TODO: Find a way to get the Wayland handle for xdg_foreign protocol. Return "wayland:{id}". } + +// assert we are implementing fyne.NativeWindow +var _ fyne.NativeWindow = (*window)(nil) + +func (w *window) RunNative(f func(any) error) error { + var err error + done := make(chan struct{}) + runOnMain(func() { + // TODO: define driver.WaylandWindowContext and pass window handle + err = f(driver.UnknownContext{}) + close(done) + }) + <-done + return err +} diff --git a/internal/driver/glfw/window_windows.go b/internal/driver/glfw/window_windows.go index 266a599121..cab525e2bf 100644 --- a/internal/driver/glfw/window_windows.go +++ b/internal/driver/glfw/window_windows.go @@ -7,7 +7,6 @@ import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/driver" - "fyne.io/fyne/v2/driver/desktop" "fyne.io/fyne/v2/internal/scale" "golang.org/x/sys/windows/registry" @@ -53,14 +52,14 @@ func (w *window) computeCanvasSize(width, height int) fyne.Size { return fyne.NewSize(scale.ToFyneCoordinate(w.canvas, width), scale.ToFyneCoordinate(w.canvas, height)) } -// assert we are implementing desktop.Window -var _ desktop.Window = (*window)(nil) +// assert we are implementing fyne.NativeWindow +var _ fyne.NativeWindow = (*window)(nil) func (w *window) RunNative(f func(any) error) error { var err error done := make(chan struct{}) runOnMain(func() { - err = f(driver.WindowsContext{ + err = f(driver.WindowsWindowContext{ HWND: uintptr(unsafe.Pointer(w.view().GetWin32Window())), }) close(done) diff --git a/internal/driver/glfw/window_x11.go b/internal/driver/glfw/window_x11.go index 13ed9b010f..23aed71d62 100644 --- a/internal/driver/glfw/window_x11.go +++ b/internal/driver/glfw/window_x11.go @@ -2,10 +2,31 @@ package glfw -import "strconv" +import ( + "strconv" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver" +) // GetWindowHandle returns the window handle. Only implemented for X11 currently. func (w *window) GetWindowHandle() string { xid := uint(w.viewport.GetX11Window()) return "x11:" + strconv.FormatUint(uint64(xid), 16) } + +// assert we are implementing fyne.NativeWindow +var _ fyne.NativeWindow = (*window)(nil) + +func (w *window) RunNative(f func(any) error) error { + var err error + done := make(chan struct{}) + runOnMain(func() { + err = f(driver.X11WindowContext{ + WindowHandle: w.GetWindowHandle(), + }) + close(done) + }) + <-done + return err +} diff --git a/internal/driver/mobile/window_android.go b/internal/driver/mobile/window_android.go new file mode 100644 index 0000000000..1e3758be9b --- /dev/null +++ b/internal/driver/mobile/window_android.go @@ -0,0 +1,20 @@ +//go:build android + +package mobile + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver" + "fyne.io/fyne/v2/internal/driver/mobile/app" +) + +// Assert we are satisfying the NativeWindow interface +var _ fyne.NativeWindow = (*window)(nil) + +func (w *window) RunNative(f func(context any) error) error { + return app.RunOnJVM(func(vm, env, ctx uintptr) error { + // TODO: define driver.AndroidWindowContext that also includes the View + data := &driver.AndroidContext{VM: vm, Env: env, Ctx: ctx} + return f(data) + }) +} diff --git a/internal/driver/mobile/window_ios.go b/internal/driver/mobile/window_ios.go new file mode 100644 index 0000000000..e7f95faf35 --- /dev/null +++ b/internal/driver/mobile/window_ios.go @@ -0,0 +1,15 @@ +//go:build ios + +package mobile + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver" +) + +// Assert we are satisfying the NativeWindow interface +var _ fyne.NativeWindow = (*window)(nil) + +func (w *window) RunNative(fn func(context any) error) error { + return fn(&driver.UnknownContext{}) +} diff --git a/window.go b/window.go index 3e366acb96..e2f51b8c93 100644 --- a/window.go +++ b/window.go @@ -103,3 +103,13 @@ type Window interface { // Clipboard returns the system clipboard Clipboard() Clipboard } + +// NativeWindow is an extension interface for Window that gives access +// to platform-native features of application windows. +// +// Since: 2.5 +type NativeWindow interface { + // RunNative provides a way to execute code within the platform-specific runtime context for a window. + // The context types are defined in the `driver` package and the specific context passed will differ by platform. + RunNative(func(context any) error) error +}