deprecate request_focus api and make initial focus setting within the GAM

request_focus is "dangerous" because any random server could
request a UX context to pop up. There is a checked version
that requires a GAM token that should be used, but, this leaves
the question of how does the initial app that's supposed to be
focused gets set.

A small mod to the UxRegistration call is made to check for
the name of the default focus app, and when it is seen, a thread
is fired off to request focus for that app. That allows us
to deprecate this otherwise dangerous call.
This commit is contained in:
bunnie 2022-01-25 00:55:14 +08:00
parent 583c2e172b
commit 02b2e4a6e7
5 changed files with 54 additions and 19 deletions

View file

@ -161,9 +161,6 @@ pub(crate) enum Opcode {
RevertFocus,
RevertFocusNb, // non-blocking version
/// request an app to take the focus
RequestFocus,
/// pass-through to get glyph heights to assist with layout planning, without having to create a gfx connection
QueryGlyphProps,

View file

@ -408,7 +408,6 @@ impl ContextManager {
// now re-check-out the new context and finalize things
let maybe_new_focus = self.get_context_by_token(token);
if let Some(context) = maybe_new_focus {
self.notify_focus_change_to(gam::FocusState::Foreground, context).unwrap();
if clear {
context.layout.clear(gfx, canvases).expect("can't clear on context activation");
}
@ -422,6 +421,7 @@ impl ContextManager {
// revert the keyboard vibe state
self.kbd.set_vibe(context.vibe).expect("couldn't restore keyboard vibe");
self.notify_focus_change_to(gam::FocusState::Foreground, context).unwrap();
log::debug!("raised focus to: {:?}", context);
let last_token = context.app_token;
self.last_context = self.focused_context;

View file

@ -315,12 +315,6 @@ impl Gam {
0, 0, 0, 0,)
).map(|_| ())
}
pub fn request_focus(&self, token: [u32; 4]) -> Result<(), xous::Error> {
send_message(self.conn,
Message::new_blocking_scalar(Opcode::RequestFocus.to_usize().unwrap(),
token[0] as usize, token[1] as usize, token[2] as usize, token[3] as usize,)
).map(|_| ())
}
pub fn glyph_height_hint(&self, glyph: GlyphStyle) -> Result<usize, xous::Error> {
let response = send_message(self.conn,

View file

@ -21,7 +21,10 @@ use gam::{MAIN_MENU_NAME, ROOTKEY_MODAL_NAME};
use log::info;
use std::collections::HashMap;
use num_traits::*;
use core::{sync::atomic::{AtomicU32, Ordering}};
use core::sync::atomic::{AtomicU32, Ordering};
/// This sets the initial app focus on boot
const INITIAL_APP_FOCUS: &'static str = gam::APP_NAME_SHELLCHAT;
static CB_TO_MAIN_CONN: AtomicU32 = AtomicU32::new(0);
fn imef_cb(s: String::<4000>) {
@ -35,7 +38,7 @@ fn imef_cb(s: String::<4000>) {
#[xous::xous_main]
fn xmain() -> ! {
log_server::init_wait().unwrap();
log::set_max_level(log::LevelFilter::Info);
log::set_max_level(log::LevelFilter::Trace);
info!("my PID is {}", xous::process::id());
let xns = xous_names::XousNames::new().unwrap();
@ -78,6 +81,9 @@ fn xmain() -> ! {
)
).expect("couldn't set status GID");
// a random number we can use to identify ourselves between API calls
let gam_token = [trng.get_u32().unwrap(), trng.get_u32().unwrap(), trng.get_u32().unwrap(), trng.get_u32().unwrap()];
let mut powerdown_requested = false;
let mut last_time: u64 = ticktimer.elapsed_ms();
let mut did_test = false; // allow one go at the test pattern
@ -396,6 +402,11 @@ fn xmain() -> ! {
let mut buffer = unsafe{ Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) };
let registration = buffer.to_original::<UxRegistration, _>().unwrap();
let init_focus_found = if registration.app_name.as_str().unwrap_or("UTF-8 error") == INITIAL_APP_FOCUS {
true
} else {
false
};
// 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,
@ -407,6 +418,22 @@ fn xmain() -> ! {
canvases = recompute_canvases(&canvases, Rectangle::new(Point::new(0, 0), screensize));
buffer.replace(Return::UxToken(token)).unwrap();
// fire off a thread that deals with activating the initial boot context. You need this because this call has to complete before the context can respond to activation events.
if token.is_some() & init_focus_found {
std::thread::spawn({
let gam_token = gam_token.clone();
let conn = CB_TO_MAIN_CONN.load(Ordering::SeqCst);
move || {
let switchapp = SwitchToApp {
token: gam_token,
app_name: String::<128>::from_str(INITIAL_APP_FOCUS),
};
let buf = Buffer::into_buf(switchapp).or(Err(xous::Error::InternalError))?;
buf.send(conn, Opcode::SwitchToApp.to_u32().unwrap()).or(Err(xous::Error::InternalError)).map(|_|())
}
});
}
},
Some(Opcode::SetAudioOpcode) => {
let buffer = unsafe{ Buffer::from_memory_message(msg.body.memory_message().unwrap()) };
@ -457,6 +484,7 @@ fn xmain() -> ! {
Some(Opcode::RevertFocusNb) => {
context_mgr.revert_focus(&gfx, &mut canvases);
},
/*
Some(Opcode::RequestFocus) => msg_blocking_scalar_unpack!(msg, t0, t1, t2, t3, {
// TODO: add some limitations around who can request focus
// for now, it's the boot set so we just trust the requestor
@ -464,7 +492,7 @@ fn xmain() -> ! {
// this is a blocking scalar, so return /something/ so we know to move on
xous::return_scalar(msg.sender, 1).expect("couldn't confirm focus activation");
}),
}), */
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");
xous::return_scalar(msg.sender, height).expect("could not return QueryGlyphProps request");
@ -496,6 +524,10 @@ fn xmain() -> ! {
continue;
}
}
// this message came from ourselves
if gam_token == switchapp.token {
context_mgr.activate(&gfx, &mut canvases, new_app_token, true);
}
}
},
Some(Opcode::RaiseMenu) => {

View file

@ -94,12 +94,9 @@ impl Repl{
gotinput_id: Some(ShellOpcode::Line.to_u32().unwrap()),
audioframe_id: None,
rawkeys_id: None,
focuschange_id: None, // shellchat will keep running in the background even if it has lost focus
focuschange_id: Some(ShellOpcode::ChangeFocus.to_u32().unwrap()),
}).expect("couldn't register Ux context for shellchat");
// we should be the first app running, so get the focus
gam.request_focus(token.unwrap()).expect("couldn't take focus");
let content = gam.request_content_canvas(token.unwrap()).expect("couldn't get content canvas");
log::trace!("content canvas {:?}", content);
let screensize = gam.get_canvas_bounds(content).expect("couldn't get dimensions of content canvas");
@ -278,6 +275,8 @@ enum ShellOpcode {
Line = 0, // make sure we occupy opcodes with discriminants < 1000, as the rest are used for callbacks
/// redraw our UI
Redraw,
/// change focus
ChangeFocus,
/// exit the application
Quit,
}
@ -301,6 +300,7 @@ fn xmain() -> ! {
let mut update_repl = false;
let mut was_callback = false;
let mut allow_redraw = true;
log::trace!("starting main loop");
loop {
let msg = xous::receive_message(shch_sid).unwrap();
@ -315,9 +315,21 @@ fn xmain() -> ! {
was_callback = false;
}
Some(ShellOpcode::Redraw) => {
log::trace!("got Redraw");
repl.redraw().expect("REPL couldn't redraw");
if allow_redraw {
repl.redraw().expect("REPL couldn't redraw");
}
}
Some(ShellOpcode::ChangeFocus) => xous::msg_scalar_unpack!(msg, new_state_code, _, _, _, {
let new_state = gam::FocusState::convert_focus_change(new_state_code);
match new_state {
gam::FocusState::Background => {
allow_redraw = false;
}
gam::FocusState::Foreground => {
allow_redraw = true;
}
}
}),
Some(ShellOpcode::Quit) => {
log::error!("got Quit");
break;