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:
bunnie 2022-02-05 23:01:16 +08:00
parent 5ef0d9f159
commit 57783e076c
7 changed files with 106 additions and 119 deletions

View file

@ -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
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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