diff --git a/area_darwin.go b/area_darwin.go index 2041494..c5f0549 100644 --- a/area_darwin.go +++ b/area_darwin.go @@ -12,6 +12,7 @@ import ( //// #include // #include "objc_darwin.h" // extern BOOL areaView_isFlipped_acceptsFirstResponder(id, SEL); +// extern void areaView_updateTrackingAreas(id, SEL); // extern void areaView_mouseMoved_mouseDragged(id, SEL, id); // extern void areaView_mouseDown(id, SEL, id); // extern void areaView_mouseUp(id, SEL, id); @@ -36,6 +37,8 @@ var goAreaSels = []selector{ "ensuring that an Area's coordinate system has (0,0) at the top-left corner"}, selector{"acceptsFirstResponder", uintptr(C.areaView_isFlipped_acceptsFirstResponder), sel_bool, "registering that Areas are to receive events"}, + selector{"updateTrackingAreas", uintptr(C.areaView_updateTrackingAreas), sel_void, + "updating tracking areas for handling mouse movements in Area"}, selector{"mouseMoved:", uintptr(C.areaView_mouseMoved_mouseDragged), sel_void_id, "handling mouse movements in Area"}, selector{"mouseDown:", uintptr(C.areaView_mouseDown), sel_void_id, @@ -78,6 +81,7 @@ func makeArea(parentWindow C.id, alternate bool, s *sysData) C.id { area := C.objc_msgSend_noargs(_goArea, _alloc) area = initWithDummyFrame(area) // TODO others? + retrack(area, s) area = newScrollView(area) addControl(parentWindow, area) return area @@ -117,6 +121,24 @@ func areaView_isFlipped_acceptsFirstResponder(self C.id, sel C.SEL) C.BOOL { return C.BOOL(C.YES) } +var ( + _addTrackingArea = sel_getUid("addTrackingArea:") + _removeTrackingArea = sel_getUid("removeTrackingArea:") +) + +func retrack(area C.id, s *sysData) { + s.trackingArea = C.makeTrackingArea(area) + C.objc_msgSend_id(area, _addTrackingArea, s.trackingArea) +} + +//export areaView_updateTrackingAreas +func areaView_updateTrackingAreas(self C.id, sel C.SEL) { + s := getSysData(self) + C.objc_msgSend_id(self, _removeTrackingArea, s.trackingArea) + C.objc_msgSend_noargs(s.trackingArea, _release) + retrack(self, s) +} + var ( _NSEvent = objc_getClass("NSEvent") @@ -175,6 +197,7 @@ func areaMouseEvent(self C.id, e C.id, click bool, up bool) { which = 0 // reset for Held processing below } // pressedMouseButtons is a class method; calling objc_msgSend() directly with e as an argument on these will panic (in real Objective-C the compiler can detect [e pressedMouseButtons]) + // the docs do say don't use this for tracking since it returns the state now, and mouse move events work by tracking, but as far as I can tell dragging the mouse over the inactive window does n ot generate an event on Mac OS X, so :/ (TODO see what happens when the program is the current one; in my own separate tests no harm was done so eh; also no need for this if tracking doesn't touch dragging) held := C.objc_msgSend_uintret_noargs(_NSEvent, _pressedMouseButtons) if which != 1 && (held & 1) != 0 { // button 1 me.Held = append(me.Held, 1) @@ -200,8 +223,8 @@ func areaMouseEvent(self C.id, e C.id, click bool, up bool) { //export areaView_mouseMoved_mouseDragged func areaView_mouseMoved_mouseDragged(self C.id, sel C.SEL, e C.id) { + // for moving, this is handled by the tracking rect stuff above // for dragging, if multiple buttons are held, only one of their xxxMouseDragged: messages will be sent, so this is OK to do - // TODO implement tracking for dragging areaMouseEvent(self, e, false, false) } diff --git a/bleh_darwin.m b/bleh_darwin.m index b537603..bc44f0f 100644 --- a/bleh_darwin.m +++ b/bleh_darwin.m @@ -21,6 +21,7 @@ though this is not always the case. #include #include #include +#include /* used by listbox_darwin.go; requires NSString */ id *_NSObservedObjectKey = (id *) (&NSObservedObjectKey); @@ -43,6 +44,9 @@ static id c_NSFont; static SEL s_setFont; /* objc_setFont() */ static SEL s_systemFontOfSize; static SEL s_systemFontSizeForControlSize; +static id c_NSTrackingArea; +static SEL s_bounds; +static SEL s_initTrackingArea; void initBleh() { @@ -60,6 +64,9 @@ void initBleh() s_setFont = sel_getUid("setFont:"); s_systemFontOfSize = sel_getUid("systemFontOfSize:"); s_systemFontSizeForControlSize = sel_getUid("systemFontSizeForControlSize:"); + c_NSTrackingArea = objc_getClass("NSTrackingArea"); + s_bounds = sel_getUid("bounds"); + s_initTrackingArea = sel_getUid("initWithRect:options:owner:userInfo:"); } /* @@ -350,3 +357,25 @@ static NSApplicationTerminateReply __appDelegate_applicationShouldTerminate(id s void *_appDelegate_applicationShouldTerminate = (void *) __appDelegate_applicationShouldTerminate; char *encodedTerminateReply = @encode(NSApplicationTerminateReply); + +/* +tracking areas; also here for convenience only +*/ + +/* IDK if this is needed; just to be safe */ +static id (*objc_msgSend_initTrackingArea)(id, SEL, NSRect, NSTrackingAreaOptions, id, id) = + (id (*)(id, SEL, NSRect, NSTrackingAreaOptions, id, id)) objc_msgSend; + +id makeTrackingArea(id area) +{ + id trackingArea; + + trackingArea = objc_msgSend(c_NSTrackingArea, s_alloc); + trackingArea = (*objc_msgSend_initTrackingArea)(trackingArea, s_initTrackingArea, + (*objc_msgSend_stret_rect)(area, s_bounds), /* initWithRect: */ + /* this bit mask (except for NSTrackingInVisibleRect, which was added later) comes from https://github.com/andlabs/misctestprogs/blob/master/cocoaviewmousetest.m (and I wrote this bit mask on 25 april 2014) and yes I know it includes enter/exit even though we don't watch those events; it probably won't really matter anyway but if it does I can change it easily */ + (NSTrackingAreaOptions) (NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingEnabledDuringMouseDrag | NSTrackingInVisibleRect), /* options: */ + area, /* owner: */ + nil); /* userData: */ + return trackingArea; +} diff --git a/objc_darwin.go b/objc_darwin.go index b8d5f8f..c1b610d 100644 --- a/objc_darwin.go +++ b/objc_darwin.go @@ -98,6 +98,7 @@ const ( sel_bool sel_void_rect sel_terminatereply_id + sel_void nitypes ) @@ -107,6 +108,7 @@ var itypes = [nitypes][]C.char{ sel_bool: []C.char{'c', '@', ':', 0}, sel_void_rect: nil, // see init() below sel_terminatereply_id: nil, + sel_void: []C.char{'v', '@', ':', 0}, } func init() { diff --git a/objc_darwin.h b/objc_darwin.h index aaca07e..c7a7157 100644 --- a/objc_darwin.h +++ b/objc_darwin.h @@ -112,8 +112,10 @@ extern void initBleh(); extern id makeDummyEvent(); /* for area_darwin.go */ +/* TODO apparently ISO C forbids casting a function pointer to a non-function pointer; this will need to change???? */ extern void *_areaView_drawRect; extern void drawImage(void *, int64_t, int64_t, int64_t, int64_t, int64_t); +extern id makeTrackingArea(id); extern struct xpoint getTranslatedEventPoint(id, id); /* for objc_darwin.go */ diff --git a/sysdata_darwin.go b/sysdata_darwin.go index 08ca202..0bcf316 100644 --- a/sysdata_darwin.go +++ b/sysdata_darwin.go @@ -50,7 +50,6 @@ var ( _initWithContentRect = sel_getUid("initWithContentRect:styleMask:backing:defer:") _initWithFrame = sel_getUid("initWithFrame:") _setDelegate = sel_getUid("setDelegate:") - _setAcceptsMouseMovedEvents = sel_getUid("setAcceptsMouseMovedEvents:") _makeKeyAndOrderFront = sel_getUid("makeKeyAndOrderFront:") _orderOut = sel_getUid("orderOut:") _setHidden = sel_getUid("setHidden:") @@ -147,8 +146,7 @@ var classTypes = [nctypes]*classData{ C.uintptr_t(_NSBackingStoreBuffered), C.BOOL(C.YES)) // defer creation of device until we show the window C.objc_msgSend_id(win, _setDelegate, appDelegate) - // this is needed for Areas in the window to receive mouse move events -// C.objc_msgSend_bool(win, _setAcceptsMouseMovedEvents, C.BOOL(C.YES)) + // we do not need setAcceptsMouseMovedEvents: here since we are using a tracking rect in Areas for that return win }, show: func(what C.id) {