diff --git a/README.md b/README.md index cd955101..83fc8b22 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,6 @@ DarwinKit lets you work with [supported Apple frameworks](https://pkg.go.dev/git package main import ( - "runtime" - "github.com/progrium/macdriver/objc" "github.com/progrium/macdriver/macos" "github.com/progrium/macdriver/macos/appkit" @@ -28,11 +26,6 @@ import ( "github.com/progrium/macdriver/macos/webkit" ) -func init() { - // ensure main is run on the startup thread - runtime.LockOSThread() -} - func main() { // runs macOS application event loop with a callback on success macos.RunApp(func(app appkit.Application, delegate *appkit.ApplicationDelegate) { diff --git a/macos/_examples/form/main.go b/macos/_examples/form/main.go index b84426b0..460c397f 100644 --- a/macos/_examples/form/main.go +++ b/macos/_examples/form/main.go @@ -1,24 +1,21 @@ package main import ( - "runtime" - "github.com/progrium/macdriver/helper/layout" "github.com/progrium/macdriver/helper/widgets" + "github.com/progrium/macdriver/macos" "github.com/progrium/macdriver/macos/appkit" "github.com/progrium/macdriver/macos/foundation" + "github.com/progrium/macdriver/objc" ) -// Arrange that main.main runs on main thread. -func init() { - runtime.LockOSThread() +func main() { + macos.RunApp(launched) } -func initAndRun() { - app := appkit.Application_SharedApplication() - app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular) - app.ActivateIgnoringOtherApps(true) +func launched(app appkit.Application, delegate *appkit.ApplicationDelegate) { w := appkit.NewWindowWithSize(600, 400) + objc.Retain(&w) w.SetTitle("Form") fv := widgets.NewFormView() @@ -38,19 +35,9 @@ func initAndRun() { w.MakeKeyAndOrderFront(nil) w.Center() - ad := &appkit.ApplicationDelegate{} - ad.SetApplicationDidFinishLaunching(func(foundation.Notification) { - app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular) - app.ActivateIgnoringOtherApps(true) - }) - ad.SetApplicationShouldTerminateAfterLastWindowClosed(func(appkit.Application) bool { + delegate.SetApplicationShouldTerminateAfterLastWindowClosed(func(appkit.Application) bool { return true }) - app.SetDelegate(ad) - - app.Run() -} - -func main() { - initAndRun() + app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular) + app.ActivateIgnoringOtherApps(true) } diff --git a/macos/_examples/helloworld/main.go b/macos/_examples/helloworld/main.go index 0800937d..e90adc6e 100644 --- a/macos/_examples/helloworld/main.go +++ b/macos/_examples/helloworld/main.go @@ -1,8 +1,6 @@ package main import ( - "runtime" - "github.com/progrium/macdriver/macos" "github.com/progrium/macdriver/macos/appkit" "github.com/progrium/macdriver/macos/foundation" @@ -10,11 +8,6 @@ import ( "github.com/progrium/macdriver/objc" ) -func init() { - // ensure main is run on the startup thread - runtime.LockOSThread() -} - func main() { // runs macOS application event loop with a callback on success macos.RunApp(func(app appkit.Application, delegate *appkit.ApplicationDelegate) { diff --git a/macos/_examples/largetype/main.go b/macos/_examples/largetype/main.go index 18af3d11..99c2f4bc 100644 --- a/macos/_examples/largetype/main.go +++ b/macos/_examples/largetype/main.go @@ -3,31 +3,36 @@ package main import ( "flag" "fmt" - "runtime" "strings" + "github.com/progrium/macdriver/macos" "github.com/progrium/macdriver/macos/appkit" "github.com/progrium/macdriver/macos/foundation" "github.com/progrium/macdriver/objc" ) -func init() { - runtime.LockOSThread() -} +var ( + fontName *string + text string +) func main() { - fontName := flag.String("font", "Helvetica", "font to use") + fontName = flag.String("font", "Helvetica", "font to use") flag.Parse() - text := strings.Join(flag.Args(), " ") + + text = strings.Join(flag.Args(), " ") if text == "" { text = "Hello world" } - - app := appkit.Application_SharedApplication() - screen := appkit.Screen_MainScreen().Frame().Size text = fmt.Sprintf(" %s ", text) fmt.Println(text) + macos.RunApp(launched) +} + +func launched(app appkit.Application, delegate *appkit.ApplicationDelegate) { + screen := appkit.Screen_MainScreen().Frame().Size + tr, fontSize := func() (rect foundation.Rect, size float64) { t := appkit.NewTextViewWithFrame(rectOf(0, 0, 0, 0)) t.SetString(text) @@ -53,8 +58,8 @@ func main() { t.SetDrawsBackground(false) c := appkit.NewViewWithFrame(rectOf(0, 0, 0, 0)) - // deprecated... - // c.SetBackgroundColor(appkit.Color_ColorWithRedGreenBlueAlpha(0, 0, 0, 0.75)) + // deprecated call, no bindings + objc.Call[objc.Void](c, objc.Sel("setBackgroundColor:"), appkit.Color_ColorWithRedGreenBlueAlpha(0, 0, 0, 0.75)) c.SetWantsLayer(true) c.Layer().SetCornerRadius(32.0) c.AddSubviewPositionedRelativeTo(t, appkit.WindowAbove, nil) @@ -79,14 +84,8 @@ func main() { appkit.Application_SharedApplication().Terminate(nil) }) - ad := &appkit.ApplicationDelegate{} - ad.SetApplicationDidFinishLaunching(func(foundation.Notification) { - app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular) - app.ActivateIgnoringOtherApps(true) - }) - app.SetDelegate(ad) - - app.Run() + app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular) + app.ActivateIgnoringOtherApps(true) } func rectOf(x, y, width, height float64) foundation.Rect { diff --git a/macos/_examples/layout/main.go b/macos/_examples/layout/main.go index 0c7cad26..c99befe3 100644 --- a/macos/_examples/layout/main.go +++ b/macos/_examples/layout/main.go @@ -2,26 +2,26 @@ package main import ( "fmt" - "runtime" "github.com/progrium/macdriver/helper/action" "github.com/progrium/macdriver/helper/layout" "github.com/progrium/macdriver/helper/widgets" + "github.com/progrium/macdriver/macos" "github.com/progrium/macdriver/macos/appkit" "github.com/progrium/macdriver/macos/foundation" "github.com/progrium/macdriver/objc" ) -// Arrange that main.main runs on main thread. -func init() { - runtime.LockOSThread() +func main() { + macos.RunApp(launched) } -func initAndRun() { - app := appkit.Application_SharedApplication() +func launched(app appkit.Application, delegate *appkit.ApplicationDelegate) { app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular) app.ActivateIgnoringOtherApps(true) + w := appkit.NewWindowWithSize(600, 400) + objc.Retain(&w) w.SetTitle("Test Layout") label := appkit.NewLabel("label") @@ -71,19 +71,7 @@ func initAndRun() { w.MakeKeyAndOrderFront(nil) w.Center() - ad := &appkit.ApplicationDelegate{} - ad.SetApplicationDidFinishLaunching(func(foundation.Notification) { - app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular) - app.ActivateIgnoringOtherApps(true) - }) - ad.SetApplicationShouldTerminateAfterLastWindowClosed(func(appkit.Application) bool { + delegate.SetApplicationShouldTerminateAfterLastWindowClosed(func(appkit.Application) bool { return true }) - app.SetDelegate(ad) - - app.Run() -} - -func main() { - initAndRun() } diff --git a/macos/_examples/menu/main.go b/macos/_examples/menu/main.go index 8ed1b4b5..ded82e3a 100644 --- a/macos/_examples/menu/main.go +++ b/macos/_examples/menu/main.go @@ -8,50 +8,43 @@ import ( "github.com/progrium/macdriver/objc" ) -// menus and tray - -// Arrange that main.main runs on main thread. -func init() { +func main() { runtime.LockOSThread() -} -func initAndRun() { app := appkit.Application_SharedApplication() - w := appkit.NewWindowWithSize(600, 400) - w.SetTitle("Test") - // text field - textView := appkit.TextView_ScrollableTextView() - textView.SetTranslatesAutoresizingMaskIntoConstraints(false) - tv := appkit.TextViewFrom(textView.DocumentView().Ptr()) - tv.SetAllowsUndo(true) - tv.SetRichText(false) - w.ContentView().AddSubview(textView) - w.ContentView().LeadingAnchor().ConstraintEqualToAnchorConstant(textView.LeadingAnchor(), -10).SetActive(true) - w.ContentView().TopAnchor().ConstraintEqualToAnchorConstant(textView.TopAnchor(), -10).SetActive(true) - w.ContentView().TrailingAnchor().ConstraintEqualToAnchorConstant(textView.TrailingAnchor(), 10).SetActive(true) - w.ContentView().BottomAnchor().ConstraintEqualToAnchorConstant(textView.BottomAnchor(), 10).SetActive(true) + delegate := &appkit.ApplicationDelegate{} + delegate.SetApplicationDidFinishLaunching(func(foundation.Notification) { + w := appkit.NewWindowWithSize(600, 400) + objc.Retain(&w) + w.SetTitle("Test") + + textView := appkit.TextView_ScrollableTextView() + textView.SetTranslatesAutoresizingMaskIntoConstraints(false) + tv := appkit.TextViewFrom(textView.DocumentView().Ptr()) + tv.SetAllowsUndo(true) + tv.SetRichText(false) + w.ContentView().AddSubview(textView) + w.ContentView().LeadingAnchor().ConstraintEqualToAnchorConstant(textView.LeadingAnchor(), -10).SetActive(true) + w.ContentView().TopAnchor().ConstraintEqualToAnchorConstant(textView.TopAnchor(), -10).SetActive(true) + w.ContentView().TrailingAnchor().ConstraintEqualToAnchorConstant(textView.TrailingAnchor(), 10).SetActive(true) + w.ContentView().BottomAnchor().ConstraintEqualToAnchorConstant(textView.BottomAnchor(), 10).SetActive(true) + + w.MakeKeyAndOrderFront(nil) + w.Center() - w.MakeKeyAndOrderFront(nil) - w.Center() + setSystemBar(app) - ad := &appkit.ApplicationDelegate{} - ad.SetApplicationDidFinishLaunching(func(foundation.Notification) { app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular) app.ActivateIgnoringOtherApps(true) }) - ad.SetApplicationWillFinishLaunching(func(foundation.Notification) { - // should set menu bar at ApplicationWillFinishLaunching + delegate.SetApplicationWillFinishLaunching(func(foundation.Notification) { setMainMenu(app) }) - ad.SetApplicationShouldTerminateAfterLastWindowClosed(func(appkit.Application) bool { + delegate.SetApplicationShouldTerminateAfterLastWindowClosed(func(appkit.Application) bool { return true }) - app.SetDelegate(ad) - - // should set system bar after window show - setSystemBar(app) - + app.SetDelegate(delegate) app.Run() } @@ -69,8 +62,7 @@ func setMainMenu(app appkit.Application) { testMenuItem := appkit.NewMenuItemWithSelector("", "", objc.Selector{}) testMenu := appkit.NewMenuWithTitle("Edit") testMenu.AddItem(appkit.NewMenuItemWithSelector("Select All", "a", objc.Sel("selectAll:"))) - // missing symbol? - //testMenu.AddItem(appkit.MenuItem_SeparatorItem()) + testMenu.AddItem(appkit.MenuItem_SeparatorItem()) testMenu.AddItem(appkit.NewMenuItemWithSelector("Copy", "c", objc.Sel("copy:"))) testMenu.AddItem(appkit.NewMenuItemWithSelector("Paste", "v", objc.Sel("paste:"))) testMenu.AddItem(appkit.NewMenuItemWithSelector("Cut", "x", objc.Sel("cut:"))) @@ -81,17 +73,12 @@ func setMainMenu(app appkit.Application) { } func setSystemBar(app appkit.Application) { - bar := appkit.StatusBar_SystemStatusBar() - item := bar.StatusItemWithLength(appkit.VariableStatusItemLength) - button := item.Button() - button.SetTitle("TestTray") + item := appkit.StatusBar_SystemStatusBar().StatusItemWithLength(appkit.VariableStatusItemLength) + objc.Retain(&item) + item.Button().SetTitle("TestTray") menu := appkit.NewMenuWithTitle("main") menu.AddItem(appkit.NewMenuItemWithAction("Hide", "h", func(sender objc.Object) { app.Hide(nil) })) menu.AddItem(appkit.NewMenuItemWithAction("Quit", "q", func(sender objc.Object) { app.Terminate(nil) })) item.SetMenu(menu) } - -func main() { - initAndRun() -} diff --git a/macos/_examples/notification/main.go b/macos/_examples/notification/main.go index fc9b0a63..42fdee78 100644 --- a/macos/_examples/notification/main.go +++ b/macos/_examples/notification/main.go @@ -2,27 +2,25 @@ package main import ( "runtime" + "time" - "github.com/progrium/macdriver/macos/appkit" "github.com/progrium/macdriver/macos/foundation" "github.com/progrium/macdriver/objc" ) -func init() { - runtime.LockOSThread() -} - func main() { - app := appkit.Application_SharedApplication() + runtime.LockOSThread() + // notifications need a unique bundleIdentifier which we can define by + // replacing the bundleIdentifier method on the default main bundle nsbundle := foundation.Bundle_MainBundle().Class() objc.ReplaceMethod(nsbundle, objc.Sel("bundleIdentifier"), func(_ objc.IObject) string { return "com.example.fake2" // change this if you miss the allow notification }) - ad := &appkit.ApplicationDelegate{} - ad.SetApplicationDidFinishLaunching(func(foundation.Notification) { - + objc.WithAutoreleasePool(func() { + // this API is deprecated and we currently don't generate bindings for deprecated APIs, + // so this is what using an API without bindings looks like. notif := objc.Call[objc.Object](objc.GetClass("NSUserNotification"), objc.Sel("new")) notif.Autorelease() objc.Call[objc.Void](notif, objc.Sel("setTitle:"), "Hello, world!") @@ -30,16 +28,8 @@ func main() { center := objc.Call[objc.Object](objc.GetClass("NSUserNotificationCenter"), objc.Sel("defaultUserNotificationCenter")) objc.Call[objc.Void](center, objc.Sel("deliverNotification:"), notif) - - //app.Terminate(nil) - - }) - ad.SetApplicationShouldTerminateAfterLastWindowClosed(func(appkit.Application) bool { - return true }) - app.SetDelegate(ad) - app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular) - app.ActivateIgnoringOtherApps(true) - app.Run() + // give notification center a moment + <-time.After(1 * time.Second) } diff --git a/macos/_examples/pomodoro/main.go b/macos/_examples/pomodoro/main.go index 6ed4e54a..41eae327 100644 --- a/macos/_examples/pomodoro/main.go +++ b/macos/_examples/pomodoro/main.go @@ -2,93 +2,83 @@ package main import ( "fmt" - "runtime" "time" "github.com/progrium/macdriver/dispatch" "github.com/progrium/macdriver/helper/action" + "github.com/progrium/macdriver/macos" "github.com/progrium/macdriver/macos/appkit" - "github.com/progrium/macdriver/macos/foundation" "github.com/progrium/macdriver/objc" ) -func init() { - runtime.LockOSThread() -} - func main() { - app := appkit.Application_SharedApplication() + macos.RunApp(launched) +} - ad := &appkit.ApplicationDelegate{} - ad.SetApplicationDidFinishLaunching(func(foundation.Notification) { +func launched(app appkit.Application, delegate *appkit.ApplicationDelegate) { + delegate.SetApplicationShouldTerminateAfterLastWindowClosed(func(appkit.Application) bool { + return false + }) - item := appkit.StatusBar_SystemStatusBar().StatusItemWithLength(-1) - item.Retain() - item.Button().SetTitle("▶️ Ready") + item := appkit.StatusBar_SystemStatusBar().StatusItemWithLength(-1) + objc.Retain(&item) + item.Button().SetTitle("▶️ Ready") - nextClicked := make(chan bool) - go func() { - state := -1 - timer := 1500 - countdown := false - for { - select { - case <-time.After(1 * time.Second): - if timer > 0 && countdown { - timer = timer - 1 - } - if timer <= 0 && state%2 == 1 { - state = (state + 1) % 4 - } - case <-nextClicked: + nextClicked := make(chan bool) + go func() { + state := -1 + timer := 1500 + countdown := false + for { + select { + case <-time.After(1 * time.Second): + if timer > 0 && countdown { + timer = timer - 1 + } + if timer <= 0 && state%2 == 1 { state = (state + 1) % 4 - timer = map[int]int{ - 0: 1500, - 1: 1500, - 2: 0, - 3: 300, - }[state] - if state%2 == 1 { - countdown = true - } else { - countdown = false - } } - labels := map[int]string{ - 0: "▶️ Ready %02d:%02d", - 1: "✴️ Working %02d:%02d", - 2: "✅ Finished %02d:%02d", - 3: "⏸️ Break %02d:%02d", + case <-nextClicked: + state = (state + 1) % 4 + timer = map[int]int{ + 0: 1500, + 1: 1500, + 2: 0, + 3: 300, + }[state] + if state%2 == 1 { + countdown = true + } else { + countdown = false } - // updates to the ui should happen on the main thread to avoid segfaults - dispatch.MainQueue().DispatchAsync(func() { - item.Button().SetTitle(fmt.Sprintf(labels[state], timer/60, timer%60)) - }) } - }() - nextClicked <- true - - itemNext := appkit.NewMenuItem() - itemNext.SetTitle("Next") - action.Set(itemNext, func(sender objc.Object) { - nextClicked <- true - }) - - itemQuit := appkit.NewMenuItem() - itemQuit.SetTitle("Quit") - itemQuit.SetAction(objc.Sel("terminate:")) - - menu := appkit.NewMenu() - menu.AddItem(itemNext) - menu.AddItem(itemQuit) - item.SetMenu(menu) + labels := map[int]string{ + 0: "▶️ Ready %02d:%02d", + 1: "✴️ Working %02d:%02d", + 2: "✅ Finished %02d:%02d", + 3: "⏸️ Break %02d:%02d", + } + // updates to the ui should happen on the main thread to avoid segfaults + dispatch.MainQueue().DispatchAsync(func() { + item.Button().SetTitle(fmt.Sprintf(labels[state], timer/60, timer%60)) + }) + } + }() + nextClicked <- true + itemNext := appkit.NewMenuItem() + itemNext.SetTitle("Next") + action.Set(itemNext, func(sender objc.Object) { + nextClicked <- true }) - ad.SetApplicationShouldTerminateAfterLastWindowClosed(func(appkit.Application) bool { - return false - }) - app.SetDelegate(ad) - app.Run() + itemQuit := appkit.NewMenuItem() + itemQuit.SetTitle("Quit") + itemQuit.SetAction(objc.Sel("terminate:")) + + menu := appkit.NewMenu() + menu.AddItem(itemNext) + menu.AddItem(itemQuit) + item.SetMenu(menu) } diff --git a/macos/_examples/tabview/main.go b/macos/_examples/tabview/main.go index 66ad79a9..9ca970bd 100644 --- a/macos/_examples/tabview/main.go +++ b/macos/_examples/tabview/main.go @@ -1,21 +1,21 @@ package main import ( - "runtime" "strconv" + "github.com/progrium/macdriver/macos" "github.com/progrium/macdriver/macos/appkit" "github.com/progrium/macdriver/macos/foundation" + "github.com/progrium/macdriver/objc" ) -// Arrange that main.main runs on main thread. -func init() { - runtime.LockOSThread() +func main() { + macos.RunApp(launched) } -func initAndRun() { - app := appkit.Application_SharedApplication() +func launched(app appkit.Application, delegate *appkit.ApplicationDelegate) { w := appkit.NewWindowWithSize(720, 440) + objc.Retain(&w) w.SetTitle("Decoder") tabView := appkit.NewTabView() @@ -26,23 +26,18 @@ func initAndRun() { tabView.AddTabViewItem(createNewView(2)) w.SetContentView(tabView) + w.Center() + w.MakeKeyAndOrderFront(nil) - ad := &appkit.ApplicationDelegate{} - ad.SetApplicationDidFinishLaunching(func(foundation.Notification) { - app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular) - app.ActivateIgnoringOtherApps(true) - }) - ad.SetApplicationWillFinishLaunching(func(foundation.Notification) { + delegate.SetApplicationWillFinishLaunching(func(foundation.Notification) { w.SetFrameAutosaveName("tab-test") }) - ad.SetApplicationShouldTerminateAfterLastWindowClosed(func(appkit.Application) bool { + delegate.SetApplicationShouldTerminateAfterLastWindowClosed(func(appkit.Application) bool { return true }) - app.SetDelegate(ad) + app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular) + app.ActivateIgnoringOtherApps(true) - w.Center() - w.MakeKeyAndOrderFront(nil) - app.Run() } func createNewView(idx int) appkit.ITabViewItem { @@ -55,7 +50,3 @@ func createNewView(idx int) appkit.ITabViewItem { ti.SetView(sv) return ti } - -func main() { - initAndRun() -} diff --git a/macos/_examples/webshot/main.go b/macos/_examples/webshot/main.go index 629797a0..72aa8ee9 100644 --- a/macos/_examples/webshot/main.go +++ b/macos/_examples/webshot/main.go @@ -3,33 +3,32 @@ package main import ( "fmt" "os" - "runtime" "github.com/progrium/macdriver/dispatch" "github.com/progrium/macdriver/helper/action" + "github.com/progrium/macdriver/macos" "github.com/progrium/macdriver/macos/appkit" "github.com/progrium/macdriver/macos/foundation" "github.com/progrium/macdriver/macos/webkit" "github.com/progrium/macdriver/objc" ) -// Arrange that main.main runs on main thread. -func init() { - runtime.LockOSThread() +func main() { + macos.RunApp(launched) } -func initAndRun() { +func launched(app appkit.Application, delegate *appkit.ApplicationDelegate) { var html = "