mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-15 08:30:02 +00:00
refactor canvas draw states to use interior mutability
Makes the code a lot easier to debug, so I could fix some subtle issues.
This commit is contained in:
parent
5ef0d9f159
commit
57783e076c
7 changed files with 106 additions and 119 deletions
|
|
@ -23,9 +23,12 @@ pub enum CanvasState {
|
|||
OffScreenNotDrawable,
|
||||
}
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A rectangular region that defines a top-left zero relative offset for graphical items
|
||||
/// and a bottom-right point that defines a clipping area for things drawn inside.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct Canvas {
|
||||
// unique, random identifier for the Canvas
|
||||
gid: Gid,
|
||||
|
|
@ -36,7 +39,7 @@ pub struct Canvas {
|
|||
// enables scroll/pan of objects within a region
|
||||
pan_offset: Point,
|
||||
// track the drawing state of the canvas
|
||||
state: CanvasState,
|
||||
state: Rc<RefCell<CanvasState>>,
|
||||
// The type of canvas. Useful for debugging, don't remove it.
|
||||
#[allow(dead_code)]
|
||||
canvas_type: crate::api::CanvasType,
|
||||
|
|
@ -57,12 +60,12 @@ impl Canvas {
|
|||
|
||||
Ok(if pan_offset.is_some() {
|
||||
Canvas {
|
||||
clip_rect, trust_level, state: CanvasState::OffScreenDrawable, gid: Gid::new(gid), pan_offset: pan_offset.unwrap(),
|
||||
clip_rect, trust_level, state: Rc::new(RefCell::new(CanvasState::OffScreenDrawable)), gid: Gid::new(gid), pan_offset: pan_offset.unwrap(),
|
||||
canvas_type,
|
||||
}
|
||||
} else {
|
||||
Canvas {
|
||||
clip_rect, trust_level, state: CanvasState::OffScreenDrawable, gid: Gid::new(gid), pan_offset: Point::new(0, 0),
|
||||
clip_rect, trust_level, state: Rc::new(RefCell::new(CanvasState::OffScreenDrawable)), gid: Gid::new(gid), pan_offset: Point::new(0, 0),
|
||||
canvas_type,
|
||||
}
|
||||
})
|
||||
|
|
@ -75,93 +78,96 @@ impl Canvas {
|
|||
}
|
||||
pub fn pan_offset(&self) -> Point { self.pan_offset }
|
||||
pub fn clip_rect(&self) -> Rectangle { self.clip_rect }
|
||||
pub fn set_clip(&mut self, cr: Rectangle) { self.clip_rect = cr; self.state = CanvasState::OffScreenDrawable }
|
||||
pub fn set_clip(&mut self, cr: Rectangle) { self.clip_rect = cr; *self.state.borrow_mut() = CanvasState::OffScreenDrawable }
|
||||
pub fn gid(&self) -> Gid { self.gid }
|
||||
pub fn trust_level(&self) -> u8 { self.trust_level }
|
||||
pub fn set_trust_level(&mut self, level: u8) {self.trust_level = level;}
|
||||
pub fn state(&self) -> CanvasState { self.state }
|
||||
pub fn state(&self) -> CanvasState { *self.state.borrow() }
|
||||
pub fn is_onscreen(&self) -> bool {
|
||||
if self.state == CanvasState::OffScreenDrawable || self.state == CanvasState::OffScreenNotDrawable {
|
||||
if *self.state.borrow() == CanvasState::OffScreenDrawable || *self.state.borrow() == CanvasState::OffScreenNotDrawable {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
pub fn is_drawable(&self) -> bool {
|
||||
if self.state == CanvasState::DrawableDirty || self.state == CanvasState::DrawableDrawn || self.state == CanvasState::OffScreenDrawable {
|
||||
if *self.state.borrow() == CanvasState::DrawableDirty
|
||||
|| *self.state.borrow() == CanvasState::DrawableDrawn
|
||||
|| *self.state.borrow() == CanvasState::OffScreenDrawable {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
pub fn is_drawable_or_offscreen(&self) -> bool {
|
||||
if self.state == CanvasState::DrawableDirty || self.state == CanvasState::DrawableDrawn
|
||||
|| self.state == CanvasState::OffScreenDrawable {
|
||||
if *self.state.borrow() == CanvasState::DrawableDirty
|
||||
|| *self.state.borrow() == CanvasState::DrawableDrawn
|
||||
|| *self.state.borrow() == CanvasState::OffScreenDrawable {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
pub fn set_drawable(&mut self, drawable: bool) {
|
||||
pub fn set_drawable(&self, drawable: bool) {
|
||||
if drawable {
|
||||
if self.state == CanvasState::OffScreenNotDrawable {
|
||||
self.state = CanvasState::OffScreenDrawable
|
||||
} else if self.state != CanvasState::DrawableDrawn {
|
||||
self.state = CanvasState::DrawableDirty;
|
||||
if *self.state.borrow() == CanvasState::OffScreenNotDrawable {
|
||||
*self.state.borrow_mut() = CanvasState::OffScreenDrawable
|
||||
} else if *self.state.borrow() != CanvasState::DrawableDrawn {
|
||||
*self.state.borrow_mut() = CanvasState::DrawableDirty;
|
||||
}
|
||||
} else {
|
||||
if self.state == CanvasState::OffScreenDrawable {
|
||||
self.state = CanvasState::OffScreenNotDrawable
|
||||
} else if self.state != CanvasState::NotDrawableDefaced {
|
||||
self.state = CanvasState::NotDrawableDirty;
|
||||
if *self.state.borrow() == CanvasState::OffScreenDrawable {
|
||||
*self.state.borrow_mut() = CanvasState::OffScreenNotDrawable
|
||||
} else if *self.state.borrow() != CanvasState::NotDrawableDefaced {
|
||||
*self.state.borrow_mut() = CanvasState::NotDrawableDirty;
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn set_onscreen(&mut self, onscreen: bool) {
|
||||
pub fn set_onscreen(&self, onscreen: bool) {
|
||||
if onscreen {
|
||||
if self.state == CanvasState::OffScreenDrawable {
|
||||
self.state = CanvasState::DrawableDirty;
|
||||
} else if self.state == CanvasState::OffScreenNotDrawable {
|
||||
self.state = CanvasState::NotDrawableDirty;
|
||||
if *self.state.borrow() == CanvasState::OffScreenDrawable {
|
||||
*self.state.borrow_mut() = CanvasState::DrawableDirty;
|
||||
} else if *self.state.borrow() == CanvasState::OffScreenNotDrawable {
|
||||
*self.state.borrow_mut() = CanvasState::NotDrawableDirty;
|
||||
}
|
||||
// other states are already onscreen
|
||||
} else {
|
||||
if self.state == CanvasState::DrawableDirty || self.state == CanvasState::DrawableDrawn {
|
||||
self.state = CanvasState::OffScreenDrawable;
|
||||
} else if self.state == CanvasState::NotDrawableDirty || self.state == CanvasState::NotDrawableDefaced {
|
||||
self.state = CanvasState::OffScreenNotDrawable;
|
||||
if *self.state.borrow() == CanvasState::DrawableDirty || *self.state.borrow() == CanvasState::DrawableDrawn {
|
||||
*self.state.borrow_mut() = CanvasState::OffScreenDrawable;
|
||||
} else if *self.state.borrow() == CanvasState::NotDrawableDirty || *self.state.borrow() == CanvasState::NotDrawableDefaced {
|
||||
*self.state.borrow_mut() = CanvasState::OffScreenNotDrawable;
|
||||
}
|
||||
// other states are already offscreen
|
||||
}
|
||||
}
|
||||
// call this after the screen has been flushed
|
||||
pub fn do_flushed(&mut self) -> Result<(), xous::Error> {
|
||||
if self.state == CanvasState::DrawableDirty || self.state == CanvasState::DrawableDrawn {
|
||||
self.state = CanvasState::DrawableDrawn;
|
||||
pub fn do_flushed(&self) -> Result<(), xous::Error> {
|
||||
if *self.state.borrow() == CanvasState::DrawableDirty || *self.state.borrow() == CanvasState::DrawableDrawn {
|
||||
*self.state.borrow_mut() = CanvasState::DrawableDrawn;
|
||||
Ok(())
|
||||
} else if self.state == CanvasState::NotDrawableDefaced
|
||||
|| self.state == CanvasState::OffScreenNotDrawable
|
||||
|| self.state == CanvasState::OffScreenDrawable {
|
||||
} else if *self.state.borrow() == CanvasState::NotDrawableDefaced
|
||||
|| *self.state.borrow() == CanvasState::OffScreenNotDrawable
|
||||
|| *self.state.borrow() == CanvasState::OffScreenDrawable {
|
||||
Ok(())
|
||||
} else {
|
||||
error!("Canvas: flush happened before not drawable regions were defaced, or before initialized! {:?}", self.state);
|
||||
Err(xous::Error::UseBeforeInit)
|
||||
}
|
||||
}
|
||||
pub fn do_drawn(&mut self) -> Result<(), xous::Error> {
|
||||
if self.state == CanvasState::DrawableDirty || self.state == CanvasState::DrawableDrawn {
|
||||
self.state = CanvasState::DrawableDirty;
|
||||
pub fn do_drawn(&self) -> Result<(), xous::Error> {
|
||||
if *self.state.borrow() == CanvasState::DrawableDirty || *self.state.borrow() == CanvasState::DrawableDrawn {
|
||||
*self.state.borrow_mut() = CanvasState::DrawableDirty;
|
||||
Ok(())
|
||||
} else {
|
||||
error!("Canvas: attempt to draw on regions that are not drawable, or not initialized!");
|
||||
Err(xous::Error::AccessDenied)
|
||||
}
|
||||
}
|
||||
pub fn do_defaced(&mut self) -> Result<(), xous::Error> {
|
||||
if self.state == CanvasState::NotDrawableDirty {
|
||||
self.state = CanvasState::NotDrawableDefaced;
|
||||
pub fn do_defaced(&self) -> Result<(), xous::Error> {
|
||||
if *self.state.borrow() == CanvasState::NotDrawableDirty {
|
||||
*self.state.borrow_mut() = CanvasState::NotDrawableDefaced;
|
||||
Ok(())
|
||||
} else if self.state == CanvasState::DrawableDirty || self.state == CanvasState::DrawableDrawn {
|
||||
} else if *self.state.borrow() == CanvasState::DrawableDirty || *self.state.borrow() == CanvasState::DrawableDrawn {
|
||||
info!("Canvas: drawable region was defaced. Allowing it, but this could be a logic bug");
|
||||
Ok(())
|
||||
} else {
|
||||
|
|
@ -170,7 +176,7 @@ impl Canvas {
|
|||
}
|
||||
}
|
||||
pub fn needs_defacing(&self) -> bool {
|
||||
if self.state == CanvasState::NotDrawableDirty {
|
||||
if *self.state.borrow() == CanvasState::NotDrawableDirty {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
|
@ -206,8 +212,6 @@ pub fn deface(gfx: &graphics_server::Gfx, trng: &trng::Trng, canvases: &mut Hash
|
|||
}
|
||||
}
|
||||
if needs_defacing {
|
||||
log::info!("doing a deface computation!");
|
||||
|
||||
let screensize = gfx.screen_size().unwrap();
|
||||
let screen_rect = Rectangle::new(Point::new(0, 0,), screensize);
|
||||
/*
|
||||
|
|
@ -292,50 +296,27 @@ fn remap_rand(end_range: i32, rand: i16, source_range: i32) -> i16 {
|
|||
}
|
||||
|
||||
// we use the "screen" parameter to determine when we can turn off drawing to canvases that are off-screen
|
||||
pub(crate) fn recompute_canvases(canvases: &HashMap<Gid, Canvas>, screen: Rectangle) -> HashMap<Gid, Canvas> {
|
||||
let debug = false; // keep this around, it's really convenient for turning off just this specific subset of debug messages
|
||||
pub(crate) fn recompute_canvases(canvases: &HashMap<Gid, Canvas>) {
|
||||
// first, sort canvases by trust_level. Canvas implements ord/eq based on the trust_level attribute
|
||||
// so jush pushing it into a max binary heap does the trick.
|
||||
if debug { info!("CANVAS: recompute canvas"); }
|
||||
let mut sorted_clipregions: BinaryHeap<Canvas> = BinaryHeap::new();
|
||||
for (&k, &c) in canvases.iter() {
|
||||
if debug { info!(" CANVAS: sorting gid {:?}, canvas {:?}", k, c);}
|
||||
sorted_clipregions.push(c); // always succeeds because incoming type is the same size
|
||||
let mut sorted_clipregions: BinaryHeap<&Canvas> = BinaryHeap::new();
|
||||
for c in canvases.values() {
|
||||
sorted_clipregions.push(c);
|
||||
}
|
||||
|
||||
// now, descend through trust levels and compute intersections, putting the updated drawable states into higher_clipregions
|
||||
let mut higher_clipregions: BinaryHeap<&Canvas> = BinaryHeap::new();
|
||||
let mut current_trust_level: u8 = 255;
|
||||
// sorted_clipregions is a Max heap keyed on trust, so popping the elements off will return them sorted from most to least trusted
|
||||
if debug{info!("CANVAS: received screen argument of {:?}", screen);}
|
||||
if debug{info!("CANVAS: now determining which regions are drawable");}
|
||||
|
||||
let mut sorted_clipregions_vec = sorted_clipregions.into_sorted_vec();
|
||||
for canvas in sorted_clipregions_vec.iter_mut() {
|
||||
if canvas.is_onscreen() {
|
||||
if canvas.trust_level() < current_trust_level {
|
||||
current_trust_level = canvas.trust_level();
|
||||
}
|
||||
for region in higher_clipregions.iter() {
|
||||
if region.is_onscreen()
|
||||
&& (region.trust_level() > current_trust_level) // regions of same trust level have arbitrary draw order
|
||||
&& region.clip_rect().intersects(canvas.clip_rect()) {
|
||||
canvas.set_drawable(false);
|
||||
} else {
|
||||
canvas.set_drawable(true);
|
||||
let mut higher_clipregions = Vec::<&Canvas>::new(); // contains only a subset of on-screen clip rects to consider
|
||||
while let Some(candidate) = sorted_clipregions.pop() {
|
||||
log::trace!("candidate {}", candidate.trust_level());
|
||||
if candidate.is_onscreen() {
|
||||
candidate.set_drawable(true); // i *think* this is ok and doesn't cause thrashing, but verify...
|
||||
for previous in higher_clipregions.iter() {
|
||||
log::trace!("candidate {:?}/{} veruss {:?}/{}", candidate.canvas_type, candidate.trust_level, previous.canvas_type, previous.trust_level);
|
||||
if candidate.clip_rect().intersects(previous.clip_rect()) {
|
||||
log::trace!("candidate is less trusted, setting to not drawable");
|
||||
candidate.set_drawable(false);
|
||||
}
|
||||
}
|
||||
higher_clipregions.push(candidate);
|
||||
}
|
||||
higher_clipregions.push(canvas);
|
||||
}
|
||||
|
||||
// create a new index map out of the recomputed higher_clipregions
|
||||
let mut map: HashMap<Gid, Canvas> = HashMap::new();
|
||||
if debug { info!("CANVAS: reconstituting index map");}
|
||||
for &c in higher_clipregions.iter() {
|
||||
if debug { info!(" CANVAS: inserting gid {:?}, canvas {:?}", c.gid(), c);}
|
||||
map.insert(c.gid(), *c);
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ pub(crate) enum LayoutBehavior {
|
|||
pub(crate) trait LayoutApi {
|
||||
fn clear(&self, gfx: &graphics_server::Gfx, canvases: &mut HashMap<Gid, Canvas>) -> Result<(), xous::Error>;
|
||||
// for Chats, this resizes the height of the input area; for menus, it resizes the overall height
|
||||
fn resize_height(&mut self, gfx: &graphics_server::Gfx, new_height: i16, status_canvas: &Canvas, canvases: &mut HashMap<Gid, Canvas>) -> Result<Point, xous::Error>;
|
||||
fn resize_height(&mut self, gfx: &graphics_server::Gfx, new_height: i16, status_cliprect: &Rectangle, canvases: &mut HashMap<Gid, Canvas>) -> Result<Point, xous::Error>;
|
||||
fn get_gids(&self) -> Vec<GidRecord>;
|
||||
//fn get_input_canvas(&self) -> Option<Gid> { None }
|
||||
//fn get_prediction_canvas(&self) -> Option<Gid> { None }
|
||||
|
|
@ -128,7 +128,7 @@ impl ContextManager {
|
|||
pub(crate) fn register(&mut self,
|
||||
gfx: &graphics_server::Gfx,
|
||||
trng: &trng::Trng,
|
||||
status_canvas: &Canvas,
|
||||
status_cliprect: &Rectangle,
|
||||
canvases: &mut HashMap<Gid, Canvas>,
|
||||
registration: UxRegistration)
|
||||
-> Option<[u32; 4]> {
|
||||
|
|
@ -137,7 +137,7 @@ impl ContextManager {
|
|||
match registration.ux_type {
|
||||
UxType::Chat => {
|
||||
let mut chatlayout = ChatLayout::init(&gfx, &trng,
|
||||
&status_canvas, canvases).expect("couldn't create chat layout");
|
||||
status_cliprect, canvases).expect("couldn't create chat layout");
|
||||
// default to off-screen for all layouts
|
||||
chatlayout.set_visibility_state(false, canvases);
|
||||
let ux_context = UxContext {
|
||||
|
|
@ -212,7 +212,7 @@ impl ContextManager {
|
|||
}
|
||||
UxType::Framebuffer => {
|
||||
let mut raw_fb = Framebuffer::init(&gfx, &trng,
|
||||
&status_canvas, canvases).expect("couldn't create raw fb layout");
|
||||
&status_cliprect, canvases).expect("couldn't create raw fb layout");
|
||||
raw_fb.set_visibility_state(false, canvases);
|
||||
log::debug!("debug raw fb layout: {:?}", raw_fb);
|
||||
let ux_context = UxContext {
|
||||
|
|
@ -272,12 +272,12 @@ impl ContextManager {
|
|||
gfx: &graphics_server::Gfx,
|
||||
gam_token: [u32; 4],
|
||||
new_height: i16,
|
||||
status_canvas: &Canvas,
|
||||
status_cliprect: &Rectangle,
|
||||
canvases: &mut HashMap<Gid, Canvas>) -> Option<Point> {
|
||||
|
||||
for context in self.contexts.values_mut() {
|
||||
if context.gam_token == gam_token {
|
||||
let result = context.layout.resize_height(gfx, new_height, status_canvas, canvases).expect("couldn't adjust height of active Ux context");
|
||||
let result = context.layout.resize_height(gfx, new_height, status_cliprect, canvases).expect("couldn't adjust height of active Ux context");
|
||||
return Some(result)
|
||||
}
|
||||
}
|
||||
|
|
@ -288,11 +288,11 @@ impl ContextManager {
|
|||
gfx: &graphics_server::Gfx,
|
||||
app_token: [u32; 4],
|
||||
new_height: i16,
|
||||
status_canvas: &Canvas,
|
||||
status_cliprect: &Rectangle,
|
||||
canvases: &mut HashMap<Gid, Canvas>) -> Option<Point> {
|
||||
|
||||
if let Some(context) = self.contexts.get_mut(&app_token) {
|
||||
let result = context.layout.resize_height(gfx, new_height, status_canvas, canvases).expect("couldn't adjust height of active Ux context");
|
||||
let result = context.layout.resize_height(gfx, new_height, status_cliprect, canvases).expect("couldn't adjust height of active Ux context");
|
||||
Some(result)
|
||||
} else {
|
||||
None
|
||||
|
|
@ -407,8 +407,7 @@ impl ContextManager {
|
|||
}
|
||||
|
||||
// now recompute the drawability of canvases, based on on-screen visibility and trust state
|
||||
let screensize = gfx.screen_size().expect("Couldn't get screen size");
|
||||
*canvases = recompute_canvases(canvases, Rectangle::new(Point::new(0, 0), screensize));
|
||||
recompute_canvases(canvases);
|
||||
}
|
||||
}
|
||||
log::trace!("foregrounding new context");
|
||||
|
|
@ -437,7 +436,7 @@ impl ContextManager {
|
|||
}
|
||||
// run the defacement before we redraw all the canvases
|
||||
if deface(gfx, &self.trng, canvases) {
|
||||
log::info!("activate triggered a defacement");
|
||||
log::trace!("activate triggered a defacement");
|
||||
}
|
||||
log::trace!("activate redraw");
|
||||
self.redraw().expect("couldn't redraw the currently focused app");
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ pub(crate) struct ChatLayout {
|
|||
impl ChatLayout {
|
||||
// pass in the status canvas so we can size around it, but we can't draw on it
|
||||
pub fn init(gfx: &graphics_server::Gfx, trng: &trng::Trng,
|
||||
status_canvas: &Canvas, canvases: &mut HashMap<Gid, Canvas>) -> Result<ChatLayout, xous::Error> {
|
||||
status_cliprect: &Rectangle, canvases: &mut HashMap<Gid, Canvas>) -> Result<ChatLayout, xous::Error> {
|
||||
let screensize = gfx.screen_size().expect("Couldn't get screen size");
|
||||
// get the height of various text regions to compute the layout
|
||||
let small_height: i16 = gfx.glyph_height_hint(GlyphStyle::Small).expect("couldn't get glyph height") as i16;
|
||||
|
|
@ -40,25 +40,30 @@ impl ChatLayout {
|
|||
MISC_CONTEXT_DEFAULT_TRUST - TRUST_OFFSET,
|
||||
&trng, None, crate::api::CanvasType::ChatPreditive
|
||||
).expect("couldn't create predictive text canvas");
|
||||
let pred_gid = predictive_canvas.gid();
|
||||
let predictive_cr = predictive_canvas.clip_rect();
|
||||
canvases.insert(predictive_canvas.gid(), predictive_canvas);
|
||||
|
||||
let min_input_height = regular_height + margin*2;
|
||||
let input_canvas = Canvas::new(
|
||||
Rectangle::new_v_stack(predictive_canvas.clip_rect(), -min_input_height),
|
||||
Rectangle::new_v_stack(predictive_cr, -min_input_height),
|
||||
MISC_CONTEXT_DEFAULT_TRUST - TRUST_OFFSET, &trng, None, crate::api::CanvasType::ChatInput
|
||||
).expect("couldn't create input text canvas");
|
||||
let input_gid = input_canvas.gid();
|
||||
let input_cr = input_canvas.clip_rect();
|
||||
canvases.insert(input_canvas.gid(), input_canvas);
|
||||
|
||||
let content_canvas = Canvas::new(
|
||||
Rectangle::new_v_span(status_canvas.clip_rect(), input_canvas.clip_rect()),
|
||||
Rectangle::new_v_span(*status_cliprect, input_cr),
|
||||
(MISC_CONTEXT_DEFAULT_TRUST - TRUST_OFFSET) / 2, &trng, None, crate::api::CanvasType::ChatContent
|
||||
).expect("couldn't create content canvas");
|
||||
let content_gid = content_canvas.gid();
|
||||
canvases.insert(content_canvas.gid(), content_canvas);
|
||||
|
||||
Ok(ChatLayout {
|
||||
content: content_canvas.gid(),
|
||||
predictive: predictive_canvas.gid(),
|
||||
input: input_canvas.gid(),
|
||||
content: content_gid,
|
||||
predictive: pred_gid,
|
||||
input: input_gid,
|
||||
min_content_height: 64,
|
||||
min_input_height,
|
||||
_screensize: screensize,
|
||||
|
|
@ -89,7 +94,7 @@ impl LayoutApi for ChatLayout {
|
|||
gfx.draw_rectangle(rect).expect("can't clear canvas");
|
||||
Ok(())
|
||||
}
|
||||
fn resize_height(&mut self, gfx: &graphics_server::Gfx, new_height: i16, status_canvas: &Canvas, canvases: &mut HashMap<Gid, Canvas>) -> Result<Point, xous::Error> {
|
||||
fn resize_height(&mut self, gfx: &graphics_server::Gfx, new_height: i16, status_canvas: &Rectangle, canvases: &mut HashMap<Gid, Canvas>) -> Result<Point, xous::Error> {
|
||||
let input_canvas = canvases.get(&self.input).expect("couldn't find input canvas");
|
||||
let predictive_canvas = canvases.get(&self.predictive).expect("couldn't find predictive canvas");
|
||||
|
||||
|
|
@ -99,7 +104,7 @@ impl LayoutApi for ChatLayout {
|
|||
new_height
|
||||
};
|
||||
let mut new_input_rect = Rectangle::new_v_stack(predictive_canvas.clip_rect(), -height);
|
||||
let mut new_content_rect = Rectangle::new_v_span(status_canvas.clip_rect(), new_input_rect);
|
||||
let mut new_content_rect = Rectangle::new_v_span(*status_canvas, new_input_rect);
|
||||
if (new_content_rect.br.y - new_content_rect.tl.y) > self.min_content_height {
|
||||
{
|
||||
let input_canvas_mut = canvases.get_mut(&self.input).expect("couldn't find input canvas");
|
||||
|
|
|
|||
|
|
@ -15,19 +15,20 @@ impl Framebuffer {
|
|||
pub fn init(
|
||||
gfx: &graphics_server::Gfx,
|
||||
trng: &trng::Trng,
|
||||
status_canvas: &Canvas,
|
||||
status_cliprect: &Rectangle,
|
||||
canvases: &mut HashMap<Gid, Canvas>
|
||||
) -> Result<Framebuffer, xous::Error> {
|
||||
let screensize = gfx.screen_size().expect("Couldn't get screen size");
|
||||
|
||||
let fb_canvas = Canvas::new(
|
||||
Rectangle::new(Point::new(0, status_canvas.clip_rect().br().y + 1), screensize),
|
||||
Rectangle::new(Point::new(0, status_cliprect.br().y + 1), screensize),
|
||||
MISC_CONTEXT_DEFAULT_TRUST - TRUST_OFFSET, &trng, None, crate::api::CanvasType::Framebuffer
|
||||
).expect("couldn't create modal canvas");
|
||||
let fb_gid = fb_canvas.gid();
|
||||
canvases.insert(fb_canvas.gid(), fb_canvas);
|
||||
|
||||
Ok(Framebuffer {
|
||||
gid: fb_canvas.gid(),
|
||||
gid: fb_gid,
|
||||
_screensize: screensize,
|
||||
})
|
||||
}
|
||||
|
|
@ -43,7 +44,7 @@ impl LayoutApi for Framebuffer {
|
|||
rect.style = DrawStyle {fill_color: Some(PixelColor::Light), stroke_color: None, stroke_width: 0,};
|
||||
gfx.draw_rectangle(rect)
|
||||
}
|
||||
fn resize_height(&mut self, _gfx: &graphics_server::Gfx, new_height: i16, _status_canvas: &Canvas, canvases: &mut HashMap<Gid, Canvas>) -> Result<Point, xous::Error> {
|
||||
fn resize_height(&mut self, _gfx: &graphics_server::Gfx, new_height: i16, _status_canvas: &Rectangle, canvases: &mut HashMap<Gid, Canvas>) -> Result<Point, xous::Error> {
|
||||
let fb_canvas = canvases.get_mut(&self.gid).expect("couldn't find my canvas");
|
||||
let orig_rect = fb_canvas.clip_rect();
|
||||
|
||||
|
|
|
|||
|
|
@ -31,10 +31,11 @@ impl MenuLayout {
|
|||
Rectangle::new_coords(MENU_X_PAD, MENU_Y_PAD, screensize.x - MENU_X_PAD, MENU_Y_PAD + height),
|
||||
MISC_CONTEXT_DEFAULT_TRUST - TRUST_OFFSET, &trng, None, crate::api::CanvasType::Menu
|
||||
).expect("couldn't create menu canvas");
|
||||
let gid = menu_canvas.gid();
|
||||
canvases.insert(menu_canvas.gid(), menu_canvas);
|
||||
|
||||
Ok(MenuLayout {
|
||||
menu: menu_canvas.gid(),
|
||||
menu: gid,
|
||||
menu_y_pad: MENU_Y_PAD,
|
||||
_menu_x_pad: MENU_X_PAD,
|
||||
menu_min_height: height,
|
||||
|
|
@ -54,7 +55,7 @@ impl LayoutApi for MenuLayout {
|
|||
rect.style = DrawStyle {fill_color: Some(PixelColor::Light), stroke_color: None, stroke_width: 0,};
|
||||
gfx.draw_rectangle(rect)
|
||||
}
|
||||
fn resize_height(&mut self, _gfx: &graphics_server::Gfx, new_height: i16, _status_canvas: &Canvas, canvases: &mut HashMap<Gid, Canvas>) -> Result<Point, xous::Error> {
|
||||
fn resize_height(&mut self, _gfx: &graphics_server::Gfx, new_height: i16, _status_canvas: &Rectangle, canvases: &mut HashMap<Gid, Canvas>) -> Result<Point, xous::Error> {
|
||||
let menu_canvas = canvases.get_mut(&self.menu).expect("couldn't find menu canvas");
|
||||
let orig_rect = menu_canvas.clip_rect();
|
||||
|
||||
|
|
|
|||
|
|
@ -33,10 +33,11 @@ impl ModalLayout {
|
|||
Rectangle::new_coords(MODAL_X_PAD, MODAL_Y_PAD, screensize.x - MODAL_X_PAD, crate::api::MODAL_Y_MAX),
|
||||
MISC_CONTEXT_DEFAULT_TRUST - TRUST_OFFSET, &trng, None, CanvasType::Modal
|
||||
).expect("couldn't create modal canvas");
|
||||
let modal_gid = modal_canvas.gid();
|
||||
canvases.insert(modal_canvas.gid(), modal_canvas);
|
||||
|
||||
Ok(ModalLayout {
|
||||
modal: modal_canvas.gid(),
|
||||
modal: modal_gid,
|
||||
modal_y_pad: MODAL_Y_PAD,
|
||||
_modal_x_pad: MODAL_X_PAD,
|
||||
modal_min_height: height,
|
||||
|
|
@ -57,7 +58,7 @@ impl LayoutApi for ModalLayout {
|
|||
rect.style = DrawStyle {fill_color: Some(PixelColor::Light), stroke_color: None, stroke_width: 0,};
|
||||
gfx.draw_rectangle(rect)
|
||||
}
|
||||
fn resize_height(&mut self, _gfx: &graphics_server::Gfx, new_height: i16, _status_canvas: &Canvas, canvases: &mut HashMap<Gid, Canvas>) -> Result<Point, xous::Error> {
|
||||
fn resize_height(&mut self, _gfx: &graphics_server::Gfx, new_height: i16, _status_canvas: &Rectangle, canvases: &mut HashMap<Gid, Canvas>) -> Result<Point, xous::Error> {
|
||||
let modal_canvas = canvases.get_mut(&self.modal).expect("couldn't find modal canvas");
|
||||
let orig_rect = modal_canvas.clip_rect();
|
||||
|
||||
|
|
|
|||
|
|
@ -59,16 +59,18 @@ fn xmain() -> ! {
|
|||
|
||||
let screensize = gfx.screen_size().expect("Couldn't get screen size");
|
||||
// the status canvas is special -- there can only be one, and it is ultimately trusted
|
||||
let mut status_canvas = Canvas::new(
|
||||
let status_canvas = Canvas::new(
|
||||
Rectangle::new_coords(
|
||||
0, 0, screensize.x,
|
||||
gfx.glyph_height_hint(GlyphStyle::Cjk).expect("couldn't get glyph height") as i16 * 2),
|
||||
255, &trng, None, crate::api::CanvasType::Status
|
||||
).expect("couldn't create status canvas");
|
||||
let status_cliprect = status_canvas.clip_rect();
|
||||
status_canvas.set_onscreen(true);
|
||||
status_canvas.set_drawable(true);
|
||||
let status_gid = status_canvas.gid().gid();
|
||||
canvases.insert(status_canvas.gid(), status_canvas);
|
||||
canvases = recompute_canvases(&canvases, Rectangle::new(Point::new(0, 0), screensize));
|
||||
recompute_canvases(&canvases);
|
||||
|
||||
// initialize the status bar -- this needs to start late, after the IMEF and most other things are initialized
|
||||
// this used to be domiciled in the GAM, but we split it out because this started to pull too much functionality
|
||||
|
|
@ -76,8 +78,6 @@ fn xmain() -> ! {
|
|||
// we do a hack to try and push a GID to the status bar "securely": we introduce a race condition where we hope
|
||||
// that the GAM is the first thing to talk to the status bar, and the first message is its GID to render on.
|
||||
// generally should be OK, because during boot, all processes are trusted...
|
||||
let status_gid = status_canvas.gid().gid();
|
||||
log::trace!("initializing status bar with gid {:?}", status_gid);
|
||||
let status_conn = xns.request_connection_blocking("_Status bar GID receiver_").expect("couldn't connect to status bar GID receiver");
|
||||
xous::send_message(status_conn,
|
||||
xous::Message::new_scalar(0, // message type doesn't matter because there is only one message it should ever receive
|
||||
|
|
@ -273,14 +273,13 @@ fn xmain() -> ! {
|
|||
log::trace!("SetCanvasBoundsRequest {:?}", cb);
|
||||
|
||||
let granted = if cb.token_type == TokenType::Gam {
|
||||
context_mgr.set_canvas_height(&gfx, cb.token, cb.requested.y, &status_canvas, &mut canvases)
|
||||
context_mgr.set_canvas_height(&gfx, cb.token, cb.requested.y, &status_cliprect, &mut canvases)
|
||||
} else {
|
||||
context_mgr.set_canvas_height_app_token(&gfx, cb.token, cb.requested.y, &status_canvas, &mut canvases)
|
||||
context_mgr.set_canvas_height_app_token(&gfx, cb.token, cb.requested.y, &status_cliprect, &mut canvases)
|
||||
};
|
||||
if granted.is_some() {
|
||||
// recompute the canvas orders based on the new layout
|
||||
let recomp_canvases = recompute_canvases(&canvases, Rectangle::new(Point::new(0, 0), screensize));
|
||||
canvases = recomp_canvases;
|
||||
recompute_canvases(&canvases);
|
||||
// this set of redraw commands is not needed because every context will call redraw after it has finished fitting its bounds
|
||||
// log::info!("canvas bounds redraw");
|
||||
// context_mgr.redraw().expect("can't redraw after new canvas bounds");
|
||||
|
|
@ -416,13 +415,13 @@ fn xmain() -> ! {
|
|||
};
|
||||
// note that we are currently assigning all Ux registrations a trust level consistent with a boot context (ultimately trusted)
|
||||
// this needs to be modified later on once we allow post-boot apps to be created
|
||||
let token = context_mgr.register(&gfx, &trng, &status_canvas, &mut canvases,
|
||||
let token = context_mgr.register(&gfx, &trng, &status_cliprect, &mut canvases,
|
||||
registration);
|
||||
|
||||
// compute what canvases are drawable
|
||||
// this _replaces_ the original canvas structure, to avoid complications of tracking mutable references through compound data structures
|
||||
// this is broken into two steps because of https://github.com/rust-lang/rust/issues/71126
|
||||
canvases = recompute_canvases(&canvases, Rectangle::new(Point::new(0, 0), screensize));
|
||||
recompute_canvases(&canvases);
|
||||
|
||||
buffer.replace(Return::UxToken(token)).unwrap();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue