-
Notifications
You must be signed in to change notification settings - Fork 123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Working EventLoop by fixing Framework NSString* constant NSDefaultRunLoopMode #56
Working EventLoop by fixing Framework NSString* constant NSDefaultRunLoopMode #56
Conversation
Wow this is awesome :) |
@trevorlinton Any comments? Seems to work for me. |
I haven't had a chance to dig into it just yet, i'll pull down the request and give it a whirl. |
I'm fine with integrating the changes; doesn't seem to break any of the unit tests (and the core changes seem great). I'm not really sure how this fixes #53 or #2. Shane, maybe you can provide some direction here? I haven't been able to get an event loop to run with NSApplication or use any UI elements. In other words, YES to the pull, but lets keep #53/#2 open until we can provide directions on running co-habitated NSApp loops with nodobjc. Here's the test I tried: var $ = require('../')
, assert = require('assert')
, util = require('util')
, events = require('events')
$.import('Foundation')
$.import('Cocoa')
function EventLoop(start) {
events.EventEmitter.call(this)
assert.equal($.NSDefaultRunLoopMode, 'kCFRunLoopDefaultMode')
if (start) this.start();
return this
}
util.inherits(EventLoop, events.EventEmitter)
EventLoop.prototype.start = function() {
this.emit('start')
return this.schedule(true)
}
EventLoop.prototype.stop = function() {
this._is_running = false
this.emit('stop')
return this
}
EventLoop.prototype._schedule = setTimeout
EventLoop.prototype.schedule = function(runRecurring) {
if (runRecurring !== undefined)
this._is_running = runRecurring
var memento = this._schedule(this.eventLoop.bind(this))
this.emit('scheduled', memento, this._is_running)
return this
}
EventLoop.prototype.eventLoop = function(runRecurring) {
this.eventLoopCore()
if (this._is_running || runRecurring)
this.schedule(runRecurring)
return this
}
EventLoop.prototype.eventLoopCore = function(block) {
var untilDate = block ? $.NSDate('distantFuture') : null; // or $.NSDate('distantPast') to not block
var event, app = $.NSApplication('sharedApplication')
var runLoopPool = $.NSAutoreleasePool('alloc')('init')
var count = 0;
try {
this.emit('eventLoop-enter')
do {
this.emit('event-next', count)
event = app('nextEventMatchingMask',
$.NSAnyEventMask.toString(), // …grumble… uint64 as string …grumble…
'untilDate', untilDate,
'inMode', $.NSDefaultRunLoopMode,
'dequeue', 1)
this.emit('event-match', event, app, count)
if (event) {
app('sendEvent', event)
this.emit('event-sent', event, app, count)
}
++count;
} while (event)
this.emit('eventLoop-exit', count)
} catch (err) {
this.emit('error', err)
throw err
} finally {
runLoopPool('drain')
}
return this;
}
var pool = $.NSAutoreleasePool('alloc')('init')
var Obj = $.NSObject.extend('Obj')
, invokeCount = 0
, eventLoopCount = 0
var evtLoop = new EventLoop()
evtLoop.on('eventLoop-exit', function(count) { eventLoopCount += count })
/*Obj.addMethod('sel:', 'v@:@', function (self, _cmd, timer) {
assert.equal('Info', timer('userInfo').toString())
if (++invokeCount == 5) {
timer('invalidate');
evtLoop.stop()
}
}).register()*/
/*var timer = $.NSTimer('scheduledTimerWithTimeInterval', 0.1
,'target', Obj('alloc')('init')
,'selector', 'sel:'
,'userInfo', $('Info')
,'repeats', 1)*/
//process.on('exit', function () {
// assert.equal(invokeCount, 5)
// assert(eventLoopCount > invokeCount, eventLoopCount+' evts > '+invokeCount+' timers')
//})
evtLoop.start();
$.import('Cocoa');
var app = $.NSApplication('sharedApplication'), appcount = 0;
var AppDelegate = $.NSObject.extend('AppDelegate')
AppDelegate.addMethod('applicationDidFinishLaunching:', 'v@:@', function (self, _cmd, notif) {
setInterval(function() {
appcount++;
if(appcount == 5) {
assert.equal(appcount, 5);
process.exit(0);
}
console.log("Run "+appcount);
}, 1000);
console.log("Run");
});
AppDelegate.register();
var delegate = AppDelegate('alloc')('init');
app('setDelegate', delegate);
console.log("Begin");
app('run');
console.log("Error");
process.exit(1); Let me know if i'm missing something. |
The code is close; however, The replacement logic for |
As noted in issue #2, I also added EventLoop-power to |
…tring Working EventLoop by fixing Framework NSString* constant NSDefaultRunLoopMode
Merged! |
Via npm I currently don't get the Fix "Fixed resolution of Framework constants like NSDefaultRunLoopMode ..." in NodObjC. So to access Cocoa constants I have to patch import.js manually. Do I miss something? |
@bernhard-42 I'll do a new release to npm today. |
@TooTallNate Seems there is still 1.0.0 on npm ... |
Having implemented asynchronous event loops before, I was investigating why @JeanSebTr's code example in issue #53 was not working. Poking around with PyObjC, the value of
NSDefaultRunLoopMode
should have been "kCFRunLoopDefaultMode", but was coming backnull
. Using PyObjC's implementation to troubleshoot, I was able to create a patch for constant resolving inlib/import.js
that fixes the problem. It also enables a node-friendly Cocoa application event loop to address issue #53 and #2.