2014-03-01 15:56:22 -06:00
// 27 february 2014
2014-03-12 20:55:45 -05:00
2014-03-01 15:56:22 -06:00
package ui
import (
"fmt"
"unsafe"
)
/ *
This creates a class goAppDelegate that will be used as the delegate for / everything / . Specifically , it :
- runs uitask requests ( uitask : )
- handles window close events ( windowShouldClose : )
2014-03-11 10:54:32 -05:00
- handles window resize events ( windowDidResize : )
2014-03-01 20:34:37 -06:00
- handles button click events ( buttonClicked : )
2014-03-01 15:56:22 -06:00
* /
// #cgo LDFLAGS: -lobjc -framework Foundation -framework AppKit
// #include <stdlib.h>
// #include "objc_darwin.h"
// extern void appDelegate_uitask(id, SEL, id); /* from uitask_darwin.go */
// extern BOOL appDelegate_windowShouldClose(id, SEL, id);
2014-03-01 17:01:30 -06:00
// extern void appDelegate_windowDidResize(id, SEL, id);
2014-03-01 20:34:37 -06:00
// extern void appDelegate_buttonClicked(id, SEL, id);
2014-03-01 15:56:22 -06:00
import "C"
var (
appDelegate C . id
)
const (
_goAppDelegate = "goAppDelegate"
)
var (
_uitask = sel_getUid ( "uitask:" )
_windowShouldClose = sel_getUid ( "windowShouldClose:" )
2014-03-01 17:01:30 -06:00
_windowDidResize = sel_getUid ( "windowDidResize:" )
2014-03-01 20:34:37 -06:00
_buttonClicked = sel_getUid ( "buttonClicked:" )
2014-03-01 15:56:22 -06:00
)
func mkAppDelegate ( ) error {
2014-03-01 16:01:28 -06:00
appdelegateclass , err := makeDelegateClass ( _goAppDelegate )
2014-03-01 15:56:22 -06:00
if err != nil {
return fmt . Errorf ( "error creating NSApplication delegate: %v" , err )
}
err = addDelegateMethod ( appdelegateclass , _uitask ,
C . appDelegate_uitask , delegate_void )
if err != nil {
return fmt . Errorf ( "error adding NSApplication delegate uitask: method (to do UI tasks): %v" , err )
}
err = addDelegateMethod ( appdelegateclass , _windowShouldClose ,
C . appDelegate_windowShouldClose , delegate_bool )
if err != nil {
return fmt . Errorf ( "error adding NSApplication delegate windowShouldClose: method (to handle window close button events): %v" , err )
}
2014-03-01 17:01:30 -06:00
err = addDelegateMethod ( appdelegateclass , _windowDidResize ,
C . appDelegate_windowDidResize , delegate_void )
if err != nil {
return fmt . Errorf ( "error adding NSApplication delegate windowDidResize: method (to handle window resize events): %v" , err )
}
2014-03-01 20:34:37 -06:00
err = addDelegateMethod ( appdelegateclass , _buttonClicked ,
C . appDelegate_buttonClicked , delegate_void )
if err != nil {
return fmt . Errorf ( "error adding NSApplication delegate buttonClicked: method (to handle button clicks): %v" , err )
}
2014-03-30 12:21:10 -05:00
appDelegate = objc_new ( objc_getClass ( _goAppDelegate ) )
2014-03-01 15:56:22 -06:00
return nil
}
//export appDelegate_windowShouldClose
func appDelegate_windowShouldClose ( self C . id , sel C . SEL , win C . id ) C . BOOL {
sysData := getSysData ( win )
sysData . signal ( )
return C . BOOL ( C . NO ) // don't close
}
2014-03-01 17:01:30 -06:00
var (
_object = sel_getUid ( "object" )
2014-03-02 18:13:26 -06:00
_display = sel_getUid ( "display" )
2014-03-01 17:01:30 -06:00
)
//export appDelegate_windowDidResize
func appDelegate_windowDidResize ( self C . id , sel C . SEL , notification C . id ) {
win := C . objc_msgSend_noargs ( notification , _object )
2014-03-29 22:57:49 -05:00
s := getSysData ( win )
2014-03-02 18:16:36 -06:00
wincv := C . objc_msgSend_noargs ( win , _contentView ) // we want the content view's size, not the window's; selector defined in sysdata_darwin.go
r := C . objc_msgSend_stret_rect_noargs ( wincv , _frame )
2014-03-29 22:57:49 -05:00
if s . resize != nil {
2014-03-03 16:44:03 -06:00
// winheight is used here because (0,0) is the bottom-left corner, not the top-left corner
2014-03-17 20:09:03 -05:00
s . resizes = s . resizes [ 0 : 0 ] // set len to 0 without changing cap
2014-03-29 22:57:49 -05:00
s . resize ( 0 , 0 , int ( r . width ) , int ( r . height ) , & s . resizes )
2014-03-17 20:09:03 -05:00
for _ , s := range s . resizes {
2014-03-17 19:42:36 -05:00
err := s . sysData . setRect ( s . x , s . y , s . width , s . height , int ( r . height ) )
if err != nil {
panic ( "child resize failed: " + err . Error ( ) )
}
2014-03-01 17:01:30 -06:00
}
}
2014-03-02 18:13:26 -06:00
C . objc_msgSend_noargs ( win , _display ) // redraw everything; TODO only if resize() was called?
2014-03-01 17:01:30 -06:00
}
2014-03-01 20:34:37 -06:00
//export appDelegate_buttonClicked
func appDelegate_buttonClicked ( self C . id , sel C . SEL , button C . id ) {
sysData := getSysData ( button )
sysData . signal ( )
}
2014-03-01 15:56:22 -06:00
// this actually constructs the delegate class
var (
2014-03-30 12:21:10 -05:00
// objc_getClass() says it returns an id but it's actually a Class
// thanks to Psy| in irc.freenode.net/##objc
// don't call object_getClass() on this then, as I originally thought — that returns the /metaclass/ (which we don't want, and in fact I wasn't even aware we COULD subclass the metaclass directly like this)
_NSObject_Class = C . Class ( unsafe . Pointer ( _NSObject ) )
2014-03-01 15:56:22 -06:00
)
func makeDelegateClass ( name string ) ( C . Class , error ) {
cname := C . CString ( name )
defer C . free ( unsafe . Pointer ( cname ) )
c := C . objc_allocateClassPair ( _NSObject_Class , cname , 0 )
if c == C . NilClass {
2014-03-29 22:57:49 -05:00
return C . NilClass , fmt . Errorf ( "unable to create Objective-C class %s for NSApplication delegate; reason unknown" , name )
2014-03-01 15:56:22 -06:00
}
C . objc_registerClassPair ( c )
return c , nil
}
var (
delegate_void = [ ] C . char { 'v' , '@' , ':' , '@' , 0 } // void (*)(id, SEL, id)
2014-03-01 16:15:26 -06:00
delegate_bool = [ ] C . char { 'c' , '@' , ':' , '@' , 0 } // BOOL (*)(id, SEL, id)
2014-03-01 15:56:22 -06:00
)
// according to errors spit out by cgo, C function pointers are unsafe.Pointer
func addDelegateMethod ( class C . Class , sel C . SEL , imp unsafe . Pointer , ty [ ] C . char ) error {
ok := C . class_addMethod ( class , sel , C . IMP ( imp ) , & ty [ 0 ] )
if ok == C . BOOL ( C . NO ) {
// TODO get function name
2014-03-29 22:57:49 -05:00
return fmt . Errorf ( "unable to add selector %v/imp %v to class %v (reason unknown)" , sel , imp , class )
2014-03-01 15:56:22 -06:00
}
return nil
}