Void lock (in Element target, optional in VoidCallback successCallback, optional in VoidCallback failureCallback);

From CDOT Wiki
Jump to: navigation, search

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

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);

Here's the C++. Notice how the callbacks have become their own types: nsIDOMGeoPositionCallback and nsIDOMGeoPositionErrorCallback

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);

The callback (and errorCallback) are passed into the ctor for nsGeolocationRequest. It holds on to them as member variables:

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 }

When it's time to finish the request, it uses these to trigger the call back in JS:

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 }

The callback DOM object wrapper looks like this:

42 [scriptable, function, uuid(527E8B53-6F29-4B6A-8D04-5C1666A4C4C1)]
43 interface nsIDOMGeoPositionCallback : nsISupports {
44   void handleEvent(in nsIDOMGeoPosition position);
45 };

So an nsDOMGeoPositionCallback is really an object with a single method, handleEvent, that takes an nsIDOMGeoPosition.