[RFC PATCH 8/9] ui/ncurses: Allow giving certain processes control of the display
Samuel Mendoza-Jonas
sam at mendozajonas.com
Wed Feb 15 15:35:40 AEDT 2017
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 <sam at mendozajonas.com>
---
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);
--
2.11.1
More information about the Petitboot
mailing list