diff options
Diffstat (limited to 'firmware/2lib/2ui.c')
-rw-r--r-- | firmware/2lib/2ui.c | 122 |
1 files changed, 79 insertions, 43 deletions
diff --git a/firmware/2lib/2ui.c b/firmware/2lib/2ui.c index 4d363f68..81243ac2 100644 --- a/firmware/2lib/2ui.c +++ b/firmware/2lib/2ui.c @@ -95,11 +95,11 @@ const struct vb2_menu *get_menu(struct vb2_ui_context *ui) .num_items = 0, .items = NULL, }; - if (ui->state.screen->get_menu) { - menu = ui->state.screen->get_menu(ui); + if (ui->state->screen->get_menu) { + menu = ui->state->screen->get_menu(ui); return menu ? menu : &empty_menu; } else { - return &ui->state.screen->menu; + return &ui->state->screen->menu; } } @@ -125,7 +125,7 @@ vb2_error_t menu_navigation_action(struct vb2_ui_context *ui) case VB_KEY_ENTER: return vb2_ui_menu_select(ui); case VB_KEY_ESC: - return vb2_ui_change_root(ui); + return vb2_ui_screen_back(ui); default: if (key != 0) VB2_DEBUG("Pressed key %#x, trusted? %d\n", @@ -142,13 +142,13 @@ vb2_error_t vb2_ui_menu_prev(struct vb2_ui_context *ui) if (!DETACHABLE && ui->key == VB_BUTTON_VOL_UP_SHORT_PRESS) return VB2_REQUEST_UI_CONTINUE; - item = ui->state.selected_item - 1; + item = ui->state->selected_item - 1; while (item >= 0 && - ((1 << item) & ui->state.disabled_item_mask)) + ((1 << item) & ui->state->disabled_item_mask)) item--; /* Only update if item is valid */ if (item >= 0) - ui->state.selected_item = item; + ui->state->selected_item = item; return VB2_REQUEST_UI_CONTINUE; } @@ -162,13 +162,13 @@ vb2_error_t vb2_ui_menu_next(struct vb2_ui_context *ui) return VB2_REQUEST_UI_CONTINUE; menu = get_menu(ui); - item = ui->state.selected_item + 1; + item = ui->state->selected_item + 1; while (item < menu->num_items && - ((1 << item) & ui->state.disabled_item_mask)) + ((1 << item) & ui->state->disabled_item_mask)) item++; /* Only update if item is valid */ if (item < menu->num_items) - ui->state.selected_item = item; + ui->state->selected_item = item; return VB2_REQUEST_UI_CONTINUE; } @@ -185,7 +185,7 @@ vb2_error_t vb2_ui_menu_select(struct vb2_ui_context *ui) if (menu->num_items == 0) return VB2_REQUEST_UI_CONTINUE; - menu_item = &menu->items[ui->state.selected_item]; + menu_item = &menu->items[ui->state->selected_item]; if (menu_item->action) { VB2_DEBUG("Menu item <%s> run action\n", menu_item->text); @@ -193,7 +193,7 @@ vb2_error_t vb2_ui_menu_select(struct vb2_ui_context *ui) } else if (menu_item->target) { VB2_DEBUG("Menu item <%s> to target screen %#x\n", menu_item->text, menu_item->target); - return vb2_ui_change_screen(ui, menu_item->target); + return vb2_ui_screen_change(ui, menu_item->target); } VB2_DEBUG("Menu item <%s> no action or target screen\n", @@ -204,28 +204,35 @@ vb2_error_t vb2_ui_menu_select(struct vb2_ui_context *ui) /*****************************************************************************/ /* Screen navigation functions */ -vb2_error_t vb2_ui_change_root(struct vb2_ui_context *ui) +vb2_error_t vb2_ui_screen_back(struct vb2_ui_context *ui) { - return vb2_ui_change_screen(ui, ui->root_screen->id); + struct vb2_screen_state *tmp; + + if (ui->state && ui->state->prev) { + tmp = ui->state->prev; + free(ui->state); + ui->state = tmp; + } else { + VB2_DEBUG("ERROR: No previous screen; ignoring\n"); + } + + return VB2_REQUEST_UI_CONTINUE; } static vb2_error_t default_screen_init(struct vb2_ui_context *ui) { const struct vb2_menu *menu = get_menu(ui); - ui->state.selected_item = 0; + ui->state->selected_item = 0; if (menu->num_items > 1 && menu->items[0].is_language_select) - ui->state.selected_item = 1; + ui->state->selected_item = 1; return VB2_REQUEST_UI_CONTINUE; } -vb2_error_t vb2_ui_change_screen(struct vb2_ui_context *ui, enum vb2_screen id) +vb2_error_t vb2_ui_screen_change(struct vb2_ui_context *ui, enum vb2_screen id) { const struct vb2_screen_info *new_screen_info; - - if (ui->state.screen && ui->state.screen->id == id) { - VB2_DEBUG("WARNING: Already on screen %#x; ignoring\n", id); - return VB2_REQUEST_UI_CONTINUE; - } + struct vb2_screen_state *cur_state; + int state_exists = 0; new_screen_info = vb2_get_screen_info(id); if (new_screen_info == NULL) { @@ -233,13 +240,41 @@ vb2_error_t vb2_ui_change_screen(struct vb2_ui_context *ui, enum vb2_screen id) return VB2_REQUEST_UI_CONTINUE; } - memset(&ui->state, 0, sizeof(ui->state)); - ui->state.screen = new_screen_info; + /* Check to see if the screen state already exists in our stack. */ + cur_state = ui->state; + while (cur_state != NULL) { + if (cur_state->screen->id == id) { + state_exists = 1; + break; + } + cur_state = cur_state->prev; + } + + if (state_exists) { + /* Pop until the requested screen is at the top of stack. */ + while (ui->state->screen->id != id) { + cur_state = ui->state; + ui->state = cur_state->prev; + free(cur_state); + } + } else { + /* Allocate the requested screen on top of the stack. */ + cur_state = malloc(sizeof(*ui->state)); + memset(cur_state, 0, sizeof(*ui->state)); + if (cur_state == NULL) { + VB2_DEBUG("WARNING: malloc failed; ignoring\n"); + return VB2_REQUEST_UI_CONTINUE; + } + cur_state->prev = ui->state; + cur_state->screen = new_screen_info; + ui->state = cur_state; + if (ui->state->screen->init) + return ui->state->screen->init(ui); + else + return default_screen_init(ui); + } - if (ui->state.screen->init) - return ui->state.screen->init(ui); - else - return default_screen_init(ui); + return VB2_REQUEST_UI_CONTINUE; } /*****************************************************************************/ @@ -252,16 +287,17 @@ vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id, struct vb2_screen_state prev_state; enum vb2_ui_error prev_error_code; const struct vb2_menu *menu; + const struct vb2_screen_info *root_info; uint32_t key_flags; vb2_error_t rv; memset(&ui, 0, sizeof(ui)); ui.ctx = ctx; - ui.root_screen = vb2_get_screen_info(root_screen_id); - if (ui.root_screen == NULL) + root_info = vb2_get_screen_info(root_screen_id); + if (root_info == NULL) VB2_DIE("Root screen not found.\n"); ui.locale_id = vb2_nv_get(ctx, VB2_NV_LOCALIZATION_INDEX); - rv = vb2_ui_change_screen(&ui, ui.root_screen->id); + rv = vb2_ui_screen_change(&ui, root_screen_id); if (rv != VB2_REQUEST_UI_CONTINUE) return rv; memset(&prev_state, 0, sizeof(prev_state)); @@ -269,19 +305,19 @@ vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id, while (1) { /* Draw if there are state changes. */ - if (memcmp(&prev_state, &ui.state, sizeof(ui.state)) || + if (memcmp(&prev_state, ui.state, sizeof(*ui.state)) || /* we want to redraw/beep on a transition */ prev_error_code != ui.error_code) { menu = get_menu(&ui); VB2_DEBUG("<%s> menu item <%s>\n", - ui.state.screen->name, + ui.state->screen->name, menu->num_items ? - menu->items[ui.state.selected_item].text : + menu->items[ui.state->selected_item].text : "null"); - vb2ex_display_ui(ui.state.screen->id, ui.locale_id, - ui.state.selected_item, - ui.state.disabled_item_mask, + vb2ex_display_ui(ui.state->screen->id, ui.locale_id, + ui.state->selected_item, + ui.state->disabled_item_mask, ui.error_code); /* * Only beep if we're transitioning from no @@ -292,7 +328,7 @@ vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id, vb2ex_beep(250, 400); /* Update prev variables. */ - memcpy(&prev_state, &ui.state, sizeof(ui.state)); + memcpy(&prev_state, ui.state, sizeof(*ui.state)); prev_error_code = ui.error_code; } @@ -313,8 +349,8 @@ vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id, return rv; /* Run screen action. */ - if (ui.state.screen->action) { - rv = ui.state.screen->action(&ui); + if (ui.state->screen->action) { + rv = ui.state->screen->action(&ui); if (rv != VB2_REQUEST_UI_CONTINUE) return rv; } @@ -350,7 +386,7 @@ vb2_error_t developer_action(struct vb2_ui_context *ui) { /* Developer mode keyboard shortcuts */ if (ui->key == VB_KEY_CTRL('S')) - return vb2_ui_change_screen(ui, VB2_SCREEN_DEVELOPER_TO_NORM); + return vb2_ui_screen_change(ui, VB2_SCREEN_DEVELOPER_TO_NORM); if (ui->key == VB_KEY_CTRL('U') || (DETACHABLE && ui->key == VB_BUTTON_VOL_UP_LONG_PRESS)) return vb2_ui_developer_mode_boot_external_action(ui); @@ -402,7 +438,7 @@ vb2_error_t manual_recovery_action(struct vb2_ui_context *ui) VB2_DEBUG("Recovery VbTryLoadKernel %#x --> %#x\n", ui->recovery_rv, rv); ui->recovery_rv = rv; - return vb2_ui_change_screen(ui, + return vb2_ui_screen_change(ui, rv == VB2_ERROR_LK_NO_DISK_FOUND ? VB2_SCREEN_RECOVERY_SELECT : VB2_SCREEN_RECOVERY_INVALID); @@ -411,7 +447,7 @@ vb2_error_t manual_recovery_action(struct vb2_ui_context *ui) /* Manual recovery keyboard shortcuts */ if (ui->key == VB_KEY_CTRL('D') || (DETACHABLE && ui->key == VB_BUTTON_VOL_UP_DOWN_COMBO_PRESS)) - return vb2_ui_change_screen(ui, VB2_SCREEN_RECOVERY_TO_DEV); + return vb2_ui_screen_change(ui, VB2_SCREEN_RECOVERY_TO_DEV); /* TODO(b/144969088): Re-implement as debug info screen. */ if (ui->key == '\t') |