667
edits
Changes
Created page with '==Doing the callbacks in IDL/C++== Consider a similar interface already in the DOM, navigator.geolocation.getCurrentPosition: https://mxr.mozilla.org/mozilla-central/source/dom…'
==Doing the callbacks in IDL/C++==
Consider a similar interface already in the DOM, navigator.geolocation.getCurrentPosition:
https://mxr.mozilla.org/mozilla-central/source/dom/interfaces/geolocation/nsIDOMGeoGeolocation.idl
<pre>
44 [scriptable, function, uuid(37687DAF-B85F-4E4D-8881-85A0AD24CF78)]
45 interface nsIDOMGeoGeolocation : nsISupports
46 {
47 void getCurrentPosition(in nsIDOMGeoPositionCallback successCallback,
48 [optional] in nsIDOMGeoPositionErrorCallback errorCallback,
49 [optional] in nsIDOMGeoPositionOptions options);
</pre>
Here's the C++. Notice how the callbacks have become their own types: nsIDOMGeoPositionCallback and nsIDOMGeoPositionErrorCallback
<pre>
918 NS_IMETHODIMP
919 nsGeolocation::GetCurrentPosition(nsIDOMGeoPositionCallback *callback,
920 nsIDOMGeoPositionErrorCallback *errorCallback,
921 nsIDOMGeoPositionOptions *options)
922 {
923 NS_ENSURE_ARG_POINTER(callback);
924
925 if (!sGeoEnabled)
926 return NS_ERROR_NOT_AVAILABLE;
927
928 if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW)
929 return NS_ERROR_NOT_AVAILABLE;
930
931 nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this,
932 callback,
933 errorCallback,
934 options,
935 false);
</pre>
The callback (and errorCallback) are passed into the ctor for nsGeolocationRequest. It holds on to them as member variables:
<pre>
239 nsGeolocationRequest::nsGeolocationRequest(nsGeolocation* aLocator,
240 nsIDOMGeoPositionCallback* aCallback,
241 nsIDOMGeoPositionErrorCallback* aErrorCallback,
242 nsIDOMGeoPositionOptions* aOptions,
243 bool aWatchPositionRequest)
244 : mAllowed(false),
245 mCleared(false),
246 mIsWatchPositionRequest(aWatchPositionRequest),
247 mCallback(aCallback),
248 mErrorCallback(aErrorCallback),
249 mOptions(aOptions),
250 mLocator(aLocator)
251 {
252 }
</pre>
When it's time to finish the request, it uses these to trigger the call back in JS:
<pre>
432 void
433 nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
434 {
435 if (mCleared || !mAllowed)
436 return;
437
438 if (mTimeoutTimer) {
439 mTimeoutTimer->Cancel();
440 mTimeoutTimer = nsnull;
441 }
442
443 // we should not pass null back to the DOM.
444 if (!aPosition) {
445 NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
446 return;
447 }
448
449 // Ensure that the proper context is on the stack (bug 452762)
450 nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
451 if (!stack || NS_FAILED(stack->Push(nsnull)))
452 return; // silently fail
453
454 mCallback->HandleEvent(aPosition);
455
456 // remove the stack
457 JSContext* cx;
458 stack->Pop(&cx);
459
460 if (mIsWatchPositionRequest)
461 SetTimeoutTimer();
462 }
</pre>
The callback DOM object wrapper looks like this:
<pre>
42 [scriptable, function, uuid(527E8B53-6F29-4B6A-8D04-5C1666A4C4C1)]
43 interface nsIDOMGeoPositionCallback : nsISupports {
44 void handleEvent(in nsIDOMGeoPosition position);
45 };
</pre>
So an nsDOMGeoPositionCallback is really an object with a single method, handleEvent, that takes an nsIDOMGeoPosition.
Consider a similar interface already in the DOM, navigator.geolocation.getCurrentPosition:
https://mxr.mozilla.org/mozilla-central/source/dom/interfaces/geolocation/nsIDOMGeoGeolocation.idl
<pre>
44 [scriptable, function, uuid(37687DAF-B85F-4E4D-8881-85A0AD24CF78)]
45 interface nsIDOMGeoGeolocation : nsISupports
46 {
47 void getCurrentPosition(in nsIDOMGeoPositionCallback successCallback,
48 [optional] in nsIDOMGeoPositionErrorCallback errorCallback,
49 [optional] in nsIDOMGeoPositionOptions options);
</pre>
Here's the C++. Notice how the callbacks have become their own types: nsIDOMGeoPositionCallback and nsIDOMGeoPositionErrorCallback
<pre>
918 NS_IMETHODIMP
919 nsGeolocation::GetCurrentPosition(nsIDOMGeoPositionCallback *callback,
920 nsIDOMGeoPositionErrorCallback *errorCallback,
921 nsIDOMGeoPositionOptions *options)
922 {
923 NS_ENSURE_ARG_POINTER(callback);
924
925 if (!sGeoEnabled)
926 return NS_ERROR_NOT_AVAILABLE;
927
928 if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW)
929 return NS_ERROR_NOT_AVAILABLE;
930
931 nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this,
932 callback,
933 errorCallback,
934 options,
935 false);
</pre>
The callback (and errorCallback) are passed into the ctor for nsGeolocationRequest. It holds on to them as member variables:
<pre>
239 nsGeolocationRequest::nsGeolocationRequest(nsGeolocation* aLocator,
240 nsIDOMGeoPositionCallback* aCallback,
241 nsIDOMGeoPositionErrorCallback* aErrorCallback,
242 nsIDOMGeoPositionOptions* aOptions,
243 bool aWatchPositionRequest)
244 : mAllowed(false),
245 mCleared(false),
246 mIsWatchPositionRequest(aWatchPositionRequest),
247 mCallback(aCallback),
248 mErrorCallback(aErrorCallback),
249 mOptions(aOptions),
250 mLocator(aLocator)
251 {
252 }
</pre>
When it's time to finish the request, it uses these to trigger the call back in JS:
<pre>
432 void
433 nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
434 {
435 if (mCleared || !mAllowed)
436 return;
437
438 if (mTimeoutTimer) {
439 mTimeoutTimer->Cancel();
440 mTimeoutTimer = nsnull;
441 }
442
443 // we should not pass null back to the DOM.
444 if (!aPosition) {
445 NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
446 return;
447 }
448
449 // Ensure that the proper context is on the stack (bug 452762)
450 nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
451 if (!stack || NS_FAILED(stack->Push(nsnull)))
452 return; // silently fail
453
454 mCallback->HandleEvent(aPosition);
455
456 // remove the stack
457 JSContext* cx;
458 stack->Pop(&cx);
459
460 if (mIsWatchPositionRequest)
461 SetTimeoutTimer();
462 }
</pre>
The callback DOM object wrapper looks like this:
<pre>
42 [scriptable, function, uuid(527E8B53-6F29-4B6A-8D04-5C1666A4C4C1)]
43 interface nsIDOMGeoPositionCallback : nsISupports {
44 void handleEvent(in nsIDOMGeoPosition position);
45 };
</pre>
So an nsDOMGeoPositionCallback is really an object with a single method, handleEvent, that takes an nsIDOMGeoPosition.