-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathEventLoop.js
More file actions
125 lines (112 loc) · 3.75 KB
/
EventLoop.js
File metadata and controls
125 lines (112 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
var $, EventEmitter = require('events').EventEmitter;
// export EventLoop at module and as 'EventLoop'
module.exports = EventLoop.EventLoop = EventLoop
EventLoop.initObjC = function(NodObjC) {
$ = NodObjC || $ || require('NodObjC')
$.import('Cocoa')
EventLoop.prototype._runLoopMode = $.NSDefaultRunLoopMode
if (EventLoop.prototype._runLoopMode === null) {
EventLoop.prototype._runLoopMode = $('kCFRunLoopDefaultMode')
console.warn('WARNING: Falling back to hard-coded string for NSDefaultRunLoopMode constant. See https://github.com/TooTallNate/NodObjC/pull/56 for details.')
}
}
function EventLoop(start, options) {
EventEmitter.call(this)
if (options) {
if (options.runLoopMode) this._runLoopMode = options.runLoopMode
}
this.runInfo = {recurring:null, schedule_id:null, loop:{}}
if (start) this.start()
return this
}
require('util').inherits(EventLoop, EventEmitter)
EventLoop.prototype.start = function() {
this.emit('start')
return this.schedule(true)
}
EventLoop.prototype.stop = function() {
this.runInfo.recurring = false
this.emit('stop')
return this
}
EventLoop.prototype._schedule = setTimeout
EventLoop.prototype._clearSchedule = clearTimeout
EventLoop.prototype.schedule = function(runRecurring) {
var runInfo = this.runInfo
if (runRecurring !== undefined)
runInfo.recurring = !!runRecurring
if (runInfo.schedule_id != null)
return this; // exit if already scheduled
var id = this._schedule(this.eventLoop.bind(this))
runInfo.schedule_id = (id !== undefined) ? id : true
this.emit('scheduled', runInfo)
return this
}
EventLoop.prototype.clearSchedule = function() {
var runInfo = this.runInfo
var id = runInfo.schedule_id
runInfo.recurring = false
if (id != null) {
runInfo.schedule_id = null
this._clearSchedule(id)
this.emit('unscheduled', runInfo)
}
return this
}
EventLoop.prototype.isScheduled = function(runInfo) {
if (!runInfo) runInfo = this.runInfo
return runInfo.schedule_id!=null }
EventLoop.prototype.isActive = function(runInfo) {
if (!runInfo) runInfo = this.runInfo
return this.isScheduled(runInfo) || runInfo.recurring }
EventLoop.prototype.eventLoop = function(runRecurring) {
var runInfo = this.runInfo
runInfo.schedule_id = null
this.eventLoopCore()
if (runInfo.recurring || runRecurring)
this.schedule(runRecurring)
else if (runInfo.schedule_id==null)
this.emit('deactivate', this.runInfo)
return this
}
EventLoop.prototype.eventLoopCore = function(block) {
if ($==null) EventLoop.initObjC();
var runInfo = this.runInfo,
loopInfo = {running:true, count:0, t0:Date.now()},
event, app = $.NSApplication('sharedApplication'),
untilDate = block ? $.NSDate('distantFuture') : null, // or $.NSDate('distantPast') to not block
inMode = this._runLoopMode
var runLoopPool = $.NSAutoreleasePool('alloc')('init')
try {
runInfo.loop = loopInfo
this.emit('eventLoop-enter', runInfo)
do {
this.emit('event-next', event, app, runInfo)
event = app('nextEventMatchingMask',
$.NSAnyEventMask.toString(), // …grumble… uint64 as string …grumble…
'untilDate', untilDate,
'inMode', inMode,
'dequeue', 1)
this.emit('event-match', event, app, runInfo)
if (event) {
app('sendEvent', event)
this.emit('event-sent', event, app, runInfo)
}
++loopInfo.count
} while (event)
loopInfo.t1 = Date.now()
loopInfo.running = false
this.emit('eventLoop-exit', runInfo)
} catch (err) {
loopInfo.t1 = Date.now()
loopInfo.running = false
loopInfo.error = err
this.emit('error', err, runInfo)
throw err
} finally {
runLoopPool('drain')
}
delete loopInfo.running
this.emit('eventLoop', runInfo)
return this
}