script/dom/wakelock/
wakelock.rs1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use embedder_traits::{AllowOrDeny, EmbedderMsg};
9use js::context::JSContext;
10use js::realm::CurrentRealm;
11use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
12use servo_constellation_traits::ScriptToConstellationMessage;
13
14use crate::conversions::Convert;
15use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
16 DocumentMethods, DocumentVisibilityState,
17};
18use crate::dom::bindings::codegen::Bindings::WakeLockBinding::{WakeLockMethods, WakeLockType};
19use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
20use crate::dom::bindings::error::Error;
21use crate::dom::bindings::reflector::DomGlobal;
22use crate::dom::bindings::root::DomRoot;
23use crate::dom::globalscope::GlobalScope;
24use crate::dom::promise::{Promise, RootedPromise};
25use crate::dom::wakelock::wakelocksentinel::WakeLockSentinel;
26use crate::routed_promise::{RoutedPromiseListener, callback_promise};
27
28#[dom_struct]
30pub(crate) struct WakeLock {
31 reflector_: Reflector,
32 type_: Cell<WakeLockType>,
33}
34
35impl WakeLock {
36 pub(crate) fn new_inherited() -> Self {
37 Self {
38 reflector_: Reflector::new(),
39 type_: Cell::new(WakeLockType::Screen),
40 }
41 }
42
43 pub(crate) fn new(cx: &mut js::context::JSContext, global: &GlobalScope) -> DomRoot<Self> {
44 reflect_dom_object_with_cx(Box::new(Self::new_inherited()), global, cx)
45 }
46}
47
48impl WakeLockMethods<crate::DomTypeHolder> for WakeLock {
49 fn Request(&self, cx: &mut CurrentRealm, type_: WakeLockType) -> RootedPromise {
51 let global = GlobalScope::from_current_realm(cx);
52 let promise = Promise::new_in_realm_rooted(cx);
53
54 let document = global.as_window().Document();
56
57 if !document.is_fully_active() {
59 promise.reject_error(cx, Error::NotAllowed(Some(
60 "Failed to execute 'request' on 'WakeLock': The requesting page is not fully active."
61 .to_string())));
62 return promise;
63 }
64
65 if document.VisibilityState() == DocumentVisibilityState::Hidden {
67 promise.reject_error(cx, Error::NotAllowed(Some(
68 "Failed to execute 'request' on 'WakeLock': The requesting page is not visible."
69 .to_string()
70 )));
71 return promise;
72 }
73
74 let Some(webview_id) = global.webview_id() else {
77 promise.reject_error(
78 cx,
79 Error::NotAllowed(Some("Unable to obtain WakeLock permission.".to_string())),
80 );
81 return promise;
82 };
83
84 self.type_.set(type_);
85 let task_manager = global.task_manager();
86 let task_source = task_manager.dom_manipulation_task_source();
87 let callback = callback_promise(&promise, self, task_source);
88 global.send_to_embedder(EmbedderMsg::RequestWakeLockPermission(
89 webview_id,
90 callback,
91 self.type_.get().convert(),
92 ));
93
94 promise
95 }
96}
97
98impl RoutedPromiseListener<AllowOrDeny> for WakeLock {
99 fn handle_response(&self, cx: &mut JSContext, response: AllowOrDeny, promise: &RootedPromise) {
101 match response {
102 AllowOrDeny::Deny => {
104 promise.reject_error(
105 cx,
106 Error::NotAllowed(Some(
107 "Failed to execute 'request' on 'WakeLock': Permission denied.".to_string(),
108 )),
109 );
110 },
111 AllowOrDeny::Allow => {
113 let global = self.global();
114 global.as_window().send_to_constellation(
115 ScriptToConstellationMessage::AcquireWakeLock(self.type_.get().convert()),
116 );
117
118 let sentinel = WakeLockSentinel::new(cx, &global, self.type_.get());
119 promise.resolve_native(cx, &sentinel);
120 },
121 }
122 }
123}
124
125impl Convert<embedder_traits::WakeLockType> for WakeLockType {
126 fn convert(self) -> embedder_traits::WakeLockType {
127 match self {
128 WakeLockType::Screen => embedder_traits::WakeLockType::Screen,
129 }
130 }
131}