int label_x;
int field_x;
+ int scroll_y;
+ WINDOW *pad;
struct nc_widgetset *widgetset;
struct {
+ struct nc_widget_label *device_l;
+ struct nc_widget_select *device_f;
struct nc_widget_label *image_l;
struct nc_widget_textbox *image_f;
struct nc_widget_label *initrd_l;
struct nc_widget_button *ok_b;
struct nc_widget_button *cancel_b;
} widgets;
+
+ const char *selected_device;
};
static struct boot_editor *boot_editor_from_scr(struct nc_scr *scr)
return boot_editor;
}
+static void pad_refresh(struct boot_editor *boot_editor)
+{
+ int y, x, rows, cols;
+
+ getmaxyx(boot_editor->scr.sub_ncw, rows, cols);
+ getbegyx(boot_editor->scr.sub_ncw, y, x);
+
+ prefresh(boot_editor->pad, boot_editor->scroll_y, 0,
+ y, x, rows, cols);
+}
+
static struct boot_editor *boot_editor_from_arg(void *arg)
{
struct boot_editor *boot_editor = arg;
widgetset_post(boot_editor->widgetset);
nc_scr_frame_draw(scr);
- redrawwin(boot_editor->scr.main_ncw);
- wrefresh(boot_editor->scr.main_ncw);
-
+ pad_refresh(boot_editor);
return 0;
}
boot_editor_post(scr);
}
+static char *conditional_prefix(struct pb_boot_data *ctx,
+ const char *prefix, const char *value)
+{
+ const char *sep;
+
+ if (!value || !*value)
+ return NULL;
+
+ sep = NULL;
+ if (!prefix)
+ prefix = "";
+ else if (prefix[strlen(prefix)] != '/')
+ sep = "/";
+
+ return talloc_asprintf(ctx, "%s%s%s", prefix, sep, value);
+}
+
static struct pb_boot_data *boot_editor_prepare_data(
struct boot_editor *boot_editor)
{
struct pb_boot_data *bd;
- char *s;
+ char *s, *prefix;
+ int idx;
bd = talloc(boot_editor, struct pb_boot_data);
if (!bd)
return NULL;
+ idx = widget_select_get_value(boot_editor->widgets.device_f);
+ if (idx == -1 || (unsigned int)idx >
+ boot_editor->cui->sysinfo->n_blockdevs)
+ prefix = NULL;
+ else
+ prefix = boot_editor->cui->sysinfo->blockdevs[idx]->mountpoint;
+
s = widget_textbox_get_value(boot_editor->widgets.image_f);
- bd->image = *s ? talloc_strdup(bd, s) : NULL;
+ bd->image = conditional_prefix(bd, prefix, s);
s = widget_textbox_get_value(boot_editor->widgets.initrd_f);
- bd->initrd = *s ? talloc_strdup(bd, s) : NULL;
+ bd->initrd = conditional_prefix(bd, prefix, s);
s = widget_textbox_get_value(boot_editor->widgets.dtb_f);
- bd->dtb = *s ? talloc_strdup(bd, s) : NULL;
+ bd->dtb = conditional_prefix(bd, prefix, s);
s = widget_textbox_get_value(boot_editor->widgets.args_f);
bd->args = *s ? talloc_strdup(bd, s) : NULL;
handled = widgetset_process_key(boot_editor->widgetset, key);
if (handled) {
- wrefresh(boot_editor->scr.main_ncw);
+ pad_refresh(boot_editor);
return;
}
{
struct boot_editor *boot_editor = boot_editor_from_arg(arg);
boot_editor->scr.sig = pb_removed_sig;
+ if (boot_editor->pad)
+ delwin(boot_editor->pad);
return 0;
}
return max(widget_height(label_w), widget_height(field_w));
}
+static int pad_height(int blockdevs_height)
+{
+ return 10 + blockdevs_height;
+}
+
static void boot_editor_layout_widgets(struct boot_editor *boot_editor)
{
+ struct nc_widget *wf, *wl;
int y = 1;
+ wl = widget_label_base(boot_editor->widgets.device_l);
+ wf = widget_select_base(boot_editor->widgets.device_f);
+ widget_move(wl, y, boot_editor->label_x);
+ widget_move(wf, y, boot_editor->field_x);
+
+ y += widget_height(wf) + 1;
+
+
y += layout_pair(boot_editor, y, boot_editor->widgets.image_l,
boot_editor->widgets.image_f);
y++;
widget_move(widget_button_base(boot_editor->widgets.ok_b), y, 9);
widget_move(widget_button_base(boot_editor->widgets.cancel_b), y, 19);
+
+ pad_refresh(boot_editor);
+}
+
+static void boot_editor_widget_focus(struct nc_widget *widget, void *arg)
+{
+ struct boot_editor *boot_editor = arg;
+ int w_y, w_height, s_max;
+
+ w_y = widget_y(widget);
+ w_height = widget_height(widget);
+ s_max = getmaxy(boot_editor->scr.sub_ncw);
+
+ if (w_y < boot_editor->scroll_y)
+ boot_editor->scroll_y = w_y;
+
+ else if (w_y + w_height + boot_editor->scroll_y > s_max - 1)
+ boot_editor->scroll_y = 1 + w_y + w_height - s_max;
+
+ else
+ return;
+
+ pad_refresh(boot_editor);
+}
+
+static void boot_editor_device_select_change(void *arg, int idx)
+{
+ struct boot_editor *boot_editor = arg;
+ if (idx == -1)
+ boot_editor->selected_device = NULL;
+ else
+ boot_editor->selected_device =
+ boot_editor->cui->sysinfo->blockdevs[idx]->name;
+}
+
+static void boot_editor_populate_device_select(struct boot_editor *boot_editor,
+ const struct system_info *sysinfo)
+{
+ struct nc_widget_select *select = boot_editor->widgets.device_f;
+ unsigned int i;
+ bool selected;
+
+ widget_select_drop_options(select);
+
+ for (i = 0; i < sysinfo->n_blockdevs; i++) {
+ struct blockdev_info *bd_info = sysinfo->blockdevs[i];
+ const char *name;
+
+ name = talloc_asprintf(boot_editor, "%s [%s]",
+ bd_info->name, bd_info->uuid);
+ selected = boot_editor->selected_device &&
+ !strcmp(bd_info->name,
+ boot_editor->selected_device);
+
+ widget_select_add_option(boot_editor->widgets.device_f,
+ i, name, selected);
+ }
+
+ /* If we're editing an existing option, the paths will be fully-
+ * resolved. In this case, we want the manual device pre-selected.
+ * However, we only do this if the widget hasn't been manually
+ * changed. */
+ selected = !boot_editor->selected_device;
+
+ widget_select_add_option(boot_editor->widgets.device_f,
+ -1, "Specify paths/URLs manually", selected);
+}
+
+static bool path_on_device(struct blockdev_info *bd_info,
+ const char *path)
+{
+ int len;
+
+ if (!bd_info->mountpoint)
+ return false;
+
+ len = strlen(bd_info->mountpoint);
+ if (strncmp(bd_info->mountpoint, path, len))
+ return false;
+
+ /* if the mountpoint doesn't have a trailing slash, ensure that
+ * the path starts with one (so we don't match a "/mnt/sda1/foo" path
+ * on a "/mnt/sda" mountpoint) */
+ return bd_info->mountpoint[len-1] == '/' || path[len] == '/';
+}
+
+
+static void boot_editor_find_device(struct boot_editor *boot_editor,
+ struct pb_boot_data *bd, const struct system_info *sysinfo,
+ char **image, char **initrd, char **dtb)
+{
+ struct blockdev_info *bd_info, *tmp;
+ unsigned int i, len;
+
+ if (!sysinfo || !sysinfo->n_blockdevs)
+ return;
+
+ /* find the device for our boot image, by finding the longest
+ * matching blockdev's mountpoint */
+ for (len = 0, i = 0, bd_info = NULL; i < sysinfo->n_blockdevs; i++) {
+ tmp = sysinfo->blockdevs[i];
+ if (!path_on_device(tmp, bd->image))
+ continue;
+ if (strlen(tmp->mountpoint) <= len)
+ continue;
+ bd_info = tmp;
+ len = strlen(tmp->mountpoint);
+ }
+
+ if (!bd_info)
+ return;
+
+ /* ensure that other paths are on this device */
+ if (bd->initrd && !path_on_device(bd_info, bd->initrd))
+ return;
+
+ if (bd->dtb && !path_on_device(bd_info, bd->dtb))
+ return;
+
+ /* ok, we match; preselect the device option, and remove the common
+ * prefix */
+ boot_editor->selected_device = bd_info->name;
+ *image += len;
+
+ if (*initrd)
+ *initrd += len;
+ if (*dtb)
+ *dtb += len;
}
struct boot_editor *boot_editor_init(struct cui *cui,
initrd = bd->initrd;
dtb = bd->dtb;
args = bd->args;
+ boot_editor_find_device(boot_editor, bd, sysinfo,
+ &image, &initrd, &dtb);
} else {
image = initrd = dtb = args = "";
}
field_size = COLS - 1 - boot_editor->field_x;
+ boot_editor->pad = newpad(pad_height(sysinfo->n_blockdevs), COLS);
+
boot_editor->widgetset = set = widgetset_create(boot_editor,
boot_editor->scr.main_ncw,
- boot_editor->scr.sub_ncw);
+ boot_editor->pad);
+
+ widgetset_set_widget_focus(boot_editor->widgetset,
+ boot_editor_widget_focus, boot_editor);
+
+ boot_editor->widgets.device_l = widget_new_label(set, 0, 0, "device:");
+ boot_editor->widgets.device_f = widget_new_select(set, 0, 0,
+ field_size);
+ widget_select_on_change(boot_editor->widgets.device_f,
+ boot_editor_device_select_change, boot_editor);
+
+ boot_editor_populate_device_select(boot_editor, sysinfo);
boot_editor->widgets.image_l = widget_new_label(set, 0, 0, "image:");
boot_editor->widgets.image_f = widget_new_textbox(set, 0, 0,