Moved uitask_darwin.go to be Objective-C-based. Both delegate_darwin.go and uitask_darwin.go will share the same .m file.
This commit is contained in:
parent
de97125c54
commit
3e712db2e0
|
@ -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 (
|
||||
|
|
|
@ -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];
|
||||
}
|
|
@ -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);
|
|
@ -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];
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue