From patchwork Wed Feb 15 04:35:40 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Mendoza-Jonas X-Patchwork-Id: 728050 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3vNRLs6cyCz9s1h for ; Wed, 15 Feb 2017 15:36:21 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=mendozajonas.com header.i=@mendozajonas.com header.b="gwWwVBVu"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3vNRLs5ZgqzDqGn for ; Wed, 15 Feb 2017 15:36:21 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=mendozajonas.com header.i=@mendozajonas.com header.b="gwWwVBVu"; dkim-atps=neutral X-Original-To: petitboot@lists.ozlabs.org Delivered-To: petitboot@lists.ozlabs.org Received: from mendozajonas.com (mendozajonas.com [188.166.185.233]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3vNRLM6GB4zDq60 for ; Wed, 15 Feb 2017 15:35:55 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=mendozajonas.com header.i=@mendozajonas.com header.b="gwWwVBVu"; dkim-atps=neutral Received: from skellige.ozlabs.ibm.com (unknown [122.99.82.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client did not present a certificate) (Authenticated sender: sam@mendozajonas.com) by mendozajonas.com (Postfix) with ESMTPSA id B7AD0143FE8; Wed, 15 Feb 2017 12:35:52 +0800 (SGT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mendozajonas.com; s=mail; t=1487133353; bh=5BjU13+eTJpGZiZ+8QN2lp8H32PAomr8ARbKATAvh/o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gwWwVBVusBhHk6K0d62BwJ3c6uKLM0llqaT9hv3KLeq1TgD/zI9mKZEy4SthH7D2J PHvf5chWU0CST2e+lqcP7iRfje9ry8U5XB+bZcAvNj08jOUm+RwMp6v/3FbzKdPfbN 9xD6wnNwmeF7Eh9kBfhRIIsThg5n3FW3XNL02TwY= From: Samuel Mendoza-Jonas To: petitboot@lists.ozlabs.org Subject: [RFC PATCH 8/9] ui/ncurses: Allow giving certain processes control of the display Date: Wed, 15 Feb 2017 15:35:40 +1100 Message-Id: <20170215043541.10204-8-sam@mendozajonas.com> X-Mailer: git-send-email 2.11.1 In-Reply-To: <20170215043541.10204-1-sam@mendozajonas.com> References: <20170215043541.10204-1-sam@mendozajonas.com> X-BeenThere: petitboot@lists.ozlabs.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Petitboot bootloader development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Samuel Mendoza-Jonas MIME-Version: 1.0 Errors-To: petitboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Petitboot" Add cui_run_external() which temporarily suspends ncurses before calling a supplied process. This allows the user to interact directly with the process, and then return to same place in the Petitboot UI. While in this 'suspended' mode petitboot-nc must ensure it does not attempt to draw to the screen. A small helper, nc_scr_active() is added to make this easier to detect. Signed-off-by: Samuel Mendoza-Jonas --- ui/ncurses/nc-boot-editor.c | 3 +- ui/ncurses/nc-config.c | 3 +- ui/ncurses/nc-cui.c | 98 +++++++++++++++++++++++++++++++++++++++++---- ui/ncurses/nc-cui.h | 4 ++ ui/ncurses/nc-scr.c | 3 ++ ui/ncurses/nc-sysinfo.c | 4 +- 6 files changed, 104 insertions(+), 11 deletions(-) diff --git a/ui/ncurses/nc-boot-editor.c b/ui/ncurses/nc-boot-editor.c index 7fa1a42..45c8f94 100644 --- a/ui/ncurses/nc-boot-editor.c +++ b/ui/ncurses/nc-boot-editor.c @@ -553,7 +553,8 @@ void boot_editor_update(struct boot_editor *boot_editor, { int height; - if (boot_editor->cui->current != boot_editor_scr(boot_editor)) { + if (boot_editor->cui->current != boot_editor_scr(boot_editor) || + boot_editor->cui->suspended) { boot_editor->need_update = true; return; } diff --git a/ui/ncurses/nc-config.c b/ui/ncurses/nc-config.c index 8349629..a80c729 100644 --- a/ui/ncurses/nc-config.c +++ b/ui/ncurses/nc-config.c @@ -1182,7 +1182,8 @@ void config_screen_update(struct config_screen *screen, const struct config *config, const struct system_info *sysinfo) { - if (screen->cui->current != config_screen_scr(screen)) { + if (screen->cui->current != config_screen_scr(screen) || + screen->cui->suspended) { screen->need_update = true; return; } diff --git a/ui/ncurses/nc-cui.c b/ui/ncurses/nc-cui.c index fbc02b9..c80d354 100644 --- a/ui/ncurses/nc-cui.c +++ b/ui/ncurses/nc-cui.c @@ -59,6 +59,11 @@ static bool lockdown_active(void) return lockdown; } +static bool nc_scr_active(struct cui *cui, struct nc_scr *scr) +{ + return (!cui->suspended && cui->current == scr); +} + static void cui_start(void) { initscr(); /* Initialize ncurses. */ @@ -161,6 +166,12 @@ int cui_run_cmd(struct pmenu_item *item) struct cui *cui = cui_from_item(item); const char **cmd_argv = item->data; + if (cui->suspended) { + pb_log("%s: tried to run command when curses not active\n", + __func__); + return -1; + } + nc_scr_status_printf(cui->current, _("Running %s..."), cmd_argv[0]); def_prog_mode(); @@ -168,7 +179,9 @@ int cui_run_cmd(struct pmenu_item *item) result = process_run_simple_argv(item, cmd_argv); reset_prog_mode(); - redrawwin(cui->current->main_ncw); + + if (cui->current) + redrawwin(cui->current->main_ncw); if (result) { pb_log("%s: failed: '%s'\n", __func__, cmd_argv[0]); @@ -525,6 +538,75 @@ static void cui_handle_resize(struct cui *cui) } /** + * cui_run_external_cb - Return from running an external program and + * re-activate ncurses mode. + */ +static void cui_run_external_cb(struct process *process) +{ + struct cui *cui = process->data; + + reset_prog_mode(); + + if (cui->current && !cui->suspended) { + pb_debug("It's like running nothing at all...\n"); + goto out; + } + + if (!cui->current && cui->suspended) { + cui->current = cui->suspended; + cui->suspended = NULL; + goto out; + } + + /* Something like a reinit or config update occured and required + * switching to a different screen - unpost the old screen and move to + * the new one */ + // FIXME Safely free/clear old screen + if (cui->current && cui->suspended) { + nc_scr_unpost(cui->suspended); + nc_scr_post(cui->current); + cui->suspended = NULL; + } + +out: + refresh(); + talloc_free(process); +} + +/** + * Temporarily drop curses mode to run a synchronous process and give it + * control of the display. + * */ +int cui_run_external(struct cui *cui, struct process *process) +{ + int result; + + pb_debug("Leaving curses mode to run '%s'\n", process->path); + + process->data = cui; + process->exit_cb = cui_run_external_cb; + + cui->suspended = cui->current; + cui->current = NULL; + + def_prog_mode(); + endwin(); + + result = process_run_async(process); + + if (result) { + pb_log("%s: Running '%s' failed\n", + __func__, process->argv[0]); + refresh(); + nc_scr_status_printf(cui->current, _("%s failed"), + process->argv[0]); + talloc_free(process); + } + + return result; +} + +/** * cui_device_add - Client device_add callback. * * Creates menu_items for all the device boot_options and inserts those @@ -548,7 +630,7 @@ static int cui_boot_option_add(struct device *dev, struct boot_option *opt, selected = current_item(cui->main->ncm); menu_format(cui->main->ncm, &rows, &cols); - if (cui->current == &cui->main->scr) + if (nc_scr_active(cui, &cui->main->scr)) nc_scr_unpost(cui->current); /* Check if the boot device is new */ @@ -631,7 +713,7 @@ static int cui_boot_option_add(struct device *dev, struct boot_option *opt, set_current_item(cui->main->ncm, selected); } - if (cui->current == &cui->main->scr) + if (nc_scr_active(cui, &cui->main->scr)) nc_scr_post(cui->current); return 0; @@ -654,7 +736,7 @@ static void cui_device_remove(struct device *dev, void *arg) pb_log("%s: %p %s\n", __func__, dev, dev->id); - if (cui->current == &cui->main->scr) + if (nc_scr_active(cui, &cui->main->scr)) nc_scr_unpost(cui->current); /* This disconnects items array from menu. */ @@ -704,7 +786,7 @@ static void cui_device_remove(struct device *dev, void *arg) item_count(cui->main->ncm) + 1); } - if (cui->current == &cui->main->scr) + if (nc_scr_active(cui, &cui->main->scr)) nc_scr_post(cui->current); } @@ -715,7 +797,7 @@ static void cui_update_status(struct status *status, void *arg) statuslog_append_steal(cui, cui->statuslog, status); /* Ignore status messages from the backlog */ - if (!status->backlog) + if (!status->backlog && !cui->suspended) nc_scr_status_printf(cui->current, "%s", status->message); } @@ -730,7 +812,7 @@ static void cui_update_mm_title(struct cui *cui) frame->rtitle = talloc_asprintf_append(frame->rtitle, " %s", cui->sysinfo->identifier); - if (cui->current == &cui->main->scr) + if (nc_scr_active(cui, &cui->main->scr)) nc_scr_post(cui->current); } @@ -799,7 +881,7 @@ static void cui_update_config(struct config *config, void *arg) if (cui->config_screen) config_screen_update(cui->config_screen, config, cui->sysinfo); - if (config->safe_mode) + if (config->safe_mode && !cui->suspended) nc_scr_status_printf(cui->current, _("SAFE MODE: select '%s' to continue"), _("Rescan devices")); diff --git a/ui/ncurses/nc-cui.h b/ui/ncurses/nc-cui.h index 418df71..2171304 100644 --- a/ui/ncurses/nc-cui.h +++ b/ui/ncurses/nc-cui.h @@ -25,6 +25,8 @@ #include "nc-menu.h" #include "nc-helpscreen.h" +struct process; + struct cui_opt_data { const char *name; struct pb_boot_data *bd; @@ -52,6 +54,7 @@ struct cui { sig_atomic_t abort; sig_atomic_t resize; struct nc_scr *current; + struct nc_scr *suspended; struct pmenu *main; struct waitset *waitset; struct discover_client *client; @@ -91,6 +94,7 @@ void cui_show_add_url(struct cui *cui); int cui_send_config(struct cui *cui, struct config *config); int cui_send_url(struct cui *cui, char *url); void cui_send_reinit(struct cui *cui); +int cui_run_external(struct cui *cui, struct process *process); /* convenience routines */ diff --git a/ui/ncurses/nc-scr.c b/ui/ncurses/nc-scr.c index a02627b..ff5eb2d 100644 --- a/ui/ncurses/nc-scr.c +++ b/ui/ncurses/nc-scr.c @@ -100,6 +100,9 @@ void nc_scr_status_printf(struct nc_scr *scr, const char *format, ...) { va_list ap; + if (!scr) + return; + nc_scr_status_free(scr); va_start(ap, format); diff --git a/ui/ncurses/nc-sysinfo.c b/ui/ncurses/nc-sysinfo.c index 8252b45..7319a0a 100644 --- a/ui/ncurses/nc-sysinfo.c +++ b/ui/ncurses/nc-sysinfo.c @@ -143,9 +143,11 @@ static void sysinfo_screen_populate(struct sysinfo_screen *screen, void sysinfo_screen_update(struct sysinfo_screen *screen, const struct system_info *sysinfo) { + struct cui *cui = screen->text_scr.cui; + sysinfo_screen_populate(screen, sysinfo); - if (screen->text_scr.cui->help_screen) + if (cui->help_screen || cui->suspended) screen->text_scr.need_update = true; else text_screen_draw(&screen->text_scr);