Add managed Window resource and native shell operations
Verify Tessera GUI / verify (push) Failing after 7m25s
Verify Tessera GUI / verify (push) Failing after 7m25s
This commit is contained in:
+62
-20
@@ -441,17 +441,31 @@ impl Worker {
|
||||
return;
|
||||
}
|
||||
let id = runtime.id;
|
||||
let result = catch_unwind(AssertUnwindSafe(|| runtime.resize(viewport)));
|
||||
let result = catch_unwind(AssertUnwindSafe(|| -> Result<_> {
|
||||
let document = runtime.resize(viewport)?;
|
||||
Ok((document, runtime.take_window_commands()?))
|
||||
}));
|
||||
let mut current = match namespace.write() {
|
||||
Ok(current) => current,
|
||||
Err(_) => return,
|
||||
};
|
||||
if current.submission != epoch || current.document.frame.session != id {
|
||||
if current.submission != epoch || current.runtime_session != id {
|
||||
return;
|
||||
}
|
||||
let document = match result {
|
||||
Ok(Ok(Some(document))) => document,
|
||||
Ok(Ok(None)) => return,
|
||||
let (document, commands) = match result {
|
||||
Ok(Ok((document, commands))) => {
|
||||
if let Some(document) = document {
|
||||
(document, Some(commands))
|
||||
} else {
|
||||
let projected = !commands.is_empty();
|
||||
current.publish_window_commands(id, commands);
|
||||
drop(current);
|
||||
if projected {
|
||||
notify();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
failure => {
|
||||
let mut document = current.document.clone();
|
||||
document.frame.fault = Some(match failure {
|
||||
@@ -461,13 +475,18 @@ impl Worker {
|
||||
.collect(),
|
||||
_ => {
|
||||
self.repl = None;
|
||||
current.runtime_session = 0;
|
||||
current.window_commands.clear();
|
||||
"Runtime discarded after an internal viewport failure".into()
|
||||
}
|
||||
});
|
||||
document
|
||||
(document, None)
|
||||
}
|
||||
};
|
||||
let changed = matches!(current.commit(epoch, document), Ok(Some(_)));
|
||||
if changed && let Some(commands) = commands {
|
||||
current.publish_window_commands(id, commands);
|
||||
}
|
||||
drop(current);
|
||||
if changed {
|
||||
notify();
|
||||
@@ -499,6 +518,8 @@ impl Worker {
|
||||
if let Ok(mut current) = namespace.write() {
|
||||
current.document.frame.session = 0;
|
||||
current.document.frame.focus = None;
|
||||
current.runtime_session = 0;
|
||||
current.window_commands.clear();
|
||||
}
|
||||
notify();
|
||||
return json(
|
||||
@@ -547,21 +568,32 @@ impl Worker {
|
||||
.as_ref()
|
||||
.is_none_or(|(current, _)| *current != epoch)
|
||||
{
|
||||
self.next_session += 1;
|
||||
self.next_session = match self.next_session.checked_add(1) {
|
||||
Some(id) => id,
|
||||
None => return error_response(StatusCode(500), "session identities exhausted"),
|
||||
};
|
||||
let viewport = namespace.read().ok().and_then(|current| current.viewport);
|
||||
match endor_host::ReplSession::new_with_viewport(self.next_session, viewport) {
|
||||
Ok(session) => self.repl = Some((epoch, session)),
|
||||
Ok(session) => {
|
||||
if let Ok(mut current) = namespace.write()
|
||||
&& current.submission == epoch
|
||||
{
|
||||
current.publish_window_commands(session.id, Vec::new());
|
||||
}
|
||||
self.repl = Some((epoch, session));
|
||||
}
|
||||
Err(error) => return error_response(StatusCode(500), error.to_string()),
|
||||
}
|
||||
}
|
||||
let session = &mut self.repl.as_mut().expect("initialized REPL").1;
|
||||
let id = session.id;
|
||||
let result = catch_unwind(AssertUnwindSafe(|| {
|
||||
if let Some(event) = &event {
|
||||
session.dispatch(event)
|
||||
let result = catch_unwind(AssertUnwindSafe(|| -> Result<_> {
|
||||
let result = if let Some(event) = &event {
|
||||
session.dispatch(event)?
|
||||
} else {
|
||||
session.execute(&job.source, &job.namespace)
|
||||
}
|
||||
session.execute(&job.source, &job.namespace)?
|
||||
};
|
||||
Ok((result, session.take_window_commands()?))
|
||||
}));
|
||||
let faulted = session.is_faulted();
|
||||
let Ok(mut current) = namespace.write() else {
|
||||
@@ -573,7 +605,8 @@ impl Worker {
|
||||
return superseded(job.submission);
|
||||
}
|
||||
match result {
|
||||
Ok(Ok(result)) => {
|
||||
Ok(Ok((result, commands))) => {
|
||||
let projected = !commands.is_empty();
|
||||
let rendered = result.document.is_some();
|
||||
if let Some(document) = result.document {
|
||||
match current.commit(epoch, document) {
|
||||
@@ -582,9 +615,10 @@ impl Worker {
|
||||
Err(error) => return error_response(StatusCode(500), error.to_string()),
|
||||
}
|
||||
}
|
||||
current.publish_window_commands(id, commands);
|
||||
let revision = current.revision;
|
||||
drop(current);
|
||||
if rendered {
|
||||
if rendered || projected {
|
||||
notify();
|
||||
}
|
||||
json(
|
||||
@@ -606,6 +640,8 @@ impl Worker {
|
||||
let mut document = current.document.clone();
|
||||
document.frame.fault =
|
||||
Some("Runtime discarded after an internal execution failure".into());
|
||||
current.runtime_session = 0;
|
||||
current.window_commands.clear();
|
||||
let _ = current.commit(epoch, document);
|
||||
drop(current);
|
||||
self.repl = None;
|
||||
@@ -640,17 +676,19 @@ impl Worker {
|
||||
.read()
|
||||
.map_err(|_| anyhow::anyhow!("namespace lock poisoned"))?
|
||||
.viewport;
|
||||
if viewport.is_some() {
|
||||
let (runtime, document) = if viewport.is_some() {
|
||||
endor_host::ReplSession::load_with_viewport(
|
||||
&job.source,
|
||||
&job.namespace,
|
||||
job.submission,
|
||||
id,
|
||||
viewport,
|
||||
)
|
||||
)?
|
||||
} else {
|
||||
endor_host::ReplSession::load(&job.source, &job.namespace, job.submission, id)
|
||||
}
|
||||
endor_host::ReplSession::load(&job.source, &job.namespace, job.submission, id)?
|
||||
};
|
||||
let commands = runtime.take_window_commands()?;
|
||||
Ok::<_, anyhow::Error>((runtime, document, commands))
|
||||
}));
|
||||
let Ok(mut current) = namespace.write() else {
|
||||
return error_response(StatusCode(500), "namespace lock poisoned");
|
||||
@@ -659,8 +697,10 @@ impl Worker {
|
||||
return superseded(job.submission);
|
||||
}
|
||||
match result {
|
||||
Ok(Ok((runtime, document))) => match current.commit(job.submission, document) {
|
||||
Ok(Ok((runtime, document, commands))) => match current.commit(job.submission, document)
|
||||
{
|
||||
Ok(Some(revision)) => {
|
||||
current.publish_window_commands(id, commands);
|
||||
self.repl = Some((job.submission, runtime));
|
||||
drop(current);
|
||||
notify();
|
||||
@@ -848,6 +888,8 @@ declarations, explicit first `self` parameters, positional field construction an
|
||||
member assignment. Inherited methods bind the actual receiver; overridden methods
|
||||
are dynamically selected through self. Concrete native visual subclasses reuse real native allocators; abstract bases remain unconstructible. Traits and annotation checking remain pending. Native Block/Page methods use the same type method tables and binding path.
|
||||
|
||||
Window is a host-provided managed resource: ui.window(), page.window(), page.open(window), window.pages()/id()/viewport(), resize(width,height), setTitle(text) and focus(). Requests project to the actual main native window only after successful input/candidate completion and carry the current runtime session. Resize is asynchronous and the reported viewport is authoritative; this host accepts 1..4096 logical dimensions with a native 720x480 minimum. Failed input/candidates discard pending requests and read-only rendering rejects window effects. Additional windows, Window() construction, tab UI and detach/move remain pending.
|
||||
|
||||
Source measure and arrange overrides execute bottom-up and top-down in one read-only VM layout call. Structural Mount links exist before first measurement; bounds queries reject premature geometry. Native base layout uses current occurrence child measurements, and Arrangement must assign every stable child slot exactly once. Layout dependencies changed by lifecycle hooks trigger another pass before publication. Page constraints now use the current logical window viewport. Column/Button propagate cross-axis width and Row propagates cross-axis height; desired sizes are clamped. ui.viewport() provides a managed snapshot whose private input participates in rendering dependencies. Native resize updates are coalesced on the same worker without adding source inputs. Source measurement caches use Mount/method/children/constraints and actual subcall object reads, including returned-result decoding; Mount-reading methods conservatively bypass caching. ui.stats() exposes sourceMeasureHits/sourceMeasureMisses outside read-only rendering. General constraint negotiation, wrapping and scrolling remain pending.
|
||||
|
||||
Source paint overrides execute in the actual frame pipeline under a read-only heap policy. Source hitTest overrides similarly refine native pointer targets in VM paint order; Point.inside(bounds) and Point.inCircle(cx, cy, radius) provide primitive shape queries. Managed DisplayList/ObjectList/PaintCommand and Constraints/Bounds/Point results are ordinary runtime objects.
|
||||
|
||||
Reference in New Issue
Block a user