2014-03-01 03:17:32 -06:00
/ * 28 february 2014 * /
/ *
I wanted to avoid invoking Objective - C directly , preferring to do everything directly with the API . However , there are some things that simply cannot be done too well ; for those situations , there ' s this . It does use the Objective - C runtime , eschewing the actual Objective - C part of this being an Objective - C file .
The main culprits are :
- data types listed as being defined in nonexistent headers
- 32 - bit / 64 - bit type differences that are more than just a different typedef
2014-03-01 14:58:54 -06:00
- wrong documentation
2014-03-05 19:09:15 -06:00
though this is not always the case .
2014-03-01 03:17:32 -06:00
Go wrapper functions ( bleh_darwin . go ) call these directly and take care of stdint . h -> Go type conversions .
* /
2014-03-01 12:53:29 -06:00
# include "objc_darwin.h"
2014-03-01 03:17:32 -06:00
2014-03-02 22:11:29 -06:00
# include < stdlib . h >
2014-03-01 03:17:32 -06:00
# include < Foundation / NSGeometry . h >
2014-03-02 22:11:29 -06:00
# include < AppKit / NSKeyValueBinding . h >
2014-03-05 19:09:15 -06:00
# include < AppKit / NSEvent . h >
2014-03-01 03:17:32 -06:00
2014-03-01 16:01:28 -06:00
/ * exception to the above : cgo doesn ' t like Nil and delegate_darwin . go has // export so I can ' t have this there * /
Class NilClass = Nil ;
2014-03-02 22:11:29 -06:00
/ * used by listbox_darwin . go ; requires NSString * /
id * _NSObservedObjectKey = ( id * ) ( & NSObservedObjectKey ) ;
2014-03-01 03:17:32 -06:00
/ *
NSUInteger is listed as being in < objc / NSObjCRuntime . h > . . . which doesn ' t exist . Rather than relying on undocumented header file locations or explicitly typedef - ing NSUInteger to the ( documented ) unsigned long , I ' ll just place things here for maximum safety . I use uintptr_t as that should encompass every possible unsigned long .
* /
2014-03-02 22:28:43 -06:00
uintptr_t objc_msgSend _uintret _noargs ( id obj , SEL sel )
{
return ( uintptr_t ) ( ( NSUInteger ) objc_msgSend ( obj , sel ) ) ;
}
2014-03-01 03:17:32 -06:00
id _objc _msgSend _uint ( id obj , SEL sel , uintptr_t a )
{
return objc_msgSend ( obj , sel , ( NSUInteger ) a ) ;
}
2014-03-02 22:28:43 -06:00
id objc_msgSend _id _uint ( id obj , SEL sel , id a , uintptr_t b )
{
return objc_msgSend ( obj , sel , a , ( NSUInteger ) b ) ;
}
2014-03-01 19:31:17 -06:00
/ *
same as above , but for NSInteger
* /
2014-03-02 17:38:45 -06:00
intptr_t objc_msgSend _intret _noargs ( id obj , SEL sel )
{
return ( intptr_t ) ( ( NSInteger ) objc_msgSend ( obj , sel ) ) ;
}
2014-03-01 19:31:17 -06:00
id objc_msgSend _int ( id obj , SEL sel , intptr_t a )
{
return objc_msgSend ( obj , sel , ( NSInteger ) a ) ;
}
2014-03-02 16:44:13 -06:00
id objc_msgSend _id _int ( id obj , SEL sel , id a , intptr_t b )
{
return objc_msgSend ( obj , sel , a , ( NSInteger ) b ) ;
}
2014-03-01 03:17:32 -06:00
/ *
These are the objc_msgSend ( ) wrappers around NSRect . The problem is that while on 32 - bit systems , NSRect is a concrete structure , on 64 - bit systems it ' s just a typedef to CGRect . While in practice just using CGRect everywhere seems to work , better to be safe than sorry .
I use int64_t for maximum safety , as my coordinates are stored as Go ints and Go int -> C int ( which is what is documented as happening ) isn ' t reliable .
* /
2014-03-01 14:58:54 -06:00
/ *
2014-03-01 20:42:57 -06:00
This is not documented in the docs , but is in various places on apple . com . In fact , the docs are actually WRONG : they say you pass a pointer to the structure as the first argument to objc_msgSend _stret ( ) ! And there might be some cases where we can ' t use stret because the struct is small enough . . .
2014-03-01 14:58:54 -06:00
* /
static NSRect ( * objc_msgSend _stret _rect ) ( id , SEL , . . . ) =
( NSRect ( * ) ( id , SEL , . . . ) ) objc_msgSend _stret ;
2014-03-01 12:58:38 -06:00
struct xrect objc_msgSend _stret _rect _noargs ( id obj , SEL sel )
{
NSRect s ;
struct xrect t ;
2014-03-01 14:58:54 -06:00
s = objc_msgSend _stret _rect ( obj , sel ) ;
2014-03-01 12:58:38 -06:00
t . x = ( int64_t ) s . origin . x ;
t . y = ( int64_t ) s . origin . y ;
t . width = ( int64_t ) s . size . width ;
t . height = ( int64_t ) s . size . height ;
return t ;
}
2014-03-01 03:17:32 -06:00
# define OurRect ( ) ( NSMakeRect ( ( CGFloat ) x , ( CGFloat ) y , ( CGFloat ) w , ( CGFloat ) h ) )
id _objc _msgSend _rect ( id obj , SEL sel , int64_t x , int64_t y , int64_t w , int64_t h )
{
return objc_msgSend ( obj , sel , OurRect ( ) ) ;
}
2014-03-01 12:29:24 -06:00
id _objc _msgSend _rect _bool ( id obj , SEL sel , int64_t x , int64_t y , int64_t w , int64_t h , BOOL b )
{
return objc_msgSend ( obj , sel , OurRect ( ) , b ) ;
}
2014-03-01 03:17:32 -06:00
id _objc _msgSend _rect _uint _uint _bool ( id obj , SEL sel , int64_t x , int64_t y , int64_t w , int64_t h , uintptr_t b , uintptr_t c , BOOL d )
{
return objc_msgSend ( obj , sel , OurRect ( ) , ( NSUInteger ) b , ( NSUInteger ) c , d ) ;
}
2014-03-01 03:21:47 -06:00
/ *
Same as NSRect above , but for NSSize now .
* /
2014-03-01 20:42:57 -06:00
/ *
2014-03-01 20:52:15 -06:00
. . . like this one . ( Note which function is being cast below . ) This is an Intel - specific optimization ; though this code won ' t run on PowerPC Macs ( Go , and thus package ui , requires 10.6 ) , if desktop ARM becomes a thing all bets are off . ( tl ; dr TODO )
2014-03-01 20:42:57 -06:00
* /
2014-03-01 14:58:54 -06:00
static NSSize ( * objc_msgSend _stret _size ) ( id , SEL , . . . ) =
2014-03-01 20:42:57 -06:00
( NSSize ( * ) ( id , SEL , . . . ) ) objc_msgSend ;
2014-03-01 14:58:54 -06:00
2014-03-01 03:21:47 -06:00
struct xsize objc_msgSend _stret _size _noargs ( id obj , SEL sel )
{
NSSize s ;
struct xsize t ;
2014-03-01 14:58:54 -06:00
s = objc_msgSend _stret _size ( obj , sel ) ;
2014-03-01 03:21:47 -06:00
t . width = ( int64_t ) s . width ;
t . height = ( int64_t ) s . height ;
return t ;
}
2014-03-02 22:11:29 -06:00
/ *
This is a doozy : it deals with a NSUInteger array needed for this one selector , and converts them all into a uintptr_t array so we can use it from Go . The two arrays are created at runtime with malloc ( ) ; only the NSUInteger one is freed here , while Go frees the returned one . It ' s not optimal .
* /
2014-03-02 22:28:43 -06:00
static SEL getIndexes ;
static BOOL getIndexes_init = NO ; / * because we can ' t initialize it out here * /
2014-03-02 22:11:29 -06:00
uintptr_t * NSIndexSetEntries ( id indexset , uintptr_t count )
{
NSUInteger * nsuints ;
uintptr_t * ret ;
uintptr_t i ;
size_t countsize ;
2014-03-02 22:28:43 -06:00
if ( getIndexes_init = = NO ) {
2014-03-03 00:51:54 -06:00
getIndexes = sel_getUid ( "getIndexes:maxCount:inIndexRange:" ) ;
2014-03-02 22:28:43 -06:00
getIndexes_init = YES ;
}
2014-03-02 22:11:29 -06:00
countsize = ( size_t ) count ;
nsuints = ( NSUInteger * ) malloc ( countsize * sizeof ( NSUInteger ) ) ;
/ * TODO check return value * /
objc_msgSend ( indexset , getIndexes ,
nsuints , ( NSUInteger ) count , nil ) ;
ret = ( uintptr_t * ) malloc ( countsize * sizeof ( uintptr_t ) ) ;
for ( i = 0 ; i < count ; i + + ) {
ret [ i ] = ( uintptr_t ) nsuints [ i ] ;
}
free ( nsuints ) ;
return ret ;
}
2014-03-05 19:09:15 -06:00
/ *
See uitask_darwin . go : we need to synthesize a NSEvent so - [ NSApplication stop : ] will work . We cannot simply init the default NSEvent though ( it throws an exception ) so we must do it "the right way" . This involves a very convoluted initializer ; we ' ll just do it here to keep things clean on the Go side ( this will only be run once anyway , on program exit ) .
* /
static id c_NSEvent ;
static SEL s_newEvent ;
static BOOL newEvent_init = NO ;
id makeDummyEvent ( )
{
if ( newEvent_init = = NO ) {
c_NSEvent = objc_getClass ( "NSEvent" ) ;
s_newEvent = sel_getUid ( "otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:" ) ;
newEvent_init = YES ;
}
return objc_msgSend ( c_NSEvent , s_newEvent ,
( NSUInteger ) NSApplicationDefined , / * otherEventWithType : * /
NSMakePoint ( 0 , 0 ) , / * location : * /
( NSUInteger ) 0 , / * modifierFlags : * /
( double ) 0 , / * timestamp : * /
( NSInteger ) 0 , / * windowNumber : * /
nil , / * context : * /
( short ) 0 , / * subtype : * /
( NSInteger ) 0 , / * data1 : * /
( NSInteger ) 0 ) ; / * data2 : * /
}