~eliasnaur/gio

gio: initial API v1 PROPOSED

~pierrec: 5
 initial API
 app.Window.SetCursor: implemented for macos
 app.Window.SetCursor: added support for windows.go
 app.Window.SetCursor: stubs for android, ios, js, wayland and x11
 app/Window.SetCursor: fixed comment

 22 files changed, 174 insertions(+), 27 deletions(-)
#343869 apple.yml failed
#343870 freebsd.yml failed
#343871 linux.yml failed
#343872 openbsd.yml failed
The calls to NSCursor don't refer any particular view or window. How do
you ensure that the cursor is properly set when moving outside or
between windows. Looking at the example/windows example may be helpful.
Drop this change from the commit you send (you can leave as a local
change for testing).
Move this check to loop to not do it once per option, and to avoid
passing the app.Window to kitchen.
Why not use pointer.CursorName here?
Next
Please add a comment to app.Window.SetCursor that lists the supported
platforms.
gio/patches: FAILED in 3m37s

[initial API][0] from [~pierrec][1]

[0]: https://lists.sr.ht/~eliasnaur/gio/patches/15066
[1]: mailto:pierre.curto@gmail.com

✗ #343871 FAILED gio/patches/linux.yml   https://builds.sr.ht/~eliasnaur/job/343871
✗ #343872 FAILED gio/patches/openbsd.yml https://builds.sr.ht/~eliasnaur/job/343872
✗ #343870 FAILED gio/patches/freebsd.yml https://builds.sr.ht/~eliasnaur/job/343870
✗ #343869 FAILED gio/patches/apple.yml   https://builds.sr.ht/~eliasnaur/job/343869
Will do, thanks!

Le lun. 16 nov. 2020 à 17:56, Elias Naur <mail@eliasnaur.com> a écrit :
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~eliasnaur/gio/patches/15066/mbox | git am -3
Learn more about email & git

[PATCH gio 1/5] initial API Export this patch

From: pierre <pierre.curto@gmail.com>

---
 app/internal/window/os_macos.go |  4 ++++
 app/internal/window/window.go   |  3 +++
 app/window.go                   |  7 +++++++
 io/pointer/pointer.go           | 18 ++++++++++++++++++
 4 files changed, 32 insertions(+)

diff --git a/app/internal/window/os_macos.go b/app/internal/window/os_macos.go
index ef95b70..961aebd 100644
--- a/app/internal/window/os_macos.go
+++ b/app/internal/window/os_macos.go
@@ -122,6 +122,10 @@ func (w *window) WriteClipboard(s string) {
	})
}

func (w *window) SetCursor(name string) string {
	return ""
}

func (w *window) ShowTextInput(show bool) {}

func (w *window) SetAnimating(anim bool) {
diff --git a/app/internal/window/window.go b/app/internal/window/window.go
index 30ba360..e5bf11f 100644
--- a/app/internal/window/window.go
+++ b/app/internal/window/window.go
@@ -60,6 +60,9 @@ type Driver interface {
	// WriteClipboard requests a clipboard write.
	WriteClipboard(s string)

	// SetCursor updates the cursor in use and returns the current one.
	SetCursor(name string) string

	// Close the window.
	Close()
}
diff --git a/app/window.go b/app/window.go
index ed46958..62453da 100644
--- a/app/window.go
+++ b/app/window.go
@@ -5,6 +5,7 @@ package app
import (
	"errors"
	"fmt"
	"gioui.org/io/pointer"
	"image"
	"time"

@@ -209,6 +210,12 @@ func (w *Window) WriteClipboard(s string) {
	})
}

// SetCursorName changes the current window cursor to the one specified
// and returns the current one.
func (w *Window) SetCursorName(name pointer.CursorName) pointer.CursorName {
	return pointer.CursorName(w.driver.SetCursor(string(name)))
}

// Close the window. The window's event loop should exit when it receives
// system.DestroyEvent.
//
diff --git a/io/pointer/pointer.go b/io/pointer/pointer.go
index 3344d6b..44550e7 100644
--- a/io/pointer/pointer.go
+++ b/io/pointer/pointer.go
@@ -79,9 +79,27 @@ type Source uint8
// Buttons is a set of mouse buttons
type Buttons uint8

// CursorName is the name of a cursor.
type CursorName string

// Must match app/internal/input.areaKind
type areaKind uint8

const (
	// CursorArrow defines the default cursor.
	CursorArrow CursorName = "arrow"
	// CursorText defines the cursor to indicate text.
	CursorText CursorName = "text"
	// CursorPointer defines the cursor to indicate a link.
	CursorPointer CursorName = "pointer"
	// CursorMove defines the cursor to indicate moving an area.
	CursorMove CursorName = "move"
	// CursorVerticalResize defines the cursor to indicate vertical resize.
	CursorVerticalResize CursorName = "vertical resize"
	// CursorHorizontalResize defines the cursor to indicate horizontal resize.
	CursorHorizontalResize CursorName = "horizontal resize"
)

const (
	// A Cancel event is generated when the current gesture is
	// interrupted by other handlers or the system.
-- 
2.26.2
Thanks for taking this on.

Please squash your changes so there are two logical commits: one for the
gioui.org module, and one for the example module. They need to be
separate because the example/go.mod needs updating before kitchen can
refer to the new API.

Use a more descriptive title for the API commit. For example:

app: add support for system cursors
"defines" doesn't seem fitting. How about

// CursorArrow is the default cursor.

[PATCH gio 2/5] app.Window.SetCursor: implemented for macos Export this patch

From: pierre <pierre.curto@gmail.com>

Also added a section to the kitchen example to manipulate the cursor.
---
 app/internal/window/os_macos.go | 12 ++++++++++--
 app/internal/window/os_macos.m  | 24 ++++++++++++++++++++++++
 app/internal/window/window.go   |  5 +++--
 app/window.go                   |  6 ++++--
 example/go.mod                  |  2 ++
 example/kitchen/kitchen.go      | 33 ++++++++++++++++++++++++++++-----
 6 files changed, 71 insertions(+), 11 deletions(-)

diff --git a/app/internal/window/os_macos.go b/app/internal/window/os_macos.go
index 961aebd..a41d488 100644
--- a/app/internal/window/os_macos.go
+++ b/app/internal/window/os_macos.go
@@ -38,6 +38,7 @@ __attribute__ ((visibility ("hidden"))) CGFloat gio_viewHeight(CFTypeRef viewRef
__attribute__ ((visibility ("hidden"))) CGFloat gio_getViewBackingScale(CFTypeRef viewRef);
__attribute__ ((visibility ("hidden"))) CGFloat gio_getScreenBackingScale(void);
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_readClipboard(void);
__attribute__ ((visibility ("hidden"))) void gio_setCursor(unichar *chars, NSUInteger length);
__attribute__ ((visibility ("hidden"))) void gio_writeClipboard(unichar *chars, NSUInteger length);
__attribute__ ((visibility ("hidden"))) void gio_setNeedsDisplay(CFTypeRef viewRef);
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height, CGFloat minWidth, CGFloat minHeight, CGFloat maxWidth, CGFloat maxHeight);
@@ -122,8 +123,15 @@ func (w *window) WriteClipboard(s string) {
	})
}

func (w *window) SetCursor(name string) string {
	return ""
func (w *window) SetCursor(s string) {
	u16 := utf16.Encode([]rune(s))
	runOnMain(func() {
		var chars *C.unichar
		if len(u16) > 0 {
			chars = (*C.unichar)(unsafe.Pointer(&u16[0]))
		}
		C.gio_setCursor(chars, C.NSUInteger(len(u16)))
	})
}

func (w *window) ShowTextInput(show bool) {}
diff --git a/app/internal/window/os_macos.m b/app/internal/window/os_macos.m
index b8c0dee..4183bdc 100644
--- a/app/internal/window/os_macos.m
+++ b/app/internal/window/os_macos.m
@@ -67,6 +67,30 @@ CFTypeRef gio_readClipboard(void) {
	}
}

void gio_setCursor(unichar *chars, NSUInteger length) {
    @autoreleasepool {
        NSString *s = [NSString string];
        if (length > 0) {
           s = [NSString stringWithCharacters:chars length:length];
        }
        if ([s isEqualToString: @"arrow"]) {
           [NSCursor.arrowCursor set];
        } else if ([s isEqualToString: @"text"]) {
           [NSCursor.IBeamCursor set];
        } else if ([s isEqualToString: @"pointer"]) {
           [NSCursor.pointingHandCursor set];
        } else if ([s isEqualToString: @"move"]) {
           [NSCursor.crosshairCursor set];
        } else if ([s isEqualToString: @"vertical resize"]) {
           [NSCursor.resizeLeftRightCursor set];
        } else if ([s isEqualToString: @"horizontal resize"]) {
           [NSCursor.resizeUpDownCursor set];
        } else {
            [NSCursor.arrowCursor set];
        }
    }
}

CGFloat gio_viewHeight(CFTypeRef viewRef) {
	NSView *view = (__bridge NSView *)viewRef;
	return [view bounds].size.height;
diff --git a/app/internal/window/window.go b/app/internal/window/window.go
index e5bf11f..375b494 100644
--- a/app/internal/window/window.go
+++ b/app/internal/window/window.go
@@ -60,8 +60,9 @@ type Driver interface {
	// WriteClipboard requests a clipboard write.
	WriteClipboard(s string)

	// SetCursor updates the cursor in use and returns the current one.
	SetCursor(name string) string
	// SetCursor updates the current cursor to name.
	// If name is invalid, the arrow cursor is used.
	SetCursor(name string)

	// Close the window.
	Close()
diff --git a/app/window.go b/app/window.go
index 62453da..0e75b70 100644
--- a/app/window.go
+++ b/app/window.go
@@ -212,8 +212,10 @@ func (w *Window) WriteClipboard(s string) {

// SetCursorName changes the current window cursor to the one specified
// and returns the current one.
func (w *Window) SetCursorName(name pointer.CursorName) pointer.CursorName {
	return pointer.CursorName(w.driver.SetCursor(string(name)))
func (w *Window) SetCursorName(name pointer.CursorName) {
	go w.driverDo(func() {
		w.driver.SetCursor(string(name))
	})
}

// Close the window. The window's event loop should exit when it receives
diff --git a/example/go.mod b/example/go.mod
index 9d8656d..f0b9071 100644
--- a/example/go.mod
+++ b/example/go.mod
@@ -11,3 +11,5 @@ require (
	golang.org/x/image v0.0.0-20200618115811-c13761719519
	golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
)

replace gioui.org => ../
\ No newline at end of file
diff --git a/example/kitchen/kitchen.go b/example/kitchen/kitchen.go
index fb59eea..105dae9 100644
--- a/example/kitchen/kitchen.go
+++ b/example/kitchen/kitchen.go
@@ -15,12 +15,14 @@ import (
	"log"
	"math"
	"os"
	"strings"
	"time"

	"gioui.org/app"
	"gioui.org/app/headless"
	"gioui.org/f32"
	"gioui.org/font/gofont"
	"gioui.org/io/pointer"
	"gioui.org/io/router"
	"gioui.org/io/system"
	"gioui.org/layout"
@@ -96,7 +98,7 @@ func saveScreenshot(f string) error {
		Queue:       new(router.Router),
	}
	th := material.NewTheme(gofont.Collection())
	kitchen(gtx, th)
	kitchen(gtx, th, nil)
	w.Frame(gtx.Ops)
	img, err := w.Screenshot()
	if err != nil {
@@ -140,7 +142,7 @@ func loop(w *app.Window) error {
					}
				}

				transformedKitchen(gtx, th)
				transformedKitchen(gtx, th, w)
				e.Frame(gtx.Ops)
			}
		case p := <-progressIncrementer:
@@ -153,7 +155,7 @@ func loop(w *app.Window) error {
	}
}

func transformedKitchen(gtx layout.Context, th *material.Theme) layout.Dimensions {
func transformedKitchen(gtx layout.Context, th *material.Theme, w *app.Window) layout.Dimensions {
	if !transformTime.IsZero() {
		dt := float32(gtx.Now.Sub(transformTime).Seconds())
		angle := dt * .1
@@ -174,7 +176,7 @@ func transformedKitchen(gtx layout.Context, th *material.Theme) layout.Dimension
		op.Affine(tr).Add(gtx.Ops)
	}

	return kitchen(gtx, th)
	return kitchen(gtx, th, w)
}

var (
@@ -190,6 +192,7 @@ var (
	flatBtn           = new(widget.Clickable)
	disableBtn        = new(widget.Clickable)
	radioButtonsGroup = new(widget.Enum)
	cursorsGroup      = new(widget.Enum)
	list              = &layout.List{
		Axis: layout.Vertical,
	}
@@ -242,7 +245,7 @@ func (b iconAndTextButton) Layout(gtx layout.Context) layout.Dimensions {
	})
}

func kitchen(gtx layout.Context, th *material.Theme) layout.Dimensions {
func kitchen(gtx layout.Context, th *material.Theme, w *app.Window) layout.Dimensions {
	for _, e := range lineEditor.Events() {
		if e, ok := e.(widget.SubmitEvent); ok {
			topLabel = e.Text
@@ -375,6 +378,26 @@ func kitchen(gtx layout.Context, th *material.Theme) layout.Dimensions {
				}),
			)
		},
		func(gtx C) D {
			r := func(s string) layout.FlexChild {
				k := strings.ToLower(s)
				return layout.Rigid(func(gtx C) D {
					if w != nil && cursorsGroup.Changed() {
						w.SetCursorName(pointer.CursorName(cursorsGroup.Value))
					}
					return material.RadioButton(th, cursorsGroup, k, s).Layout(gtx)
				})
			}
			return layout.Flex{}.Layout(gtx,
				layout.Rigid(material.Body1(th, "Change cursor").Layout),
				r("Arrow"),
				r("Text"),
				r("Pointer"),
				r("Move"),
				r("Vertical resize"),
				r("Horizontal resize"),
			)
		},
	}

	return list.Layout(gtx, len(widgets), func(gtx C, i int) D {
-- 
2.26.2
The calls to NSCursor don't refer any particular view or window. How do
you ensure that the cursor is properly set when moving outside or
between windows. Looking at the example/windows example may be helpful.
Drop this change from the commit you send (you can leave as a local
change for testing).
Move this check to loop to not do it once per option, and to avoid
passing the app.Window to kitchen.

[PATCH gio 3/5] app.Window.SetCursor: added support for windows.go Export this patch

From: Pierre.Curto <pierre.curto@gmail.com>

Removed unused field on app/internal/window.resources.
Also changed the name of the move cursor to crosshair.
---
 app/internal/window/os_macos.m    |  2 +-
 app/internal/window/os_windows.go | 41 ++++++++++++++++++++++++++-----
 app/internal/windows/windows.go   | 13 +++++++++-
 example/kitchen/kitchen.go        |  2 +-
 io/pointer/pointer.go             |  4 +--
 5 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/app/internal/window/os_macos.m b/app/internal/window/os_macos.m
index 4183bdc..debb8f9 100644
--- a/app/internal/window/os_macos.m
+++ b/app/internal/window/os_macos.m
@@ -79,7 +79,7 @@ void gio_setCursor(unichar *chars, NSUInteger length) {
           [NSCursor.IBeamCursor set];
        } else if ([s isEqualToString: @"pointer"]) {
           [NSCursor.pointingHandCursor set];
        } else if ([s isEqualToString: @"move"]) {
        } else if ([s isEqualToString: @"crosshair"]) {
           [NSCursor.crosshairCursor set];
        } else if ([s isEqualToString: @"vertical resize"]) {
           [NSCursor.resizeLeftRightCursor set];
diff --git a/app/internal/window/os_windows.go b/app/internal/window/os_windows.go
index edf7f54..49646c0 100644
--- a/app/internal/window/os_windows.go
+++ b/app/internal/window/os_windows.go
@@ -45,6 +45,7 @@ type window struct {
	height      int
	stage       system.Stage
	pointerBtns pointer.Buttons
	cursor      syscall.Handle

	mu        sync.Mutex
	animating bool
@@ -74,8 +75,6 @@ var resources struct {
	handle syscall.Handle
	// class is the Gio window class from RegisterClassEx.
	class uint16
	// cursor is the arrow cursor resource
	cursor syscall.Handle
}

func Main() {
@@ -105,6 +104,9 @@ func NewWindow(window Callbacks, opts *Options) error {
		windows.ShowWindow(w.hwnd, windows.SW_SHOWDEFAULT)
		windows.SetForegroundWindow(w.hwnd)
		windows.SetFocus(w.hwnd)
		// Since the window class for the cursor is null,
		// set it here to show the cursor.
		w.SetCursor("")
		if err := w.loop(); err != nil {
			panic(err)
		}
@@ -120,17 +122,17 @@ func initResources() error {
		return err
	}
	resources.handle = hInst
	curs, err := windows.LoadCursor(windows.IDC_ARROW)
	if err != nil {
	if _, err := windows.LoadCursor(windows.IDC_ARROW); err != nil {
		return err
	}
	resources.cursor = curs
	// Leave the HCursor class NULL to be able to change the cursor.
	// See the remarks here:
	// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcursor
	wcls := windows.WndClassEx{
		CbSize:        uint32(unsafe.Sizeof(windows.WndClassEx{})),
		Style:         windows.CS_HREDRAW | windows.CS_VREDRAW | windows.CS_OWNDC,
		LpfnWndProc:   syscall.NewCallback(windowProc),
		HInstance:     hInst,
		HCursor:       curs,
		LpszClassName: syscall.StringToUTF16Ptr("GioWindow"),
	}
	cls, err := windows.RegisterClassEx(&wcls)
@@ -297,6 +299,8 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
				Y: w.minmax.maxHeight + w.deltas.height,
			}
		}
	case windows.WM_SETCURSOR:
		windows.SetCursor(w.cursor)
	}

	return windows.DefWindowProc(hwnd, msg, wParam, lParam)
@@ -546,6 +550,31 @@ func (w *window) writeClipboard(s string) error {
	return nil
}

func (w *window) SetCursor(name string) {
	var curID uint16
	switch name {
	case "arrow":
		curID = windows.IDC_ARROW
	case "text":
		curID = windows.IDC_IBEAM
	case "pointer":
		curID = windows.IDC_HAND
	case "crosshair":
		curID = windows.IDC_CROSS
	case "vertical resize":
		curID = windows.IDC_SIZENS
	case "horizontal resize":
		curID = windows.IDC_SIZEWE
	default:
		curID = windows.IDC_ARROW
	}
	c, err := windows.LoadCursor(curID)
	if err != nil {
		return
	}
	w.cursor = c
}

func (w *window) ShowTextInput(show bool) {}

func (w *window) HDC() syscall.Handle {
diff --git a/app/internal/windows/windows.go b/app/internal/windows/windows.go
index 29e7f99..087de0f 100644
--- a/app/internal/windows/windows.go
+++ b/app/internal/windows/windows.go
@@ -61,7 +61,12 @@ const (

	CW_USEDEFAULT = -2147483648

	IDC_ARROW = 32512
	IDC_ARROW  = 32512
	IDC_IBEAM  = 32513
	IDC_HAND   = 32649
	IDC_CROSS  = 32515
	IDC_SIZENS = 32645
	IDC_SIZEWE = 32644

	INFINITE = 0xFFFFFFFF

@@ -145,6 +150,7 @@ const (
	WM_PAINT         = 0x000F
	WM_CLOSE         = 0x0010
	WM_QUIT          = 0x0012
	WM_SETCURSOR     = 0x0020
	WM_SETFOCUS      = 0x0007
	WM_KILLFOCUS     = 0x0008
	WM_SHOWWINDOW    = 0x0018
@@ -226,6 +232,7 @@ var (
	_ScreenToClient              = user32.NewProc("ScreenToClient")
	_ShowWindow                  = user32.NewProc("ShowWindow")
	_SetCapture                  = user32.NewProc("SetCapture")
	_SetCursor                   = user32.NewProc("SetCursor")
	_SetClipboardData            = user32.NewProc("SetClipboardData")
	_SetForegroundWindow         = user32.NewProc("SetForegroundWindow")
	_SetFocus                    = user32.NewProc("SetFocus")
@@ -513,6 +520,10 @@ func SetClipboardData(format uint32, mem syscall.Handle) error {
	return nil
}

func SetCursor(h syscall.Handle) {
	_SetCursor.Call(uintptr(h))
}

func SetTimer(hwnd syscall.Handle, nIDEvent uintptr, uElapse uint32, timerProc uintptr) error {
	r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), uintptr(uElapse), timerProc)
	if r == 0 {
diff --git a/example/kitchen/kitchen.go b/example/kitchen/kitchen.go
index 105dae9..6eea40f 100644
--- a/example/kitchen/kitchen.go
+++ b/example/kitchen/kitchen.go
@@ -393,7 +393,7 @@ func kitchen(gtx layout.Context, th *material.Theme, w *app.Window) layout.Dimen
				r("Arrow"),
				r("Text"),
				r("Pointer"),
				r("Move"),
				r("Crosshair"),
				r("Vertical resize"),
				r("Horizontal resize"),
			)
diff --git a/io/pointer/pointer.go b/io/pointer/pointer.go
index 44550e7..7fb6c9e 100644
--- a/io/pointer/pointer.go
+++ b/io/pointer/pointer.go
@@ -92,8 +92,8 @@ const (
	CursorText CursorName = "text"
	// CursorPointer defines the cursor to indicate a link.
	CursorPointer CursorName = "pointer"
	// CursorMove defines the cursor to indicate moving an area.
	CursorMove CursorName = "move"
	// CursorCrossHair defines the cursor to indicate precise location.
	CursorCrossHair CursorName = "crosshair"
	// CursorVerticalResize defines the cursor to indicate vertical resize.
	CursorVerticalResize CursorName = "vertical resize"
	// CursorHorizontalResize defines the cursor to indicate horizontal resize.
-- 
2.26.2
Why not use pointer.CursorName here?

[PATCH gio 4/5] app.Window.SetCursor: stubs for android, ios, js, wayland and x11 Export this patch

From: pierre <pierre.curto@gmail.com>

---
 app/internal/window/os_android.go | 2 ++
 app/internal/window/os_ios.go     | 2 ++
 app/internal/window/os_js.go      | 4 ++++
 app/internal/window/os_macos.go   | 4 ++--
 app/internal/window/os_wayland.go | 4 ++++
 app/internal/window/os_x11.go     | 4 ++++
 6 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/app/internal/window/os_android.go b/app/internal/window/os_android.go
index dac0bf3..d8031ba 100644
--- a/app/internal/window/os_android.go
+++ b/app/internal/window/os_android.go
@@ -392,6 +392,8 @@ func (w *window) SetAnimating(anim bool) {
	}
}

func (w *window) SetCursor(string) {}

func (w *window) draw(sync bool) {
	win := w.aNativeWindow()
	width, height := C.ANativeWindow_getWidth(win), C.ANativeWindow_getHeight(win)
diff --git a/app/internal/window/os_ios.go b/app/internal/window/os_ios.go
index 1865454..09140df 100644
--- a/app/internal/window/os_ios.go
+++ b/app/internal/window/os_ios.go
@@ -249,6 +249,8 @@ func (w *window) SetAnimating(anim bool) {
	}
}

func (w *window) SetCursor(string) {}

func (w *window) onKeyCommand(name string) {
	w.w.Event(key.Event{
		Name: name,
diff --git a/app/internal/window/os_js.go b/app/internal/window/os_js.go
index 7f3ffc5..9ff5e18 100644
--- a/app/internal/window/os_js.go
+++ b/app/internal/window/os_js.go
@@ -396,6 +396,10 @@ func (w *window) WriteClipboard(s string) {
	w.clipboard.Call("writeText", s)
}

func (w *window) SetCursor(name string) {
	//TODO SetCursor
}

func (w *window) ShowTextInput(show bool) {
	// Run in a goroutine to avoid a deadlock if the
	// focus change result in an event.
diff --git a/app/internal/window/os_macos.go b/app/internal/window/os_macos.go
index a41d488..c623371 100644
--- a/app/internal/window/os_macos.go
+++ b/app/internal/window/os_macos.go
@@ -123,8 +123,8 @@ func (w *window) WriteClipboard(s string) {
	})
}

func (w *window) SetCursor(s string) {
	u16 := utf16.Encode([]rune(s))
func (w *window) SetCursor(name string) {
	u16 := utf16.Encode([]rune(name))
	runOnMain(func() {
		var chars *C.unichar
		if len(u16) > 0 {
diff --git a/app/internal/window/os_wayland.go b/app/internal/window/os_wayland.go
index 60f59b1..9d80e61 100644
--- a/app/internal/window/os_wayland.go
+++ b/app/internal/window/os_wayland.go
@@ -917,6 +917,10 @@ func (w *window) WriteClipboard(s string) {
	w.disp.wakeup()
}

func (w *window) SetCursor(name string) {
	//TODO SetCursor
}

func (w *window) resetFling() {
	w.fling.start = false
	w.fling.anim = fling.Animation{}
diff --git a/app/internal/window/os_x11.go b/app/internal/window/os_x11.go
index 17bdd5a..9a6abb5 100644
--- a/app/internal/window/os_x11.go
+++ b/app/internal/window/os_x11.go
@@ -112,6 +112,10 @@ func (w *x11Window) WriteClipboard(s string) {
	w.wakeup()
}

func (w *x11Window) SetCursor(name string) {
	//TODO SetCursor
}

func (w *x11Window) ShowTextInput(show bool) {}

// Close the window.
-- 
2.26.2
Please add a comment to app.Window.SetCursor that lists the supported
platforms.

[PATCH gio 5/5] app/Window.SetCursor: fixed comment Export this patch

From: pierre <pierre.curto@gmail.com>

---
 app/window.go | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/app/window.go b/app/window.go
index 0e75b70..deb719b 100644
--- a/app/window.go
+++ b/app/window.go
@@ -5,12 +5,12 @@ package app
import (
	"errors"
	"fmt"
	"gioui.org/io/pointer"
	"image"
	"time"

	"gioui.org/app/internal/window"
	"gioui.org/io/event"
	"gioui.org/io/pointer"
	"gioui.org/io/profile"
	"gioui.org/io/router"
	"gioui.org/io/system"
@@ -210,8 +210,7 @@ func (w *Window) WriteClipboard(s string) {
	})
}

// SetCursorName changes the current window cursor to the one specified
// and returns the current one.
// SetCursorName changes the current window cursor to name.
func (w *Window) SetCursorName(name pointer.CursorName) {
	go w.driverDo(func() {
		w.driver.SetCursor(string(name))
-- 
2.26.2
gio/patches: FAILED in 3m37s

[initial API][0] from [~pierrec][1]

[0]: https://lists.sr.ht/~eliasnaur/gio/patches/15066
[1]: mailto:pierre.curto@gmail.com

✗ #343871 FAILED gio/patches/linux.yml   https://builds.sr.ht/~eliasnaur/job/343871
✗ #343872 FAILED gio/patches/openbsd.yml https://builds.sr.ht/~eliasnaur/job/343872
✗ #343870 FAILED gio/patches/freebsd.yml https://builds.sr.ht/~eliasnaur/job/343870
✗ #343869 FAILED gio/patches/apple.yml   https://builds.sr.ht/~eliasnaur/job/343869