From 5dc293fe4fd31127deb57493749aadbe3f319388 Mon Sep 17 00:00:00 2001 From: TotallyGamerJet Date: Sun, 10 Sep 2023 13:05:42 -0400 Subject: [PATCH] internal/ui: use new OBJC API (#2750) Updates #1162 --- go.mod | 4 +- go.sum | 8 +- internal/ui/ui_glfw_darwin.go | 241 +++++++++++++++++----------------- 3 files changed, 124 insertions(+), 129 deletions(-) diff --git a/go.mod b/go.mod index 6715bc453..ddc6b3f21 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/hajimehoshi/ebiten/v2 go 1.18 require ( - github.com/ebitengine/oto/v3 v3.1.0-alpha.2.0.20230907160415-270e2cbf1b2a - github.com/ebitengine/purego v0.5.0-alpha.2 + github.com/ebitengine/oto/v3 v3.1.0-alpha.2.0.20230909164631-3369785c90ea + github.com/ebitengine/purego v0.5.0-alpha.2.0.20230909154830-63192295690d github.com/go-text/typesetting v0.0.0-20230905121921-abdbcca6e0eb github.com/hajimehoshi/bitmapfont/v3 v3.0.0 github.com/hajimehoshi/go-mp3 v0.3.4 diff --git a/go.sum b/go.sum index 113c2e05b..ce0ac4645 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -github.com/ebitengine/oto/v3 v3.1.0-alpha.2.0.20230907160415-270e2cbf1b2a h1:Oagu27Kc7g00dvG0Hv89cgJG5ZvY6tDJL0KnIEyeISs= -github.com/ebitengine/oto/v3 v3.1.0-alpha.2.0.20230907160415-270e2cbf1b2a/go.mod h1:33ZrprO86svDJzUiIGDPMY47Nn0iquc7CVzjNZ5X7XY= -github.com/ebitengine/purego v0.5.0-alpha.2 h1:LKY/juINoHspp9sRqRAmIw1VoaHaPqD8KbKgbYAECCE= -github.com/ebitengine/purego v0.5.0-alpha.2/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= +github.com/ebitengine/oto/v3 v3.1.0-alpha.2.0.20230909164631-3369785c90ea h1:KM0GTGD2heyFImodvmPjJyxkXadH7agMpAkPukYp2tk= +github.com/ebitengine/oto/v3 v3.1.0-alpha.2.0.20230909164631-3369785c90ea/go.mod h1:ofLbkwlSk+3/3OiYtDXBSf8SDPKVxXxRtA47yu4j6AY= +github.com/ebitengine/purego v0.5.0-alpha.2.0.20230909154830-63192295690d h1:N+CZYJ1d76GVNdM14ToK7Plieyn4AZI6/qhmFiFFUx0= +github.com/ebitengine/purego v0.5.0-alpha.2.0.20230909154830-63192295690d/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= github.com/go-text/typesetting v0.0.0-20230905121921-abdbcca6e0eb h1:4GpJirtA8yY24aqbU3uppiXGYiVpWfLIrqc2NNKKk9s= github.com/go-text/typesetting v0.0.0-20230905121921-abdbcca6e0eb/go.mod h1:evDBbvNR/KaVFZ2ZlDSOWWXIUKq0wCOEtzLxRM8SG3k= github.com/go-text/typesetting-utils v0.0.0-20230616150549-2a7df14b6a22 h1:LBQTFxP2MfsyEDqSKmUBZaDuDHN1vpqDyOZjcqS7MYI= diff --git a/internal/ui/ui_glfw_darwin.go b/internal/ui/ui_glfw_darwin.go index 4f41ed4c5..d0bc1cb40 100644 --- a/internal/ui/ui_glfw_darwin.go +++ b/internal/ui/ui_glfw_darwin.go @@ -18,6 +18,7 @@ package ui import ( "fmt" + "reflect" "unsafe" "github.com/ebitengine/purego/objc" @@ -29,129 +30,122 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl" ) -var ( - class_EbitengineWindowDelegate objc.Class -) - -type windowDelegate struct { - isa objc.Class `objc:"EbitengineWindowDelegate : NSObject "` - origDelegate objc.ID - origResizable bool -} - -func (w *windowDelegate) pushResizableState(win objc.ID) { - window := cocoa.NSWindow{ID: win} - w.origResizable = window.StyleMask()&cocoa.NSWindowStyleMaskResizable != 0 - if !w.origResizable { - window.SetStyleMask(window.StyleMask() | cocoa.NSWindowStyleMaskResizable) - } -} - -func (w *windowDelegate) popResizableState(win objc.ID) { - if !w.origResizable { - window := cocoa.NSWindow{ID: win} - window.SetStyleMask(window.StyleMask() & ^uint(cocoa.NSWindowStyleMaskResizable)) - } - w.origResizable = false -} - -func (w *windowDelegate) InitWithOrigDelegate(cmd objc.SEL, origDelegate objc.ID) objc.ID { - self := objc.ID(unsafe.Pointer(w)).SendSuper(sel_init) - if self != 0 { - w = *(**windowDelegate)(unsafe.Pointer(&self)) - w.origDelegate = origDelegate - } - return self -} - -// The method set of origDelegate must sync with GLFWWindowDelegate's implementation. -// See cocoa_window.m in GLFW. - -func (w *windowDelegate) WindowShouldClose(cmd objc.SEL, notification objc.ID) bool { - return w.origDelegate.Send(cmd, notification) != 0 -} - -func (w *windowDelegate) WindowDidResize(cmd objc.SEL, notification objc.ID) { - w.origDelegate.Send(cmd, notification) -} - -func (w *windowDelegate) WindowDidMove(cmd objc.SEL, notification objc.ID) { - w.origDelegate.Send(cmd, notification) -} - -func (w *windowDelegate) WindowDidMiniaturize(cmd objc.SEL, notification objc.ID) { - w.origDelegate.Send(cmd, notification) -} - -func (w *windowDelegate) WindowDidDeminiaturize(cmd objc.SEL, notification objc.ID) { - w.origDelegate.Send(cmd, notification) -} - -func (w *windowDelegate) WindowDidBecomeKey(cmd objc.SEL, notification objc.ID) { - w.origDelegate.Send(cmd, notification) -} - -func (w *windowDelegate) WindowDidResignKey(cmd objc.SEL, notification objc.ID) { - w.origDelegate.Send(cmd, notification) -} - -func (w *windowDelegate) WindowDidChangeOcclusionState(cmd objc.SEL, notification objc.ID) { - w.origDelegate.Send(cmd, notification) -} - -func (w *windowDelegate) WindowWillEnterFullScreen(cmd objc.SEL, notification objc.ID) { - w.pushResizableState(cocoa.NSNotification{ID: notification}.Object()) -} - -func (w *windowDelegate) WindowDidEnterFullScreen(cmd objc.SEL, notification objc.ID) { - w.popResizableState(cocoa.NSNotification{ID: notification}.Object()) -} - -func (w *windowDelegate) WindowWillExitFullScreen(cmd objc.SEL, notification objc.ID) { - w.pushResizableState(cocoa.NSNotification{ID: notification}.Object()) -} - -func (w *windowDelegate) WindowDidExitFullScreen(cmd objc.SEL, notification objc.ID) { - w.popResizableState(cocoa.NSNotification{ID: notification}.Object()) - // Do not call setFrame here (#2295). setFrame here causes unexpected results. -} - -func (w *windowDelegate) Selector(cmd string) objc.SEL { - switch cmd { - case "InitWithOrigDelegate": - return sel_initWithOrigDelegate - case "WindowShouldClose": - return sel_windowShouldClose - case "WindowDidResize": - return sel_windowDidResize - case "WindowDidMove": - return sel_windowDidMove - case "WindowDidMiniaturize": - return sel_windowDidMiniaturize - case "WindowDidDeminiaturize": - return sel_windowDidDeminiaturize - case "WindowDidBecomeKey": - return sel_windowDidBecomeKey - case "WindowDidResignKey": - return sel_windowDidResignKey - case "WindowDidChangeOcclusionState": - return sel_windowDidChangeOcclusionState - case "WindowWillEnterFullScreen": - return sel_windowWillEnterFullScreen - case "WindowDidEnterFullScreen": - return sel_windowDidEnterFullScreen - case "WindowWillExitFullScreen": - return sel_windowWillExitFullScreen - case "WindowDidExitFullScreen": - return sel_windowDidExitFullScreen - default: - return 0 - } -} +var class_EbitengineWindowDelegate objc.Class func init() { var err error - class_EbitengineWindowDelegate, err = objc.RegisterClass(&windowDelegate{}) + pushResizableState := func(id, win objc.ID) { + window := cocoa.NSWindow{ID: win} + id.Send(sel_setOrigResizable, window.StyleMask()&cocoa.NSWindowStyleMaskResizable != 0) + if !objc.Send[bool](id, sel_origResizable) { + window.SetStyleMask(window.StyleMask() | cocoa.NSWindowStyleMaskResizable) + } + } + popResizableState := func(id, win objc.ID) { + if !objc.Send[bool](id, sel_origResizable) { + window := cocoa.NSWindow{ID: win} + window.SetStyleMask(window.StyleMask() & ^uint(cocoa.NSWindowStyleMaskResizable)) + } + id.Send(sel_setOrigResizable, false) + } + class_EbitengineWindowDelegate, err = objc.RegisterClass( + "EbitengineWindowDelegate", + objc.GetClass("NSObject"), + []*objc.Protocol{objc.GetProtocol("NSWindowDelegate")}, + []objc.FieldDef{ + { + Name: "origDelegate", + Type: reflect.TypeOf(objc.ID(0)), + Attribute: objc.ReadWrite, + }, + { + Name: "origResizable", + Type: reflect.TypeOf(true), + Attribute: objc.ReadWrite, + }, + }, + []objc.MethodDef{ + { + Cmd: sel_initWithOrigDelegate, + Fn: func(id objc.ID, cmd objc.SEL, origDelegate objc.ID) objc.ID { + self := id.SendSuper(sel_init) + if self != 0 { + id.Send(sel_setOrigDelegate, origDelegate) + } + return self + }, + }, + // The method set of origDelegate must sync with GLFWWindowDelegate's implementation. + // See cocoa_window.m in GLFW. + { + Cmd: sel_windowShouldClose, + Fn: func(id objc.ID, cmd objc.SEL, notification objc.ID) bool { + return id.Send(sel_origDelegate).Send(cmd, notification) != 0 + }, + }, + { + Cmd: sel_windowDidResize, + Fn: func(id objc.ID, cmd objc.SEL, notification objc.ID) { + id.Send(sel_origDelegate).Send(cmd, notification) + }, + }, + { + Cmd: sel_windowDidMove, + Fn: func(id objc.ID, cmd objc.SEL, notification objc.ID) { + id.Send(sel_origDelegate).Send(cmd, notification) + }, + }, + { + Cmd: sel_windowDidMiniaturize, + Fn: func(id objc.ID, cmd objc.SEL, notification objc.ID) { + id.Send(sel_origDelegate).Send(cmd, notification) + }, + }, + { + Cmd: sel_windowDidBecomeKey, + Fn: func(id objc.ID, cmd objc.SEL, notification objc.ID) { + id.Send(sel_origDelegate).Send(cmd, notification) + }, + }, + { + Cmd: sel_windowDidResignKey, + Fn: func(id objc.ID, cmd objc.SEL, notification objc.ID) { + id.Send(sel_origDelegate).Send(cmd, notification) + }, + }, + { + Cmd: sel_windowDidChangeOcclusionState, + Fn: func(id objc.ID, cmd objc.SEL, notification objc.ID) { + id.Send(sel_origDelegate).Send(cmd, notification) + }, + }, + { + Cmd: sel_windowWillEnterFullScreen, + Fn: func(id objc.ID, cmd objc.SEL, notification objc.ID) { + pushResizableState(id, cocoa.NSNotification{ID: notification}.Object()) + }, + }, + { + Cmd: sel_windowDidEnterFullScreen, + Fn: func(id objc.ID, cmd objc.SEL, notification objc.ID) { + popResizableState(id, cocoa.NSNotification{ID: notification}.Object()) + }, + }, + { + Cmd: sel_windowWillExitFullScreen, + Fn: func(id objc.ID, cmd objc.SEL, notification objc.ID) { + pushResizableState(id, cocoa.NSNotification{ID: notification}.Object()) + }, + }, + { + Cmd: sel_windowDidExitFullScreen, + Fn: func(id objc.ID, cmd objc.SEL, notification objc.ID) { + popResizableState(id, cocoa.NSNotification{ID: notification}.Object()) + // Do not call setFrame here (#2295). setFrame here causes unexpected results. + }, + }, + }, + ) if err != nil { panic(err) } @@ -218,14 +212,15 @@ var ( var ( sel_alloc = objc.RegisterName("alloc") - sel_class = objc.RegisterName("class") sel_collectionBehavior = objc.RegisterName("collectionBehavior") sel_delegate = objc.RegisterName("delegate") sel_init = objc.RegisterName("init") sel_initWithOrigDelegate = objc.RegisterName("initWithOrigDelegate:") sel_mouseLocation = objc.RegisterName("mouseLocation") - sel_performSelector = objc.RegisterName("performSelector:") - sel_set = objc.RegisterName("set") + sel_origDelegate = objc.RegisterName("origDelegate") + sel_setOrigDelegate = objc.RegisterName("setOrigDelegate:") + sel_origResizable = objc.RegisterName("isOrigResizable") + sel_setOrigResizable = objc.RegisterName("setOrigResizable:") sel_setCollectionBehavior = objc.RegisterName("setCollectionBehavior:") sel_setDelegate = objc.RegisterName("setDelegate:") sel_toggleFullScreen = objc.RegisterName("toggleFullScreen:")