mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
add busy-wait queuing for alerts in case multiple alerts pop up
this case happens when e.g. you're asking for a password but then the connection manager throws an error.
This commit is contained in:
parent
08421999ad
commit
b4a34bd9ec
10 changed files with 105 additions and 84 deletions
|
|
@ -67,6 +67,12 @@ impl Canvas {
|
|||
}
|
||||
})
|
||||
}
|
||||
pub fn intersects(&self, other: &Canvas) -> bool {
|
||||
self.clip_rect.intersects(other.clip_rect())
|
||||
}
|
||||
pub fn less_trusted_than(&self, other: &Canvas) -> bool {
|
||||
self.trust_level() < other.trust_level()
|
||||
}
|
||||
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::OffScreenNotDrawable }
|
||||
|
|
@ -322,36 +328,6 @@ pub fn recompute_canvases(canvases: &HashMap<Gid, Canvas>, screen: Rectangle) ->
|
|||
}
|
||||
higher_clipregions.push(canvas);
|
||||
}
|
||||
/*
|
||||
loop {
|
||||
if let Some(c) = sorted_clipregions.pop() {
|
||||
if debug { info!(" CANVAS: considering {:?}", c);}
|
||||
let mut canvas = c.clone();
|
||||
|
||||
let mut drawable: bool = true;
|
||||
if canvas.trust_level() < trust_level {
|
||||
trust_level = canvas.trust_level();
|
||||
}
|
||||
//if !clip_region.intersects(screen) {
|
||||
// drawable = false;
|
||||
// if debug { info!(" * CANVAS: not drawable, does not intersect");}
|
||||
//} else { // short circuit this computation if it's not drawable because it's off screen
|
||||
// note that this .iter() is *not* sorted by trust level, but all elements will be of greater than or equal to the current trust level
|
||||
for ®ion in higher_clipregions.iter() {
|
||||
// regions of the same trust level can draw over each other. Draw order is arbitrary.
|
||||
if region.clip_rect().intersects(clip_region) && (region.trust_level() < trust_level) {
|
||||
log::info!("{:?} {:?}->false", canvas.canvas_type, canvas.state);
|
||||
drawable = false;
|
||||
if debug { info!(" * CANVAS: not drawable, lower trust intersecting with higher trust region");}
|
||||
}
|
||||
}
|
||||
//}
|
||||
canvas.set_drawable(drawable);
|
||||
higher_clipregions.push(canvas);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
// create a new index map out of the recomputed higher_clipregions
|
||||
let mut map: HashMap<Gid, Canvas> = HashMap::new();
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ impl ContextManager {
|
|||
canvases: &mut HashMap<Gid, Canvas>,
|
||||
token: [u32; 4],
|
||||
clear: bool,
|
||||
) -> ActivationResult {
|
||||
) -> Result<(), xous::Error> {
|
||||
let mut leaving_visibility: bool = false;
|
||||
{
|
||||
// using a temp copy of the old focus, check if we need to update any visibility state
|
||||
|
|
@ -327,28 +327,29 @@ impl ContextManager {
|
|||
if let Some(context) = maybe_new_focus {
|
||||
if let Some(leaving_focused_context) = maybe_leaving_focused_context {
|
||||
if token != leaving_focused_context.app_token {
|
||||
if (context.layout.behavior() == LayoutBehavior::Alert) &&
|
||||
(leaving_focused_context.layout.behavior() == LayoutBehavior::Alert) {
|
||||
// left off: determine if the currently visible context is a password field. if it is, deny the activation.
|
||||
|
||||
context.layout.set_visibility_state(true, canvases);
|
||||
//leaving_focused_context.layout.set_visibility_state(false, canvases);
|
||||
leaving_visibility = false;
|
||||
} else if (context.layout.behavior() == LayoutBehavior::App) &&
|
||||
(leaving_focused_context.layout.behavior() == LayoutBehavior::App) {
|
||||
context.layout.set_visibility_state(true, canvases);
|
||||
//leaving_focused_context.layout.set_visibility_state(false, canvases);
|
||||
leaving_visibility = false;
|
||||
} else if (context.layout.behavior() == LayoutBehavior::Alert) &&
|
||||
(leaving_focused_context.layout.behavior() == LayoutBehavior::App) {
|
||||
context.layout.set_visibility_state(true, canvases);
|
||||
//leaving_focused_context.layout.set_visibility_state(true, canvases);
|
||||
leaving_visibility = true;
|
||||
} else if (context.layout.behavior() == LayoutBehavior::App) &&
|
||||
(leaving_focused_context.layout.behavior() == LayoutBehavior::Alert) {
|
||||
context.layout.set_visibility_state(true, canvases);
|
||||
//leaving_focused_context.layout.set_visibility_state(false, canvases);
|
||||
leaving_visibility = false;
|
||||
if // alert covering an alert
|
||||
(context.layout.behavior() == LayoutBehavior::Alert) &&
|
||||
(leaving_focused_context.layout.behavior() == LayoutBehavior::Alert) {
|
||||
// just disallow alerts covering alerts for now...it's first come, first-serve.
|
||||
log::warn!("Disallowing raise of alert over alert");
|
||||
return Err(xous::Error::ShareViolation)
|
||||
// context.layout.set_visibility_state(true, canvases);
|
||||
// leaving_visibility = false;
|
||||
} else if // app covering an app
|
||||
(context.layout.behavior() == LayoutBehavior::App) &&
|
||||
(leaving_focused_context.layout.behavior() == LayoutBehavior::App) {
|
||||
context.layout.set_visibility_state(true, canvases);
|
||||
leaving_visibility = false;
|
||||
} else if // alert covering an app
|
||||
(context.layout.behavior() == LayoutBehavior::Alert) &&
|
||||
(leaving_focused_context.layout.behavior() == LayoutBehavior::App) {
|
||||
context.layout.set_visibility_state(true, canvases);
|
||||
leaving_visibility = true;
|
||||
} else if // app covering an alert
|
||||
(context.layout.behavior() == LayoutBehavior::App) &&
|
||||
(leaving_focused_context.layout.behavior() == LayoutBehavior::Alert) {
|
||||
context.layout.set_visibility_state(true, canvases);
|
||||
leaving_visibility = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -440,14 +441,16 @@ impl ContextManager {
|
|||
log::trace!("activate redraw");
|
||||
self.redraw().expect("couldn't redraw the currently focused app");
|
||||
}
|
||||
ActivationResult::Success
|
||||
Ok(())
|
||||
}
|
||||
pub(crate) fn revert_focus(&mut self,
|
||||
gfx: &graphics_server::Gfx,
|
||||
canvases: &mut HashMap<Gid, Canvas>,
|
||||
) {
|
||||
) -> Result<(), xous::Error> {
|
||||
if let Some(last) = self.last_context {
|
||||
self.activate(gfx, canvases, last, false);
|
||||
self.activate(gfx, canvases, last, false)
|
||||
} else {
|
||||
Err(xous::Error::UseBeforeInit)
|
||||
}
|
||||
}
|
||||
fn notify_focus_change_to(&self, new_state: gam::FocusState, context: &UxContext) -> Result<(), xous::Error> {
|
||||
|
|
@ -511,7 +514,9 @@ impl ContextManager {
|
|||
if context.layout.behavior() == LayoutBehavior::App {
|
||||
if let Some(menu_token) = self.find_app_token_by_name(MAIN_MENU_NAME) {
|
||||
// set the menu to the active context
|
||||
self.activate(gfx, canvases, menu_token, false);
|
||||
match self.activate(gfx, canvases, menu_token, false) {
|
||||
_ => log::warn!("Couldn't raise menu, user will have to try again."),
|
||||
}
|
||||
// don't pass the initial key hit back to the menu app, just eat it and return
|
||||
return;
|
||||
}
|
||||
|
|
@ -568,7 +573,7 @@ impl ContextManager {
|
|||
name: &str,
|
||||
gfx: &graphics_server::Gfx,
|
||||
canvases: &mut HashMap<Gid, Canvas>,
|
||||
) -> ActivationResult {
|
||||
) -> Result<(), xous::Error> {
|
||||
log::debug!("looking for menu {}", name);
|
||||
if let Some(token) = self.find_app_token_by_name(name) {
|
||||
log::debug!("found menu token: {:?}", token);
|
||||
|
|
@ -579,10 +584,11 @@ impl ContextManager {
|
|||
if context.layout.behavior() == LayoutBehavior::Alert {
|
||||
log::debug!("activating context");
|
||||
return self.activate(gfx, canvases, token, false)
|
||||
} else {
|
||||
return Err(xous::Error::AccessDenied)
|
||||
}
|
||||
}
|
||||
}
|
||||
ActivationResult::Failure
|
||||
Err(xous::Error::ProcessNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ pub(crate) struct ChatLayout {
|
|||
// my internal bookkeeping records. Allow input area to grow into content area
|
||||
min_content_height: i16,
|
||||
min_input_height: i16,
|
||||
screensize: Point,
|
||||
_screensize: Point,
|
||||
_small_height: i16,
|
||||
_regular_height: i16,
|
||||
}
|
||||
|
|
@ -61,7 +61,7 @@ impl ChatLayout {
|
|||
input: input_canvas.gid(),
|
||||
min_content_height: 64,
|
||||
min_input_height,
|
||||
screensize,
|
||||
_screensize: screensize,
|
||||
_small_height: small_height,
|
||||
_regular_height: regular_height,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const TRUST_OFFSET: u8 = 4;
|
|||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) struct Framebuffer {
|
||||
pub gid: Gid,
|
||||
screensize: Point,
|
||||
_screensize: Point,
|
||||
}
|
||||
impl Framebuffer {
|
||||
pub fn init(
|
||||
|
|
@ -28,7 +28,7 @@ impl Framebuffer {
|
|||
|
||||
Ok(Framebuffer {
|
||||
gid: fb_canvas.gid(),
|
||||
screensize,
|
||||
_screensize: screensize,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -335,6 +335,8 @@ impl Gam {
|
|||
}
|
||||
/// requests a context switch to a new app. Doesn't have to be obeyed, depending
|
||||
/// upon the GAM's policy. Only the certain sources can switch apps, hence the token.
|
||||
/// Failure to switch *is silent* because waiting for an activation to go through and
|
||||
/// confirm can cause a deadlock condition.
|
||||
pub fn switch_to_app(&self, app_name: &str, token: [u32; 4]) -> Result<(), xous::Error> {
|
||||
let switchapp = SwitchToApp {
|
||||
token,
|
||||
|
|
@ -343,21 +345,27 @@ impl Gam {
|
|||
let buf = Buffer::into_buf(switchapp).or(Err(xous::Error::InternalError))?;
|
||||
buf.send(self.conn, Opcode::SwitchToApp.to_u32().unwrap()).or(Err(xous::Error::InternalError)).map(|_|())
|
||||
}
|
||||
pub fn raise_menu(&self, menu_name: &str) -> Result<ActivationResult, xous::Error> {
|
||||
pub fn raise_menu(&self, menu_name_str: &str) -> Result<(), xous::Error> {
|
||||
let menu_name = GamActivation {
|
||||
name: String::<128>::from_str(menu_name),
|
||||
name: String::<128>::from_str(menu_name_str),
|
||||
result: None,
|
||||
};
|
||||
let mut buf = Buffer::into_buf(menu_name).or(Err(xous::Error::InternalError))?;
|
||||
buf.lend_mut(self.conn, Opcode::RaiseMenu.to_u32().unwrap()).or(Err(xous::Error::InternalError)).expect("couldn't send RaiseMenu opcode");
|
||||
let result = buf.to_original::<GamActivation, _>().unwrap();
|
||||
if let Some(code) = result.result {
|
||||
Ok(code)
|
||||
match code {
|
||||
ActivationResult::Success => Ok(()),
|
||||
ActivationResult::Failure => {
|
||||
log::warn!("Couldn't raise {}", menu_name_str);
|
||||
Err(xous::Error::ShareViolation)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(xous::Error::InternalError)
|
||||
}
|
||||
}
|
||||
pub fn raise_modal(&self, modal_name: &str) -> Result<ActivationResult, xous::Error> {
|
||||
pub fn raise_modal(&self, modal_name: &str) -> Result<(), xous::Error> {
|
||||
self.raise_menu(modal_name)
|
||||
}
|
||||
/// this is a one-way door, once you've set it, you can't unset it.
|
||||
|
|
|
|||
|
|
@ -468,11 +468,15 @@ fn xmain() -> ! {
|
|||
else { context_mgr.vibe(false) }
|
||||
}),
|
||||
Some(Opcode::RevertFocus) => {
|
||||
context_mgr.revert_focus(&gfx, &mut canvases);
|
||||
xous::return_scalar(msg.sender, 0).expect("couldn't unblock caller");
|
||||
match context_mgr.revert_focus(&gfx, &mut canvases) {
|
||||
Ok(_) => xous::return_scalar(msg.sender, 0).expect("couldn't unblock caller"),
|
||||
_ => xous::return_scalar(msg.sender, 1).expect("couldn't unblock caller"),
|
||||
}
|
||||
},
|
||||
Some(Opcode::RevertFocusNb) => {
|
||||
context_mgr.revert_focus(&gfx, &mut canvases);
|
||||
match context_mgr.revert_focus(&gfx, &mut canvases) {
|
||||
_ => log::warn!("failed to revert focus, silent error!"),
|
||||
}
|
||||
},
|
||||
Some(Opcode::QueryGlyphProps) => msg_blocking_scalar_unpack!(msg, style, _, _, _, {
|
||||
let height = gfx.glyph_height_hint(GlyphStyle::from(style)).expect("couldn't query glyph height from gfx");
|
||||
|
|
@ -489,25 +493,33 @@ fn xmain() -> ! {
|
|||
if let Some(new_app_token) = context_mgr.find_app_token_by_name(switchapp.app_name.as_str().unwrap()) {
|
||||
if let Some(menu_token) = context_mgr.find_app_token_by_name(MAIN_MENU_NAME) {
|
||||
if menu_token == switchapp.token {
|
||||
context_mgr.activate(&gfx, &mut canvases, new_app_token, false);
|
||||
match context_mgr.activate(&gfx, &mut canvases, new_app_token, false) {
|
||||
_ => log::warn!("failed to switch to {}, silent error!", switchapp.app_name.as_str().unwrap()),
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if let Some(modal_token) = context_mgr.find_app_token_by_name(ROOTKEY_MODAL_NAME) {
|
||||
if modal_token == switchapp.token {
|
||||
context_mgr.activate(&gfx, &mut canvases, new_app_token, false);
|
||||
match context_mgr.activate(&gfx, &mut canvases, new_app_token, false) {
|
||||
_ => log::warn!("failed to switch to {}, silent error!", switchapp.app_name.as_str().unwrap()),
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if let Some(token) = context_mgr.find_app_token_by_name(gam::STATUS_BAR_NAME) {
|
||||
if token == switchapp.token {
|
||||
context_mgr.activate(&gfx, &mut canvases, new_app_token, true);
|
||||
match context_mgr.activate(&gfx, &mut canvases, new_app_token, true) {
|
||||
_ => log::warn!("failed to switch to {}, silent error!", switchapp.app_name.as_str().unwrap()),
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// this message came from ourselves
|
||||
if gam_token == switchapp.token {
|
||||
context_mgr.activate(&gfx, &mut canvases, new_app_token, true);
|
||||
match context_mgr.activate(&gfx, &mut canvases, new_app_token, true) {
|
||||
_ => log::warn!("failed to switch to {}, silent error!", switchapp.app_name.as_str().unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -516,7 +528,11 @@ fn xmain() -> ! {
|
|||
let mut activation = buffer.to_original::<GamActivation, _>().unwrap();
|
||||
log::debug!("got request to raise context {}", activation.name);
|
||||
let result = context_mgr.raise_menu(activation.name.as_str().unwrap(), &gfx, &mut canvases);
|
||||
activation.result = Some(result);
|
||||
activation.result = Some(
|
||||
match result {
|
||||
Ok(_) => ActivationResult::Success,
|
||||
Err(_) => ActivationResult::Failure,
|
||||
});
|
||||
buffer.replace(activation).unwrap();
|
||||
},
|
||||
Some(Opcode::Devboot) => msg_scalar_unpack!(msg, ena, _, _, _, {
|
||||
|
|
|
|||
|
|
@ -330,10 +330,25 @@ impl<'a> Modal<'a> {
|
|||
modal
|
||||
}
|
||||
pub fn activate(&self) {
|
||||
let tt = ticktimer_server::Ticktimer::new().unwrap();
|
||||
while self.gam.raise_modal(self.name.to_str()).expect("couldn't activate modal") != ActivationResult::Success {
|
||||
// wait a bit then try again
|
||||
tt.sleep_ms(857).unwrap();
|
||||
const POLL_DELAY_MS: usize = 857;
|
||||
match self.gam.raise_modal(self.name.to_str()) {
|
||||
Ok(_) => (),
|
||||
Err(_) => {
|
||||
std::thread::spawn({
|
||||
let name = self.name.clone();
|
||||
move || {
|
||||
let xns = xous_names::XousNames::new().unwrap();
|
||||
let ticktimer = ticktimer_server::Ticktimer::new().unwrap();
|
||||
ticktimer.sleep_ms(POLL_DELAY_MS).unwrap();
|
||||
let gam = crate::Gam::new(&xns).unwrap();
|
||||
while gam.raise_modal(name.to_str()).is_err() {
|
||||
log::info!("Couldn't raise {}; retrying...", name);
|
||||
ticktimer.sleep_ms(POLL_DELAY_MS).unwrap();
|
||||
}
|
||||
log::info!("Success! exiting polling thread.");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,4 +24,4 @@ utralib = { path = "../../utralib"}
|
|||
|
||||
[features]
|
||||
ux_tests = []
|
||||
default = ["ux_tests"]
|
||||
default = []
|
||||
|
|
|
|||
|
|
@ -467,9 +467,9 @@ fn xmain() -> ! {
|
|||
}
|
||||
});
|
||||
// try to mount the PDDB automatically before starting the server
|
||||
//#[cfg(not(any(windows, unix)))] // avoid errors in hosted mode
|
||||
#[cfg(not(any(windows, unix)))] // avoid errors in hosted mode
|
||||
let tt = ticktimer_server::Ticktimer::new().unwrap();
|
||||
//#[cfg(not(any(windows, unix)))] // skip this step if running in hosted mode, for now...
|
||||
#[cfg(not(any(windows, unix)))] // skip this step if running in hosted mode, for now...
|
||||
if pddb_os.rootkeys_initialized() {
|
||||
tt.sleep_ms(1000).unwrap(); // wait 1 second after boot before attempting to mount, to let the boot screen finish redrawing (cometic issue).
|
||||
match ensure_password(&modals, &mut pddb_os) {
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ mod implementation {
|
|||
false
|
||||
}
|
||||
pub fn is_pcache_boot_password_valid(&self) -> bool {
|
||||
false
|
||||
true
|
||||
}
|
||||
pub fn fpga_key_source(&self) -> FpgaKeySource {
|
||||
FpgaKeySource::Efuse
|
||||
|
|
|
|||
Loading…
Reference in a new issue