From 8c5f525ac2e0a3895e0243eaf1eefacfebfc66dc Mon Sep 17 00:00:00 2001 From: TotallyGamerJet Date: Sun, 6 Nov 2022 21:31:39 -0800 Subject: [PATCH] internal/ui: use RegisterClass API (#2442) Updates #1162 This change uses purego's new RegisterClass API to clean up the EbitengineWindowDelegate ObjC class. Doing so makes the code easier to read and more efficient since it directly get the origResizable and origDelegate fields. --- internal/ui/ui_glfw_darwin.go | 204 ++++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 83 deletions(-) diff --git a/internal/ui/ui_glfw_darwin.go b/internal/ui/ui_glfw_darwin.go index ab1c9c558..b124646a9 100644 --- a/internal/ui/ui_glfw_darwin.go +++ b/internal/ui/ui_glfw_darwin.go @@ -31,90 +31,128 @@ import ( var class_EbitengineWindowDelegate objc.Class -func init() { - class_EbitengineWindowDelegate = objc.AllocateClassPair(objc.GetClass("NSObject"), "EbitengineWindowDelegate", 0) - protocol := objc.GetProtocol("NSWindowDelegate") - class_EbitengineWindowDelegate.AddProtocol(protocol) - // TODO: remove these Ivars and place them in Go since there is only ever one instance of this class - class_EbitengineWindowDelegate.AddIvar("origDelegate", objc.ID(0), "@") - class_EbitengineWindowDelegate.AddIvar("origResizable", false, "B") - origDelegateOffset := class_EbitengineWindowDelegate.InstanceVariable("origDelegate").Offset() - origResizableOffset := class_EbitengineWindowDelegate.InstanceVariable("origResizable").Offset() - getOrigDelegate := func(self objc.ID) objc.ID { - selfPtr := *(**uintptr)(unsafe.Pointer(&self)) - return *(*objc.ID)(unsafe.Pointer(uintptr(unsafe.Pointer(selfPtr)) + origDelegateOffset)) - } - getResizable := func(self objc.ID) bool { - selfPtr := *(**uintptr)(unsafe.Pointer(&self)) - return *(*bool)(unsafe.Pointer(uintptr(unsafe.Pointer(selfPtr)) + origResizableOffset)) - } - setResizable := func(self objc.ID, resizable bool) { - selfPtr := *(**uintptr)(unsafe.Pointer(&self)) - *(*bool)(unsafe.Pointer(uintptr(unsafe.Pointer(selfPtr)) + origResizableOffset)) = resizable - } - pushResizableState := func(self, w objc.ID) { - window := cocoa.NSWindow{ID: w} - setResizable(self, window.StyleMask()&cocoa.NSWindowStyleMaskResizable != 0) - if !getResizable(self) { - window.SetStyleMask(window.StyleMask() | cocoa.NSWindowStyleMaskResizable) - } - } - popResizableState := func(self, w objc.ID) { - window := cocoa.NSWindow{ID: w} - if !getResizable(self) { - window.SetStyleMask(window.StyleMask() & ^uint(cocoa.NSWindowStyleMaskResizable)) - } - setResizable(self, false) - } - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("initWithOrigDelegate:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, origDelegate objc.ID) objc.ID { - self = self.SendSuper(objc.RegisterName("init")) - if self != 0 { - selfPtr := *(**uintptr)(unsafe.Pointer(&self)) - *(*objc.ID)(unsafe.Pointer(uintptr(unsafe.Pointer(selfPtr)) + origDelegateOffset)) = origDelegate - } - return self - }), "@@:B") - // The method set of origDelegate_ must sync with GLFWWindowDelegate's implementation. - // See cocoa_window.m in GLFW. - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowShouldClose:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) int { - return int(getOrigDelegate(self).Send(objc.RegisterName("windowShouldClose:"), notification)) - }), "B@:@") - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidResize:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) { - getOrigDelegate(self).Send(cmd, notification) - }), "v@:@") - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidMove:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) { - getOrigDelegate(self).Send(cmd, notification) - }), "v@:@") - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidMiniaturize:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) { - getOrigDelegate(self).Send(cmd, notification) - }), "v@:@") - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidDeminiaturize:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) { - getOrigDelegate(self).Send(cmd, notification) - }), "v@:@") - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidBecomeKey:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) { - getOrigDelegate(self).Send(cmd, notification) - }), "v@:@") - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidResignKey:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) { - getOrigDelegate(self).Send(cmd, notification) - }), "v@:@") - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidChangeOcclusionState:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) { - getOrigDelegate(self).Send(cmd, notification) - }), "v@:@") +type windowDelgate struct { + isa objc.Class `objc:"EbitengineWindowDelegate : NSObject "` + origDelegate objc.ID + origResizable bool +} - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowWillEnterFullScreen:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) { - pushResizableState(self, cocoa.NSNotification{ID: notification}.Object()) - }), "v@:@") - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidEnterFullScreen:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) { - popResizableState(self, cocoa.NSNotification{ID: notification}.Object()) - }), "v@:@") - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowWillExitFullScreen:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) { - pushResizableState(self, cocoa.NSNotification{ID: notification}.Object()) - }), "v@:@") - class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidExitFullScreen:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) { - popResizableState(self, cocoa.NSNotification{ID: notification}.Object()) - // Do not call setFrame here (#2295). setFrame here causes unexpected results. - }), "v@:@") - class_EbitengineWindowDelegate.Register() +func (w *windowDelgate) 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 *windowDelgate) popResizableState(win objc.ID) { + if !w.origResizable { + window := cocoa.NSWindow{ID: win} + window.SetStyleMask(window.StyleMask() & ^uint(cocoa.NSWindowStyleMaskResizable)) + } + w.origResizable = false +} + +func (w *windowDelgate) InitWithOrigDelegate(cmd objc.SEL, origDelegate objc.ID) objc.ID { + self := objc.ID(unsafe.Pointer(w)).SendSuper(objc.RegisterName("init")) + if self != 0 { + w = *(**windowDelgate)(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 *windowDelgate) WindowShouldClose(cmd objc.SEL, notification objc.ID) bool { + return w.origDelegate.Send(cmd, notification) != 0 +} + +func (w *windowDelgate) WindowDidResize(cmd objc.SEL, notification objc.ID) { + w.origDelegate.Send(cmd, notification) +} + +func (w *windowDelgate) WindowDidMove(cmd objc.SEL, notification objc.ID) { + w.origDelegate.Send(cmd, notification) +} + +func (w *windowDelgate) WindowDidMiniaturize(cmd objc.SEL, notification objc.ID) { + w.origDelegate.Send(cmd, notification) +} + +func (w *windowDelgate) WindowDidDeminiaturize(cmd objc.SEL, notification objc.ID) { + w.origDelegate.Send(cmd, notification) +} + +func (w *windowDelgate) WindowDidBecomeKey(cmd objc.SEL, notification objc.ID) { + w.origDelegate.Send(cmd, notification) +} + +func (w *windowDelgate) WindowDidResignKey(cmd objc.SEL, notification objc.ID) { + w.origDelegate.Send(cmd, notification) +} + +func (w *windowDelgate) WindowDidChangeOcclusionState(cmd objc.SEL, notification objc.ID) { + w.origDelegate.Send(cmd, notification) +} + +func (w *windowDelgate) WindowWillEnterFullScreen(cmd objc.SEL, notification objc.ID) { + w.pushResizableState(cocoa.NSNotification{ID: notification}.Object()) +} + +func (w *windowDelgate) WindowDidEnterFullScreen(cmd objc.SEL, notification objc.ID) { + w.popResizableState(cocoa.NSNotification{ID: notification}.Object()) +} + +func (w *windowDelgate) WindowWillExitFullScreen(cmd objc.SEL, notification objc.ID) { + w.pushResizableState(cocoa.NSNotification{ID: notification}.Object()) +} + +func (w *windowDelgate) 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 *windowDelgate) Selector(cmd string) objc.SEL { + switch cmd { + case "InitWithOrigDelegate": + return objc.RegisterName("initWithOrigDelegate:") + case "WindowShouldClose": + return objc.RegisterName("windowShouldClose:") + case "WindowDidResize": + return objc.RegisterName("windowDidResize:") + case "WindowDidMove": + return objc.RegisterName("windowDidMove:") + case "WindowDidMiniaturize": + return objc.RegisterName("windowDidMiniaturize:") + case "WindowDidDeminiaturize": + return objc.RegisterName("windowDidDeminiaturize:") + case "WindowDidBecomeKey": + return objc.RegisterName("windowDidBecomeKey:") + case "WindowDidResignKey": + return objc.RegisterName("windowDidResignKey:") + case "WindowDidChangeOcclusionState": + return objc.RegisterName("windowDidChangeOcclusionState:") + case "WindowWillEnterFullScreen": + return objc.RegisterName("windowWillEnterFullScreen:") + case "WindowDidEnterFullScreen": + return objc.RegisterName("windowDidEnterFullScreen:") + case "WindowWillExitFullScreen": + return objc.RegisterName("windowWillExitFullScreen:") + case "WindowDidExitFullScreen": + return objc.RegisterName("windowDidExitFullScreen:") + default: + return 0 + } +} + +func init() { + var err error + class_EbitengineWindowDelegate, err = objc.RegisterClass(&windowDelgate{}) + if err != nil { + panic(err) + } } type graphicsDriverCreatorImpl struct {