summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--delegate_darwin.go4
-rw-r--r--delegate_darwin.m53
-rw-r--r--delegateuitask_darwin.h10
-rw-r--r--delegateuitask_darwin.m95
-rw-r--r--uitask_darwin.go42
5 files changed, 116 insertions, 88 deletions
diff --git a/delegate_darwin.go b/delegate_darwin.go
index be26a1e..a3f7486 100644
--- a/delegate_darwin.go
+++ b/delegate_darwin.go
@@ -18,9 +18,7 @@ This creates a class goAppDelegate that will be used as the delegate for /everyt
// #cgo LDFLAGS: -lobjc -framework Foundation -framework AppKit
// #include <stdlib.h>
// #include "objc_darwin.h"
-// /* TODO this goes in objc_darwin.h once I take care of everything else */
-// extern id makeAppDelegate(void);
-// extern id windowGetContentView(id);
+// #include "delegateuitask_darwin.h"
import "C"
var (
diff --git a/delegate_darwin.m b/delegate_darwin.m
deleted file mode 100644
index 638bfa3..0000000
--- a/delegate_darwin.m
+++ /dev/null
@@ -1,53 +0,0 @@
-// 13 may 2014
-
-#include "objc_darwin.h"
-#include "_cgo_export.h"
-#include <Foundation/NSObject.h>
-#include <Foundation/NSValue.h>
-#include <Foundation/NSNotification.h>
-#include <AppKit/NSApplication.h>
-#include <AppKit/NSWindow.h>
-
-@interface appDelegate : NSObject
-@end
-
-@implementation appDelegate
-
-- (void)uitask:(NSValue *)fp
-{
- appDelegate_uitask([fp pointerValue]);
-}
-
-- (BOOL)windowShouldClose:(id)win
-{
- appDelegate_windowShouldClose(win);
- return NO; // don't close
-}
-
-- (void)windowDidResize:(NSNotification *)n
-{
- appDelegate_windowDidResize([n object]);
-}
-
-- (void)buttonClicked:(id)button
-{
- appDelegate_buttonClicked(button);
-}
-
-- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app
-{
- appDelegate_applicationShouldTerminate();
- return NSTerminateCancel;
-}
-
-@end
-
-id makeAppDelegate(void)
-{
- return [appDelegate new];
-}
-
-id windowGetContentView(id window)
-{
- return [((NSWindow *) window) contentView];
-}
diff --git a/delegateuitask_darwin.h b/delegateuitask_darwin.h
new file mode 100644
index 0000000..cccc6a2
--- /dev/null
+++ b/delegateuitask_darwin.h
@@ -0,0 +1,10 @@
+/* 13 may 2014 */
+
+//#include "common_darwin.h"
+
+extern id makeAppDelegate(void);
+extern id windowGetContentView(id);
+extern BOOL initCocoa(id);
+extern void douitask(id, void *);
+extern void breakMainLoop(void);
+extern void cocoaMainLoop(void);
diff --git a/delegateuitask_darwin.m b/delegateuitask_darwin.m
new file mode 100644
index 0000000..5d2ec9e
--- /dev/null
+++ b/delegateuitask_darwin.m
@@ -0,0 +1,95 @@
+// 13 may 2014
+
+#include "objc_darwin.h"
+#include "delegateuitask_darwin.h"
+#include "_cgo_export.h"
+#include <Foundation/NSObject.h>
+#include <Foundation/NSValue.h>
+#include <Foundation/NSNotification.h>
+#include <AppKit/NSApplication.h>
+#include <AppKit/NSWindow.h>
+#include <Foundation/NSAutoreleasePool.h>
+
+@interface appDelegate : NSObject
+@end
+
+@implementation appDelegate
+
+- (void)uitask:(NSValue *)fp
+{
+ appDelegate_uitask([fp pointerValue]);
+}
+
+- (BOOL)windowShouldClose:(id)win
+{
+ appDelegate_windowShouldClose(win);
+ return NO; // don't close
+}
+
+- (void)windowDidResize:(NSNotification *)n
+{
+ appDelegate_windowDidResize([n object]);
+}
+
+- (void)buttonClicked:(id)button
+{
+ appDelegate_buttonClicked(button);
+}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app
+{
+ appDelegate_applicationShouldTerminate();
+ return NSTerminateCancel;
+}
+
+@end
+
+id makeAppDelegate(void)
+{
+ return [appDelegate new];
+}
+
+id windowGetContentView(id window)
+{
+ return [((NSWindow *) window) contentView];
+}
+
+BOOL initCocoa(id appDelegate)
+{
+ [NSApplication sharedApplication];
+ if ([NSApp setActivationPolicy:NSApplicationActivationPolicyRegular] != YES)
+ return NO;
+ [NSApp activateIgnoringOtherApps:YES]; // TODO actually do C.NO here? Russ Cox does YES in his devdraw; the docs say the Finder does NO
+ [NSApp setDelegate:appDelegate];
+ return YES;
+}
+
+void douitask(id appDelegate, void *p)
+{
+ NSAutoreleasePool *pool;
+ NSValue *fp;
+
+ // we need to make an NSAutoreleasePool, otherwise we get leak warnings on stderr
+ pool = [NSAutoreleasePool new];
+ fp = [NSValue valueWithPointer:p];
+ [appDelegate performSelectorOnMainThread:@selector(uitask:)
+ withObject:fp
+ waitUntilDone:YES]; // wait so we can properly drain the autorelease pool; on other platforms we wind up waiting anyway (since the main thread can only handle one thing at a time) so
+ [pool release];
+}
+
+void breakMainLoop(void)
+{
+ // -[NSApplication stop:] stops the event loop; it won't do a clean termination, but we're not too concerned with that (at least not on the other platforms either so)
+ // we can't call -[NSApplication terminate:] because that will just quit the program, ensuring we never leave ui.Go()
+ [NSApp stop:NSApp];
+ // simply calling -[NSApplication stop:] is not good enough, as the stop flag is only checked when an event comes in
+ // we have to create a "proper" event; a blank event will just throw an exception
+ [NSApp postEvent:makeDummyEvent() // TODO inline this
+ atStart:NO]; // not at start, just in case there are other events pending (TODO is this correct?)
+}
+
+void cocoaMainLoop(void)
+{
+ [NSApp run];
+}
diff --git a/uitask_darwin.go b/uitask_darwin.go
index 6d044f6..6b886cf 100644
--- a/uitask_darwin.go
+++ b/uitask_darwin.go
@@ -10,6 +10,7 @@ import (
// #cgo LDFLAGS: -lobjc -framework Foundation -framework AppKit
// #include "objc_darwin.h"
+// #include "delegateuitask_darwin.h"
import "C"
var uitask chan func()
@@ -32,7 +33,7 @@ func ui(main func()) error {
uitask = make(chan func())
- NSApp, err := initCocoa()
+ err := initCocoa()
if err != nil {
return err
}
@@ -40,36 +41,18 @@ func ui(main func()) error {
// Cocoa must run on the first thread created by the program, so we run our dispatcher on another thread instead
go func() {
for f := range uitask {
- // we need to make an NSAutoreleasePool, otherwise we get leak warnings on stderr
- pool := C.objc_msgSend_noargs(_NSAutoreleasePool, _new)
- fp := C.objc_msgSend_ptr(_NSValue, _valueWithPointer,
- unsafe.Pointer(&f))
- C.objc_msgSend_sel_id_bool(
- appDelegate,
- _performSelectorOnMainThread,
- _uitask,
- fp,
- C.BOOL(C.YES)) // wait so we can properly drain the autorelease pool; on other platforms we wind up waiting anyway (since the main thread can only handle one thing at a time) so
- C.objc_msgSend_noargs(pool, _release)
+ C.douitask(appDelegate, unsafe.Pointer(&f))
}
}()
go func() {
main()
uitask <- func() {
- // -[NSApplication stop:] stops the event loop; it won't do a clean termination, but we're not too concerned with that (at least not on the other platforms either so)
- // we can't call -[NSApplication terminate:] because that will just quit the program, ensuring we never leave ui.Go()
- C.objc_msgSend_id(NSApp, _stop, NSApp)
- // simply calling -[NSApplication stop:] is not good enough, as the stop flag is only checked when an event comes in
- // we have to create a "proper" event; a blank event will just throw an exception
- C.objc_msgSend_id_bool(NSApp,
- _postEventAtStart,
- C.makeDummyEvent(),
- C.BOOL(C.NO)) // not at start, just in case there are other events pending (TODO is this correct?)
+ C.breakMainLoop()
}
}()
- C.objc_msgSend_noargs(NSApp, _run)
+ C.cocoaMainLoop()
return nil
}
@@ -84,21 +67,16 @@ var (
// _setDelegate in sysdata_darwin.go
)
-func initCocoa() (NSApp C.id, err error) {
+func initCocoa() (err error) {
C.initBleh() // initialize bleh_darwin.m functions
- NSApp = C.objc_msgSend_noargs(_NSApplication, _sharedApplication)
- r := C.objc_msgSend_int(NSApp, _setActivationPolicy,
- 0) // NSApplicationActivationPolicyRegular
- if C.BOOL(uintptr(unsafe.Pointer(r))) != C.BOOL(C.YES) {
- err = fmt.Errorf("error setting NSApplication activation policy (basically identifies our program as a separate program; needed for several things, such as Dock icon, application menu, window resizing, etc.) (unknown reason)")
- return
- }
- C.objc_msgSend_bool(NSApp, _activateIgnoringOtherApps, C.BOOL(C.YES)) // TODO actually do C.NO here? Russ Cox does YES in his devdraw; the docs say the Finder does NO
err = mkAppDelegate()
if err != nil {
return
}
- C.objc_msgSend_id(NSApp, _setDelegate, appDelegate)
+ if C.initCocoa(appDelegate) != C.YES {
+ err = fmt.Errorf("error setting NSApplication activation policy (basically identifies our program as a separate program; needed for several things, such as Dock icon, application menu, window resizing, etc.) (unknown reason)")
+ return
+ }
err = mkAreaClass()
return
}