Re: [whatwg] Proposal: Wake Lock API

2014-08-18 Thread Mounir Lamouri
On Sat, 16 Aug 2014, at 08:40, Jonas Sicking wrote:
 On Fri, Aug 15, 2014 at 6:14 AM, Mounir Lamouri mou...@lamouri.fr
 wrote:
  On Thu, 14 Aug 2014, at 11:00, Jonas Sicking wrote:
  I am however more worried about that only having a request() and a
  release() function means that pages that contain multiple independent
  subsystems will have to make sure that they don't stomp on each
  other's locks. Simply counting request() calls vs. release() calls
  helps, but doesn't fully solve the problem. It's very easy to
  accidentally call release too many times, in response to some UI
  action for example.
 
  An alternative design would be something like
 
  x = new WakeLock(display);
  x.request();
  x.release();
 
  Extra calls of either request() or release() are ignored, but pages
  can create any number of WakeLocks of the same type.
 
  It seems that we already discussed using an object and this solution was
  dismissed because of this model being error-prone.
 
 Where was this discussed? Why was it considered more error prone? Was
 it related to the patterns discussed at
 http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2014-August/297431.html

There might have been some discussions in the DAP WG (but the archives
website isn't helping). There was definitely at thread in blink-dev [1]
and you might want to have a look at the GitHub repo [2]. By the way, it
seems that this API might be worked in the DAP WG [3].

  It's also not clear
  how this solution is superior than the current solution [1] with regards
  to multiple releases or requests. In [1], if you call .request() or
  .release() multiple time, the promise reacts appropriately.
 
 The problem arises when you have several semi-independent pieces of
 code within a single page. Given that request() and release() is
 likely going to happen in response to very different UI events or IO
 events, it makes it fairly easy to accidentally have unbalanced calls.
 
 Consider for example a lock which is released either when a video
 reaches its end, when the user presses the pause button, or when the
 user close the dialog in which the video is rendered. It seems quite
 easy to end up with a race where if the user close the dialog right
 when the video ends, that release() would get called twice. Or if the
 user pause the video first and then close the dialog that release()
 would get called twice.
 
 If there's only one subsystem of the page that uses a display lock,
 then this is not a big deal. The extra call to release() would cause
 an rejection, but hopefully that won't break the page.

It is possible that the API might behave differently and the first
release() will release the lock even if lock() was called multiple
times. I guess the scope of the lock could be the browsing context so a
website will not end up conflicting with iframes. However, if a websites
embeds libraries that use this API, it will need to coordinate.

 However if there are multiple subsystems that all use a display lock,
 it would mean that those subsystems might stomp on each other's
 attempts at holding a display lock. The effect would be that the
 display lock is released too early.
 
 I don't care strongly about this though. It's pretty easy for pages to
 write a wrapper around the currently proposed API to implement the API
 that I'm proposing.

I understand the problem and I agree that an object-based approach would
be nicer in theory because the scope of the lock would be well defined.
However, it's a very uncommon pattern as far as Web APIs are concerned
and I would worry that developers would end up  doing things wrong and
depend on the GC behaviour without even being aware of it.

[1]
https://groups.google.com/a/chromium.org/d/msg/blink-dev/SzVuAi2KRhA/OaNDiHOKl8gJ
[2] https://github.com/w3c/wake-lock
[3]
http://lists.w3.org/Archives/Public/public-device-apis/2014Aug/0035.html

-- Mounir


Re: [whatwg] Proposal: Wake Lock API

2014-08-18 Thread Tab Atkins Jr.
On Sat, Aug 16, 2014 at 9:19 AM, Nils Dagsson Moskopp
n...@dieweltistgarnichtso.net wrote:
 Jonas Sicking jo...@sicking.cc writes:
 On Fri, Aug 15, 2014 at 6:14 AM, Mounir Lamouri mou...@lamouri.fr wrote:
 On Thu, 14 Aug 2014, at 11:00, Jonas Sicking wrote:
 I am however more worried about that only having a request() and a
 release() function means that pages that contain multiple independent
 subsystems will have to make sure that they don't stomp on each
 other's locks. Simply counting request() calls vs. release() calls
 helps, but doesn't fully solve the problem. It's very easy to
 accidentally call release too many times, in response to some UI
 action for example.

 An alternative design would be something like

 x = new WakeLock(display);
 x.request();
 x.release();

 Extra calls of either request() or release() are ignored, but pages
 can create any number of WakeLocks of the same type.

 It seems that we already discussed using an object and this solution was
 dismissed because of this model being error-prone.

 Where was this discussed? Why was it considered more error prone? Was
 it related to the patterns discussed at

 http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2014-August/297431.html

 It's also not clear
 how this solution is superior than the current solution [1] with regards
 to multiple releases or requests. In [1], if you call .request() or
 .release() multiple time, the promise reacts appropriately.

 The problem arises when you have several semi-independent pieces of
 code within a single page. Given that request() and release() is
 likely going to happen in response to very different UI events or IO
 events, it makes it fairly easy to accidentally have unbalanced calls.

 Consider for example a lock which is released either when a video
 reaches its end, when the user presses the pause button, or when the
 user close the dialog in which the video is rendered. It seems quite
 easy to end up with a race where if the user close the dialog right
 when the video ends, that release() would get called twice. Or if the
 user pause the video first and then close the dialog that release()
 would get called twice.

 Seems to me a declarative solution (like CSS) might be appropriate.

 @media screen {
 video:playing {
 wake-lock: display 15s;
 }
 }

 article.recipe:target {
 wake-lock: display;
 }

That's not a terrible idea.  The CSSWG is generally hesitant to put
behavior-altering things in CSS, but some bleed-through is fine, and
this can be argued as an aspect of appearance.

This solves the GC and locking issues (the latter by delegating state
management to CSS, which everyone already knows to use).

~TJ


Re: [whatwg] Proposal: Wake Lock API

2014-08-18 Thread Jonas Sicking
On Mon, Aug 18, 2014 at 2:04 AM, Mounir Lamouri mou...@lamouri.fr wrote:

  It's also not clear
  how this solution is superior than the current solution [1] with regards
  to multiple releases or requests. In [1], if you call .request() or
  .release() multiple time, the promise reacts appropriately.

 The problem arises when you have several semi-independent pieces of
 code within a single page. Given that request() and release() is
 likely going to happen in response to very different UI events or IO
 events, it makes it fairly easy to accidentally have unbalanced calls.

 Consider for example a lock which is released either when a video
 reaches its end, when the user presses the pause button, or when the
 user close the dialog in which the video is rendered. It seems quite
 easy to end up with a race where if the user close the dialog right
 when the video ends, that release() would get called twice. Or if the
 user pause the video first and then close the dialog that release()
 would get called twice.

 If there's only one subsystem of the page that uses a display lock,
 then this is not a big deal. The extra call to release() would cause
 an rejection, but hopefully that won't break the page.

 It is possible that the API might behave differently and the first
 release() will release the lock even if lock() was called multiple
 times. I guess the scope of the lock could be the browsing context so a
 website will not end up conflicting with iframes. However, if a websites
 embeds libraries that use this API, it will need to coordinate.

I'd rather have request() and release() work as they are defined now.
Otherwise coordinating becomes even harder as the specification does
not provide a coordination mechanism.

 However if there are multiple subsystems that all use a display lock,
 it would mean that those subsystems might stomp on each other's
 attempts at holding a display lock. The effect would be that the
 display lock is released too early.

 I don't care strongly about this though. It's pretty easy for pages to
 write a wrapper around the currently proposed API to implement the API
 that I'm proposing.

 I understand the problem and I agree that an object-based approach would
 be nicer in theory because the scope of the lock would be well defined.
 However, it's a very uncommon pattern as far as Web APIs are concerned
 and I would worry that developers would end up  doing things wrong and
 depend on the GC behaviour without even being aware of it.

Note that in the API that I'm proposing, there is no way to
accidentally rely on GC behavior. If a WakeLock object is GCed before
it has been release()ed, then the lock is held indefinitely (until the
user leaves the page of course).

I.e. an unbalanced request() and release() in both the currently
proposed API, and in the API that I propose behave the same, the lock
is held indefinitely. Any objects getting GCed does not change this.

Again, I don't feel terribly strongly about this as it's easy to shim
in either direction.

/ Jonas


Re: [whatwg] Proposal: Wake Lock API

2014-08-18 Thread Kornel Lesiński
I think it'd be unfortunate if this API had just one shared lock per browsing 
context and required components on the page to coordinate locking, but provided 
no means to do so. This will force authors of libraries and components to 
create dummy iframes just to have their private lock, and libraries/pages 
without such workaround will be messing up each other's locks.

Having just a single shared DOM0-style event handler navigator.wakeLock.onlost 
looks especially jarring. I would expect this to be a proper DOM event that can 
be used with normal addEventListener (please avoid repeating the mistake of 
matchMedia).


To make some coordination possible, the simplest method could be to keep track 
of number of lock requests and releases, like retain/release in Objective-C:

navigator.wakeLock.request(screen); // locks
navigator.wakeLock.request(screen); // increases lock count
navigator.wakeLock.release(screen); // not released yet, but decreases lock 
count
navigator.wakeLock.release(screen); // now released for real

However, as you probably know from Objective-C, perfect balancing of 
retain/release takes care and discipline. Personally, I wouldn't trust all 3rd 
party libraries/widgets/ads to be careful with this. In fact, I expect some 
clever libraries to ruin this with:

while(navigator.wakeLock.isHeld(screen)) 
navigator.wakeLock.release(screen); // just release the damn thing in my 
leaky code!


Therefore, if WakeLock needs to be purely JS API, I strongly prefer having 
WakeLock available only as an object instance, but without exposing GC 
behavior—if it's lost, it's like a missing release call. 

If devtools ever get monitoring of unhanded errors in Promise objects, they 
could also warn against lost WakeLock objects—it's the same type of problem 
dependent on GC.

I'm assuming that release would work only once on each lock object:

var lock = new WakeLock(screen);
lock.release();
lock.release(); // ignored, so it doesn't unlock any other component's lock

This makes coordination easier: each page component can easily create their own 
lock independently (without needing to create an iframe to get their own lock), 
and can't release any other component's lock.


-- 
regards, Kornel





[whatwg] Feature-detectable WakeLocks

2014-08-18 Thread Kornel Lesiński
WakeLock.request() expecting a string isn't very friendly to feature detection. 

I'd prefer if individual lock types were instances of objects, e.g. 
navigator.*Lock objects could be instances of a variant of the WakeLock 
interface:

navigator.screenLock.request();
navigator.screenLock.isHeld();

navigator.cpuLock.request();
navigator.cpuLock.release();


Alternatively, if the WakeLock was instantiable (to have a standard way for 
independent page components to share locks) then these objects could be 
constructors:

if (navigator.ScreenLock) {
var lock = new navigator.ScreenLock();
…
lock.release();
}

(or `new navigator.wakeLocks.Screen()`, etc.)

Having specific instances for different types of locks could also enable 
elegant extensibility of the API, e.g.

var screenLock = new navigator.ScreenLock();
screenLock.dimScreen(); // completely made-up API

var cpuLock = new navigator.CpuLock();
cpuLock.setThreadPriority(low); // completely made-up API

-- 
regards, Kornel





[whatwg] Preventing wake lock leaks with DOM nodes

2014-08-18 Thread Kornel Lesiński
My biggest concern with the WakeLock API is that it's easy to forget (or fail) 
to release the lock.

It's not a problem with the API per se, but a programming problem in general: 
resource management in non-trivial programs is hard. WakeLocks are especially 
problematic in this regard, as a leaked lock won't cause any immediate 
problems for the developer, so this type of bug can easily go unnoticed.

So I think lifetime of WakeLocks needs to be attached to something visible to 
make failure to release the lock immediately obvious.


In case of screen lock it's especially easy: the whole purpose of this lock is 
to keep something visible on screen, so we can require that something to be 
explicitly connected to the lock.

For example if I were creating a widget that displays a presentation on the 
page, I could attach the screen lock to the canvas or svg element that 
holds the presentation:

new navigator.ScreenLock(myCanvas);

and if the canvas was removed from the document or hidden in any way, then the 
browser could turn the screen off as usual, and I wouldn't have to do anything!

It's nearly impossible to forget to remove a visible DOM element from the 
document — the mistake is likely to be quite obviously visible. If screen lock 
lifetime was dependent on visibility of a DOM element, then it would also be 
very hard to leak the lock without noticing it!

(that's a variant of wake-lock:display CSS proposal, but less explicitly 
dependent on CSS).


With CPU lock it's less clear cut. I think tying it to a notification may be a 
good idea. Alternatively, perhaps the lock itself could be an instance of the 
progress element that author is supposed to insert to the document? ;)

-- 
regards, Kornel





Re: [whatwg] Preventing wake lock leaks with DOM nodes

2014-08-18 Thread Tab Atkins Jr.
On Mon, Aug 18, 2014 at 4:21 PM, Kornel Lesiński kor...@geekhood.net wrote:
 My biggest concern with the WakeLock API is that it's easy to forget (or 
 fail) to release the lock.

 It's not a problem with the API per se, but a programming problem in general: 
 resource management in non-trivial programs is hard. WakeLocks are especially 
 problematic in this regard, as a leaked lock won't cause any immediate 
 problems for the developer, so this type of bug can easily go unnoticed.

 So I think lifetime of WakeLocks needs to be attached to something visible to 
 make failure to release the lock immediately obvious.


 In case of screen lock it's especially easy: the whole purpose of this lock 
 is to keep something visible on screen, so we can require that something to 
 be explicitly connected to the lock.

 For example if I were creating a widget that displays a presentation on the 
 page, I could attach the screen lock to the canvas or svg element that 
 holds the presentation:

 new navigator.ScreenLock(myCanvas);

 and if the canvas was removed from the document or hidden in any way, then 
 the browser could turn the screen off as usual, and I wouldn't have to do 
 anything!

 It's nearly impossible to forget to remove a visible DOM element from the 
 document — the mistake is likely to be quite obviously visible. If screen 
 lock lifetime was dependent on visibility of a DOM element, then it would 
 also be very hard to leak the lock without noticing it!

 (that's a variant of wake-lock:display CSS proposal, but less explicitly 
 dependent on CSS).

Good, but you lose the ability to key the wake-lock to
Selectors-exposed UA state (like video:playing), or directly to your
app's own state (via some class that gets set/removed by your app at
some point in its lifecycle).

But if the CSS part is distasteful, I agree that this works reasonably
well - there is *absolutely no reason* to screenlock based on an
element that's not visible on screen.

 With CPU lock it's less clear cut. I think tying it to a notification may be 
 a good idea. Alternatively, perhaps the lock itself could be an instance of 
 the progress element that author is supposed to insert to the document? ;)

Just pass a promise to the CpuLock constructor, and have it
auto-release when the promise is settled?  You'll generally be
CPU-locking to wait for some operation to finish, and a lot of those
types of operations vend promises these days (or will in the future).

~TJ


Re: [whatwg] Proposal: Wake Lock API

2014-08-18 Thread Marcos Caceres



On Monday, August 18, 2014 at 6:24 PM, Kornel Lesiński wrote:

 I think it'd be unfortunate if this API had just one shared lock per browsing 
 context and required components on the page to coordinate locking, but 
 provided no means to do so.  


The API allows scripts to check which locks are currently held (as either a 
`isHeld()` or `getCurrentLocks()`, for which I just sent a PR for).   
 This will force authors of libraries and components to create dummy iframes 
 just to have their private lock, and libraries/pages without such workaround 
 will be messing up each other's locks.

Currently, iframes are not allowed to have locks - only top-level browsing 
contexts are. This is to avoid things like embedded ads from requesting wake 
locks.   
 Having just a single shared DOM0-style event handler 
 navigator.wakeLock.onlost looks especially jarring. I would expect this to be 
 a proper DOM event that can be used with normal addEventListener (please 
 avoid repeating the mistake of matchMedia).

Oops! I forgot to put that `WakeLock` inherits from `EventTarget`. It's always 
been the intention that you will have .addEventListener! I've sent a PR to fix 
this.  
 To make some coordination possible, the simplest method could be to keep 
 track of number of lock requests and releases, like retain/release in 
 Objective-C:
  
 navigator.wakeLock.request(screen); // locks
 navigator.wakeLock.request(screen); // increases lock count
 navigator.wakeLock.release(screen); // not released yet, but decreases lock 
 count
 navigator.wakeLock.release(screen); // now released for real


In my dummy implementation, I've just been using (the Swift equivalent of):
[UIApplication sharedApplication].idleTimerDisabled = YES;


On MacOS, I thought the right thing to do (tm) according to Apple was [1] 
(see listing 2)? I'm pretty sure that's what we do already in Gecko for videos 
as we've been investigating repurposing the video code for wake locks.  

So, I've not seen the request/release behavior you describe above (at least not 
in the context of wake locks on MacOS/iOS). I guess it's used as an idiom maybe 
in other places?
 However, as you probably know from Objective-C,

Full disclosure, I barely know objective-c ;)
 perfect balancing of retain/release takes care and discipline. Personally, I 
 wouldn't trust all 3rd party libraries/widgets/ads to be careful with this. 
 In fact, I expect some clever libraries to ruin this with:
  
 while(navigator.wakeLock.isHeld(screen)) 
 navigator.wakeLock.release(screen); // just release the damn thing in my 
 leaky code!
That would just halt the browser as the script would never complete: currently 
releasing happens async once the system acknowledges that the release has been 
granted. I'm not sure if there is a use case for that behavior - it's just what 
is currently/sorta roughly proposed in the spec.  
 Therefore, if WakeLock needs to be purely JS API, I strongly prefer having 
 WakeLock available only as an object instance, but without exposing GC 
 behavior—if it's lost, it's like a missing release call.  
  
 If devtools ever get monitoring of unhanded errors in Promise objects, they 
 could also warn against lost WakeLock objects—it's the same type of problem 
 dependent on GC.
  
 I'm assuming that release would work only once on each lock object:
  
 var lock = new WakeLock(screen);
 lock.release();
 lock.release(); // ignored, so it doesn't unlock any other component's lock
  
 This makes coordination easier: each page component can easily create their 
 own lock independently (without needing to create an iframe to get their own 
 lock), and can't release any other component's lock.
Personally, I don't know if I agree that it makes coordination easier. Seems 
that having a centralized place to check what is currently being held makes 
life a lot easier, because it allows scripts to check if they actually need to 
request a lock or not. If you have some objects requesting and others 
releasing, then it makes a huge mess because you need to track down which 
object screwed up the lock. And if GC also then works to release the locks, 
then there is no certainty as to what is actually releasing the lock or when.   


[1] https://developer.apple.com/library/mac/qa/qa1340/_index.html


Re: [whatwg] Preventing wake lock leaks with DOM nodes

2014-08-18 Thread Marcos Caceres


On Monday, August 18, 2014 at 7:21 PM, Kornel Lesiński wrote:

 My biggest concern with the WakeLock API is that it's easy to forget (or 
 fail) to release the lock.
  
 It's not a problem with the API per se, but a programming problem in general: 
 resource management in non-trivial programs is hard. WakeLocks are especially 
 problematic in this regard, as a leaked lock won't cause any immediate 
 problems for the developer, so this type of bug can easily go unnoticed.

Sure. At least on a mobile device, it's easy enough for the user to turn off 
the screen (or just switch apps or browser tabs)... on laptops, it could be a 
problem. However, MacOS (at least) is pretty good at telling users if an app is 
eating too much battery. So this could be also handled at the system level.  
 So I think lifetime of WakeLocks needs to be attached to something visible to 
 make failure to release the lock immediately obvious.
  
  
 In case of screen lock it's especially easy: the whole purpose of this lock 
 is to keep something visible on screen, so we can require that something to 
 be explicitly connected to the lock.

I think that would be nice, actually. It's at least a kinda workaround to 
having to check if something is in the drawable area manually.  

However, it still doesn't really deal with the case where the dev forgets to 
release the lock. What is nicer is combining this with a timeout:

navigator.wakeLock.request(screen, {element: myCanvas, timeout: aFewMinutes});

That would be the most ideal solution for me personally. Just set it, and 
forget it.  
  
 It's nearly impossible to forget to remove a visible DOM element from the 
 document — the mistake is likely to be quite obviously visible. If screen 
 lock lifetime was dependent on visibility of a DOM element, then it would 
 also be very hard to leak the lock without noticing it!
  
 (that's a variant of wake-lock:display CSS proposal, but less explicitly 
 dependent on CSS).

Yes, absolutely. So long as CSS lacks some way to detect if something is 
offscreen, it makes sense. The current ways of checking if an element is within 
the viewport are quite expensive (bunch of jQuery plugins do this - and I think 
they depend on the onscroll event).  
 With CPU lock it's less clear cut. I think tying it to a notification may be 
 a good idea.

Need to think about it.  
 Alternatively, perhaps the lock itself could be an instance of the progress 
 element that author is supposed to insert to the document? ;)

heh:) Yeah, need to think about that.   




Re: [whatwg] Preventing wake lock leaks with DOM nodes

2014-08-18 Thread Domenic Denicola
In general I feel this thread has taken a turn for the complex. Why don't we 
just do what other platforms do, and provide a simple global request/release 
mechanism (or toggleable Boolean property!), which developers can build on top 
of? A lot of the ideas here seem to be trying to create the perfect, 
developer-friendly, foolproof API. Some of them seem quite clever too, tying to 
page visibility and the like. But all of them could be built, as libraries, on 
top of a global request/release. That way users could get reference counting if 
they want that, visibility-based locking if they want that, promise-based 
locking if they want that, timeouts if they want those, or even just not do any 
of those if their use case is simple enough that it doesn't warrant anything 
more complicated than what they are already doing on existing platforms.

We don't need to solve Hard Problems in Programming (TM) before we expose a 
wake lock API. Leave that as a subsequent step, which users can do, while we 
move on to exposing more missing platform capabilities

 On Aug 18, 2014, at 19:52, Marcos Caceres w...@marcosc.com wrote:
 
 
 
 On Monday, August 18, 2014 at 7:21 PM, Kornel Lesiński wrote:
 
 My biggest concern with the WakeLock API is that it's easy to forget (or 
 fail) to release the lock.
 
 It's not a problem with the API per se, but a programming problem in 
 general: resource management in non-trivial programs is hard. WakeLocks are 
 especially problematic in this regard, as a leaked lock won't cause any 
 immediate problems for the developer, so this type of bug can easily go 
 unnoticed.
 
 Sure. At least on a mobile device, it's easy enough for the user to turn off 
 the screen (or just switch apps or browser tabs)... on laptops, it could be a 
 problem. However, MacOS (at least) is pretty good at telling users if an app 
 is eating too much battery. So this could be also handled at the system 
 level.  
  So I think lifetime of WakeLocks needs to be attached to something visible 
 to make failure to we release the lock immediately obvious.
 
 
 In case of screen lock it's especially easy: the whole purpose of this lock 
 is to keep something visible on screen, so we can require that something to 
 be explicitly connected to the lock.
 
 I think that would be nice, actually. It's at least a kinda workaround to 
 having to check if something is in the drawable area manually.  
 
 However, it still doesn't really deal with the case where the dev forgets to 
 release the lock. What is nicer is combining this with a timeout:
 
 navigator.wakeLock.request(screen, {element: myCanvas, timeout: 
 aFewMinutes});
 
 That would be the most ideal solution for me personally. Just set it, and 
 forget it.  
 
 It's nearly impossible to forget to remove a visible DOM element from the 
 document — the mistake is likely to be quite obviously visible. If screen 
 lock lifetime was dependent on visibility of a DOM element, then it would 
 also be very hard to leak the lock without noticing it!
 
 (that's a variant of wake-lock:display CSS proposal, but less explicitly 
 dependent on CSS).
 
 Yes, absolutely. So long as CSS lacks some way to detect if something is 
 offscreen, it makes sense. The current ways of checking if an element is 
 within the viewport are quite expensive (bunch of jQuery plugins do this - 
 and I think they depend on the onscroll event).  
 With CPU lock it's less clear cut. I think tying it to a notification may be 
 a good idea.
 
 Need to think about it.  
 Alternatively, perhaps the lock itself could be an instance of the 
 progress element that author is supposed to insert to the document? ;)
 
 heh:) Yeah, need to think about that.   
 
 


Re: [whatwg] Preventing wake lock leaks with DOM nodes

2014-08-18 Thread Tab Atkins Jr.
On Mon, Aug 18, 2014 at 5:10 PM, Domenic Denicola
dome...@domenicdenicola.com wrote:
 In general I feel this thread has taken a turn for the complex. Why don't we 
 just do what other platforms do, and provide a simple global request/release 
 mechanism (or toggleable Boolean property!), which developers can build on 
 top of? A lot of the ideas here seem to be trying to create the perfect, 
 developer-friendly, foolproof API. Some of them seem quite clever too, tying 
 to page visibility and the like. But all of them could be built, as 
 libraries, on top of a global request/release. That way users could get 
 reference counting if they want that, visibility-based locking if they want 
 that, promise-based locking if they want that, timeouts if they want those, 
 or even just not do any of those if their use case is simple enough that it 
 doesn't warrant anything more complicated than what they are already doing on 
 existing platforms.

 We don't need to solve Hard Problems in Programming (TM) before we expose a 
 wake lock API. Leave that as a subsequent step, which users can do, while we 
 move on to exposing more missing platform capabilities

Nope, doesn't work.  You can't build anything more complex on top of a
simple request/release (or a boolean, which is equivalent), because
any other library can come along and screw with the lock.  So, if we
want this to be extensible, we still need to design it in a localized
way so that you can have multiple independent locks.

If we did that, we *could* then layer a visibility/promise-based thing
on top as an auto-release mechanism for a specific lock.  But you've
still got to solve at least one problem correctly.

~TJ


Re: [whatwg] Preventing wake lock leaks with DOM nodes

2014-08-18 Thread Marcos Caceres



On Monday, August 18, 2014 at 8:10 PM, Domenic Denicola wrote:

 In general I feel this thread has taken a turn for the complex. Why don't we 
 just do what other platforms do, and provide a simple global request/release 
 mechanism (or toggleable Boolean property!), which developers can build on 
 top of? A lot of the ideas here seem to be trying to create the perfect, 
 developer-friendly, foolproof API. Some of them seem quite clever too, tying 
 to page visibility and the like. But all of them could be built, as 
 libraries, on top of a global request/release. That way users could get 
 reference counting if they want that, visibility-based locking if they want 
 that, promise-based locking if they want that, timeouts if they want those, 
 or even just not do any of those if their use case is simple enough that it 
 doesn't warrant anything more complicated than what they are already doing on 
 existing platforms.


 
 
 We don't need to solve Hard Problems in Programming (TM) before we expose a 
 wake lock API. Leave that as a subsequent step, which users can do, while we 
 move on to exposing more missing platform capabilities 




Re: [whatwg] Preventing wake lock leaks with DOM nodes

2014-08-18 Thread Marcos Caceres
(sorry, accidental send before!)


On Monday, August 18, 2014 at 8:10 PM, Domenic Denicola wrote:

 In general I feel this thread has taken a turn for the complex. Why don't we 
 just do what other platforms do, and provide a simple global request/release 
 mechanism (or toggleable Boolean property!), which developers can build on 
 top of? A lot of the ideas here seem to be trying to create the perfect, 
 developer-friendly, foolproof API. Some of them seem quite clever too, tying 
 to page visibility and the like. But all of them could be built, as 
 libraries, on top of a global request/release. That way users could get 
 reference counting if they want that, visibility-based locking if they want 
 that, promise-based locking if they want that, timeouts if they want those, 
 or even just not do any of those if their use case is simple enough that it 
 doesn't warrant anything more complicated than what they are already doing on 
 existing platforms.

The reason I didn't make it a boolean was because of the IPC involved and 
because I wanted to support multiple types of locks without needing to add new 
attributes in the future (and if we need to add the complex stuff later). The 
request()/release() mechanism is well suited for that, IMO. And it's also 
fairly simple, even if it vends a promise.

Admittedly, I could just make it a bunch of boolean attributes. The spec is 
kinda already designed to work that way (what lock is applied is just a flag, 
which is checked synchronously)... it's how `isHeld(lockType)` works.

About tying it to visibility, and time, etc. Those are nice to have, but can 
certainly do without for now. We already dropped the timeout stuff from the 
original spec - but certainly a nice to have in the future. Having said that, 
if we know that this API is going to be used in conjunction with scroll events, 
then we know we are going to have potential battery eating problems (beyond 
just keeping the screen on). 
 
 We don't need to solve Hard Problems in Programming (TM) before we expose a 
 wake lock API. Leave that as a subsequent step, which users can do, while we 
 move on to exposing more missing platform capabilities
 

Yeah, certainly want to keep it as simple as possible. Just want to cover 
keeping the screen on for now. 



Re: [whatwg] Feature-detectable WakeLocks

2014-08-18 Thread Marcos Caceres


On Monday, August 18, 2014 at 6:41 PM, Kornel Lesiński wrote:

 WakeLock.request() expecting a string isn't very friendly to feature 
 detection.

The API tells you if a wake lock type is not supported by either rejecting with 
a TypeError or by a DOMException whose name is NotSupportedError.  
  
  
 I'd prefer if individual lock types were instances of objects, e.g. 
 navigator.*Lock objects could be instances of a variant of the WakeLock 
 interface:
  
 navigator.screenLock.request();
 navigator.screenLock.isHeld();
  
 navigator.cpuLock.request();
 navigator.cpuLock.release();
  
Personally, this doesn't strike me as good API design. It means having a bunch 
of attributes that all use the same class but only differ in name.  
  
  
 Alternatively, if the WakeLock was instantiable (to have a standard way for 
 independent page components to share locks) then these objects could be 
 constructors:
  
 if (navigator.ScreenLock) {
 var lock = new navigator.ScreenLock();
 …
 lock.release();
 }
  
 (or `new navigator.wakeLocks.Screen()`, etc.)
We don't have any APIs like this today on the Web.  It would be weird :)  

It would just be better to have a constructor on the interface: `new 
WakeLock(screen)` or whatever.  

But then we are just back discussing the other email about GC, etc.  
 Having specific instances for different types of locks could also enable 
 elegant extensibility of the API, e.g.
  
 var screenLock = new navigator.ScreenLock();
 screenLock.dimScreen(); // completely made-up API
  
 var cpuLock = new navigator.CpuLock();
 cpuLock.setThreadPriority(low); // completely made-up API
  

IMO, this is not really different from:  

navigator.wakeLock.request(cpu, {
   setThreadPriority: low
});  

If we need to start returning an actual WakeLock objects in the future, we can 
add that.   






Re: [whatwg] Proposal: Wake Lock API

2014-08-18 Thread Jonas Sicking
On Mon, Aug 18, 2014 at 4:37 PM, Marcos Caceres w...@marcosc.com wrote:
 while(navigator.wakeLock.isHeld(screen)) 
 navigator.wakeLock.release(screen); // just release the damn thing in my 
 leaky code!

 That would just halt the browser as the script would never complete: 
 currently releasing happens async once the system acknowledges that the 
 release has been granted. I'm not sure if there is a use case for that 
 behavior - it's just what is currently/sorta roughly proposed in the spec.

I don't think the sync part was the important aspect here. You could
easily rewrite that as an async loop.

The point is that it's easy for developers to end up trying to work
around bugs in their own code by simply doing extra releases. Or end
up with bugs where they accidentally release too many times and so
stomp on other components.

 Therefore, if WakeLock needs to be purely JS API, I strongly prefer having 
 WakeLock available only as an object instance, but without exposing GC 
 behavior--if it's lost, it's like a missing release call.

 If devtools ever get monitoring of unhanded errors in Promise objects, they 
 could also warn against lost WakeLock objects--it's the same type of problem 
 dependent on GC.

 I'm assuming that release would work only once on each lock object:

 var lock = new WakeLock(screen);
 lock.release();
 lock.release(); // ignored, so it doesn't unlock any other component's lock

 This makes coordination easier: each page component can easily create their 
 own lock independently (without needing to create an iframe to get their own 
 lock), and can't release any other component's lock.

 Personally, I don't know if I agree that it makes coordination easier. Seems 
 that having a centralized place to check what is currently being held makes 
 life a lot easier, because it allows scripts to check if they actually need 
 to request a lock or not.

Why does the ability to check if a lock is held make coordination
easier? Checking if they need to request a lock or if someone else is
already doing it seems like a very bad code pattern which actually
makes coordination harder. It makes it very easy to get confused and
try to rely on party X to hold a lock, but then it turns out that in
reality it was Y holding the lock, but Y releases the lock much sooner
and now end up holding a lock for a shorter time than intended.

Am I missing something?

 If you have some objects requesting and others releasing, then it makes a 
 huge mess because you need to track down which object screwed up the lock.

This is not what the proposal is. The proposal is that if a WakeLock
instance x is used to grab a lock, then the lock will be held until
x.release() is called. Any calls on other WakeLock instances will not
cause the lock to be released. Only one all WakeLock instances that
have had request() called on them also gets a call to release(), does
the lock get released.

Losing track of the instance that you called request() on, then that
is equivalent to losing track of how many time you have called
wakeLock.request(x). There is no way to get correctly out of that
situation.

 And if GC also then works to release the locks, then there is no certainty as 
 to what is actually releasing the lock or when.

Can we please stop talking about GC. I don't think anyone has made a
serious proposal where GC releases a lock, or where GC is otherwise
exposed.

/ Jonas


Re: [whatwg] Feature-detectable WakeLocks

2014-08-18 Thread Jonas Sicking
On Mon, Aug 18, 2014 at 5:37 PM, Marcos Caceres w...@marcosc.com wrote:
 On Monday, August 18, 2014 at 6:41 PM, Kornel Lesiński wrote:
 WakeLock.request() expecting a string isn't very friendly to feature 
 detection.

 The API tells you if a wake lock type is not supported by either rejecting 
 with a TypeError or by a DOMException whose name is NotSupportedError.

We've made this mistake before. See

http://robert.ocallahan.org/2012/05/canvas-getcontext-mistake.html

/ Jonas


Re: [whatwg] Preventing wake lock leaks with DOM nodes

2014-08-18 Thread Jonas Sicking
On Mon, Aug 18, 2014 at 5:35 PM, Marcos Caceres w...@marcosc.com wrote:
 The reason I didn't make it a boolean was because of the IPC involved and 
 because I wanted to support multiple types of locks without needing to add 
 new attributes in the future (and if we need to add the complex stuff later).

What's the problem with adding more attributes in the future?

That said, I do think that a timeout for screen locks make sense, so
a boolean wouldn't work. Though not as a timeout for when to release
the lock, but rather as a minimum time I'd like to keep the screen
awake as described at

http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2014-August/297423.html

/ Jonas


Re: [whatwg] Proposal: Wake Lock API

2014-08-18 Thread Kornel Lesiński
 On Monday, August 18, 2014 at 6:24 PM, Kornel Lesiński wrote:
 
 I think it'd be unfortunate if this API had just one shared lock per 
 browsing context and required components on the page to coordinate locking, 
 but provided no means to do so.  
 
 
 The API allows scripts to check which locks are currently held (as either a 
 `isHeld()` or `getCurrentLocks()`, for which I just sent a PR for).   

I don't understand how is that helping.

Let's say I have embedded a Slideshare presentation and a YouTube video on my 
page. I start watching slides, then start playing the video, then finish 
watching slides.

When Slideshare finishes and wants to release the lock, it can't learn via this 
API whether YouTube still wants the lock. When Slideshare started isHeld was 
false, but setting it back to that original state would be incorrect. When 
Slideshare finished isHeld was true, but that doesn't tell anything either, 
since Slideshare itself set it to true.


The only way I see for coordinating lock between independent components on the 
page is not via isHeld(), but by defensively re-setting the lock.

In my previous example both Slideshare and YouTube would have to watch for 
'lost' events (but not via the Netscape-style onlost footgun!) and keep 
re-requesting the lock soon after it's been released, for as long as they need 
it.

IMHO that's really ugly.

If re-requesting is supposed to be the pattern for maintaining locks properly, 
then the whole API could be cut down to just events:

window.addEventListener('beforeScreenLock', function(e) {
if (stillShowingStuff) e.preventDefault();
}, false);

The browser would fire beforeScreenLock event every time the OS is about to 
turn the screen off. To keep the screen on for another while the page just 
needs to prevent the event.


 This will force authors of libraries and components to create dummy iframes 
 just to have their private lock, and libraries/pages without such workaround 
 will be messing up each other's locks.
 
 Currently, iframes are not allowed to have locks - only top-level browsing 
 contexts are. This is to avoid things like embedded ads from requesting wake 
 locks.   

That's a noble goal. However, it may not be effective against ads in practice, 
because majority of ads are embedded using script. OTOH it may prevent use of 
locks in well-behaved embedded documents (slideshows and the like). 

At very least I suggest controlling this like other potentially-annoying 
features via iframe sandbox=allow-locks.

 To make some coordination possible, the simplest method could be to keep 
 track of number of lock requests and releases, like retain/release in 
 Objective-C:
 
 navigator.wakeLock.request(screen); // locks
 navigator.wakeLock.request(screen); // increases lock count
 navigator.wakeLock.release(screen); // not released yet, but decreases 
 lock count
 navigator.wakeLock.release(screen); // now released for real
 
 
 In my dummy implementation, I've just been using (the Swift equivalent of):
 [UIApplication sharedApplication].idleTimerDisabled = YES;

I admire elegance of most of Cocoa's APIs, but I don't think design of that one 
is worth copying. It's global shared mutable state, and there's even negation 
in the property name—it may have been a quick hack that slipped though Cocoa QA 
(the documentation even includes a warning that it should be used with care and 
only when necessary).

Apple has tight control over what apps do, and iOS apps generally don't have as 
many code mashups as web pages, so such primitive fragile API may be less of a 
concern for Apple.


Other APIs you've liked to 
(https://developer.apple.com/library/mac/qa/qa1340/_index.html) are better:

IOPMAssertionCreateWithName/IOPMAssertionRelease creates instances that can be 
individually independently released, so each component can have its own lock 
and they can't release each other's locks accidentally (similar to the `new 
WakeLock()` proposal).

IORegisterForSystemPower uses a callback (similar to the 
`event.preventDefault()` solution I've outlined earlier in this mail).

 This makes coordination easier: each page component can easily create their 
 own lock independently (without needing to create an iframe to get their own 
 lock), and can't release any other component's lock.
 Personally, I don't know if I agree that it makes coordination easier. Seems 
 that having a centralized place to check what is currently being held makes 
 life a lot easier, because it allows scripts to check if they actually need 
 to request a lock or not.

No! That's a footgun! You can't do `if (!isHeld()) request()`, because the 
other component holding the lock may have shorter lifetime than yours, and you 
can't know that.

-- 
regards, Kornel





Re: [whatwg] Feature-detectable WakeLocks

2014-08-18 Thread Kornel Lesiński

 I'd prefer if individual lock types were instances of objects, e.g. 
 navigator.*Lock objects could be instances of a variant of the WakeLock 
 interface:
 
 navigator.screenLock.request();
 navigator.screenLock.isHeld();
 
 navigator.cpuLock.request();
 navigator.cpuLock.release();
 
 Personally, this doesn't strike me as good API design. It means having a 
 bunch of attributes that all use the same class but only differ in name.

Really?

I think clearly separating different classes of locks (with a common base 
class) is much better than conflating them behind a weakly typed string-driven 
API.

It's like:
Element.firstChild.getAttribute(…);
Element.nextSibling.getAttribute(…);
 
instead of:
Element.getAttribute(firstChild, …);
Element.getAttribute(nextSibling, …);

 Alternatively, if the WakeLock was instantiable (to have a standard way for 
 independent page components to share locks) then these objects could be 
 constructors:
 
 if (navigator.ScreenLock) {
 var lock = new navigator.ScreenLock();
 …
 lock.release();
 }
 
 (or `new navigator.wakeLocks.Screen()`, etc.)
 We don't have any APIs like this today on the Web.  It would be weird :)  

Weird is subjective and a vague criticism. Can you elaborate what's wrong 
with that?

 It would just be better to have a constructor on the interface: `new 
 WakeLock(screen)` or whatever.  

I don't see any benefit in obscuring types of the objects. 

String-driven API doesn't allow simple feature detection, and a single type 
that conflates all lock types makes extensibility uglier. You won't be able to 
elegantly add methods that are valid only for some types of locks, e.g. `new 
WakeLock(cpu).dimScreen()` is nonsense, but would valid from perspective of 
WebIDL and JS prototypes.

-- 
regards, Kornel