2 * Copyright (C) 2013 IBM Corporation
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 #if defined(HAVE_CONFIG_H)
26 #include <pb-config/pb-config.h>
27 #include <talloc/talloc.h>
28 #include <types/types.h>
30 #include <i18n/i18n.h>
33 #include "nc-config.h"
34 #include "nc-widgets.h"
38 extern struct help_text config_help_text;
47 NET_CONF_TYPE_DHCP_ALL,
48 NET_CONF_TYPE_DHCP_ONE,
52 struct config_screen {
55 struct nc_widgetset *widgetset;
60 void (*on_exit)(struct cui *);
68 enum net_conf_type net_conf_type;
69 enum autoboot_type autoboot_type;
72 struct nc_widget_select *autoboot_f;
73 struct nc_widget_label *autoboot_l;
74 struct nc_widget_select *boot_device_f;
75 struct nc_widget_textbox *timeout_f;
76 struct nc_widget_label *timeout_l;
77 struct nc_widget_label *timeout_help_l;
79 struct nc_widget_label *network_l;
80 struct nc_widget_select *network_f;
82 struct nc_widget_label *iface_l;
83 struct nc_widget_select *iface_f;
84 struct nc_widget_label *ip_addr_l;
85 struct nc_widget_textbox *ip_addr_f;
86 struct nc_widget_label *ip_mask_l;
87 struct nc_widget_textbox *ip_mask_f;
88 struct nc_widget_label *ip_addr_mask_help_l;
89 struct nc_widget_label *gateway_l;
90 struct nc_widget_textbox *gateway_f;
91 struct nc_widget_label *gateway_help_l;
92 struct nc_widget_label *dns_l;
93 struct nc_widget_textbox *dns_f;
94 struct nc_widget_label *dns_dhcp_help_l;
95 struct nc_widget_label *dns_help_l;
97 struct nc_widget_button *ok_b;
98 struct nc_widget_button *help_b;
99 struct nc_widget_button *cancel_b;
103 static struct config_screen *config_screen_from_scr(struct nc_scr *scr)
105 struct config_screen *config_screen;
107 assert(scr->sig == pb_config_screen_sig);
108 config_screen = (struct config_screen *)
109 ((char *)scr - (size_t)&((struct config_screen *)0)->scr);
110 assert(config_screen->scr.sig == pb_config_screen_sig);
111 return config_screen;
114 static void pad_refresh(struct config_screen *screen)
116 int y, x, rows, cols;
118 getmaxyx(screen->scr.sub_ncw, rows, cols);
119 getbegyx(screen->scr.sub_ncw, y, x);
121 prefresh(screen->pad, screen->scroll_y, 0, y, x, rows, cols);
124 static void config_screen_process_key(struct nc_scr *scr, int key)
126 struct config_screen *screen = config_screen_from_scr(scr);
129 handled = widgetset_process_key(screen->widgetset, key);
138 screen->show_help = true;
144 screen->on_exit(screen->cui);
146 } else if (screen->show_help) {
147 screen->show_help = false;
148 cui_show_help(screen->cui, _("System Configuration"),
151 } else if (handled) {
156 static void config_screen_resize(struct nc_scr *scr)
158 struct config_screen *screen = config_screen_from_scr(scr);
162 static int config_screen_post(struct nc_scr *scr)
164 struct config_screen *screen = config_screen_from_scr(scr);
165 widgetset_post(screen->widgetset);
166 nc_scr_frame_draw(scr);
167 redrawwin(scr->main_ncw);
168 wrefresh(screen->scr.main_ncw);
173 static int config_screen_unpost(struct nc_scr *scr)
175 struct config_screen *screen = config_screen_from_scr(scr);
176 widgetset_unpost(screen->widgetset);
180 struct nc_scr *config_screen_scr(struct config_screen *screen)
185 static int screen_process_form(struct config_screen *screen)
187 const struct system_info *sysinfo = screen->cui->sysinfo;
188 enum net_conf_type net_conf_type;
189 struct interface_config *iface;
190 struct config *config;
194 config = config_copy(screen, screen->cui->config);
196 screen->autoboot_type =
197 widget_select_get_value(screen->widgets.autoboot_f);
199 config->autoboot_enabled = screen->autoboot_type != AUTOBOOT_DISABLED;
201 if (screen->autoboot_type == AUTOBOOT_ONE) {
202 char mac[20], *uuid = NULL;
204 /* if idx is -1 here, we have an unknown UUID selected.
205 * Otherwise, it's a blockdev index (idx <= n_blockdevs) or an
208 idx = widget_select_get_value(screen->widgets.boot_device_f);
209 if (idx >= (int)sysinfo->n_blockdevs) {
210 struct interface_info *info = sysinfo->
211 interfaces[idx - sysinfo->n_blockdevs];
212 mac_str(info->hwaddr, info->hwaddr_size,
215 } else if (idx != -1) {
216 uuid = sysinfo->blockdevs[idx]->uuid;
220 talloc_free(config->boot_device);
221 config->boot_device = talloc_strdup(config, uuid);
225 str = widget_textbox_get_value(screen->widgets.timeout_f);
229 x = strtoul(str, &end, 10);
230 if (!errno && end != str)
231 config->autoboot_timeout_sec = x;
234 net_conf_type = widget_select_get_value(screen->widgets.network_f);
236 /* if we don't have any network interfaces, prevent per-interface
238 if (sysinfo->n_interfaces == 0)
239 net_conf_type = NET_CONF_TYPE_DHCP_ALL;
241 if (net_conf_type == NET_CONF_TYPE_DHCP_ALL) {
242 config->network.n_interfaces = 0;
245 iface = talloc_zero(config, struct interface_config);
246 config->network.n_interfaces = 1;
247 config->network.interfaces = talloc_array(config,
248 struct interface_config *, 1);
249 config->network.interfaces[0] = iface;
251 /* copy hwaddr (from the sysinfo interface data) to
252 * the configuration */
253 idx = widget_select_get_value(screen->widgets.iface_f);
254 memcpy(iface->hwaddr, sysinfo->interfaces[idx]->hwaddr,
255 sizeof(iface->hwaddr));
258 if (net_conf_type == NET_CONF_TYPE_DHCP_ONE) {
259 iface->method = CONFIG_METHOD_DHCP;
262 if (net_conf_type == NET_CONF_TYPE_STATIC) {
263 char *ip, *mask, *gateway;
265 ip = widget_textbox_get_value(screen->widgets.ip_addr_f);
266 mask = widget_textbox_get_value(screen->widgets.ip_mask_f);
267 gateway = widget_textbox_get_value(screen->widgets.gateway_f);
269 if (!ip || !*ip || !mask || !*mask) {
270 screen->scr.frame.status =
271 _("No IP / mask values are set");
272 nc_scr_frame_draw(&screen->scr);
277 iface->method = CONFIG_METHOD_STATIC;
278 iface->static_config.address = talloc_asprintf(iface, "%s/%s",
280 iface->static_config.gateway = talloc_strdup(iface, gateway);
283 str = widget_textbox_get_value(screen->widgets.dns_f);
284 talloc_free(config->network.dns_servers);
285 config->network.dns_servers = NULL;
286 config->network.n_dns_servers = 0;
288 if (str && strlen(str)) {
293 dns = strtok_r(str, " \t", &tmp);
298 i = config->network.n_dns_servers++;
299 config->network.dns_servers = talloc_realloc(config,
300 config->network.dns_servers,
302 config->network.n_dns_servers);
303 config->network.dns_servers[i] =
304 talloc_strdup(config, dns);
310 rc = cui_send_config(screen->cui, config);
314 pb_log("cui_send_config failed!\n");
316 pb_debug("config sent!\n");
321 static void ok_click(void *arg)
323 struct config_screen *screen = arg;
324 if (screen_process_form(screen))
325 /* errors are written to the status line, so we'll need
327 wrefresh(screen->scr.main_ncw);
332 static void help_click(void *arg)
334 struct config_screen *screen = arg;
335 screen->show_help = true;
338 static void cancel_click(void *arg)
340 struct config_screen *screen = arg;
344 static int layout_pair(struct config_screen *screen, int y,
345 struct nc_widget_label *label,
346 struct nc_widget *field)
348 struct nc_widget *label_w = widget_label_base(label);
349 widget_move(label_w, y, screen->label_x);
350 widget_move(field, y, screen->field_x);
351 return max(widget_height(label_w), widget_height(field));
354 static void config_screen_layout_widgets(struct config_screen *screen)
356 struct nc_widget *wl, *wf, *wh;
361 help_x = screen->field_x + 2 +
362 widget_width(widget_textbox_base(screen->widgets.dns_f));
364 y += layout_pair(screen, y, screen->widgets.autoboot_l,
365 widget_select_base(screen->widgets.autoboot_f));
367 wf = widget_select_base(screen->widgets.boot_device_f);
368 if (screen->autoboot_type == AUTOBOOT_ONE) {
369 widget_set_visible(wf, true);
370 widget_move(wf, y, screen->field_x + 3);
371 y += widget_height(wf);
373 widget_set_visible(wf, false);
378 wf = widget_textbox_base(screen->widgets.timeout_f);
379 wl = widget_label_base(screen->widgets.timeout_l);
380 wh = widget_label_base(screen->widgets.timeout_help_l);
381 if (screen->autoboot_type != AUTOBOOT_DISABLED) {
382 widget_set_visible(wl, true);
383 widget_set_visible(wf, true);
384 widget_set_visible(wh, true);
385 widget_move(wl, y, screen->label_x);
386 widget_move(wf, y, screen->field_x);
387 widget_move(wh, y, screen->field_x + widget_width(wf) + 1);
390 widget_set_visible(wl, false);
391 widget_set_visible(wf, false);
392 widget_set_visible(wh, false);
395 y += layout_pair(screen, y, screen->widgets.network_l,
396 widget_select_base(screen->widgets.network_f));
400 /* conditionally show iface select */
401 wl = widget_label_base(screen->widgets.iface_l);
402 wf = widget_select_base(screen->widgets.iface_f);
404 show = screen->net_conf_type == NET_CONF_TYPE_DHCP_ONE ||
405 screen->net_conf_type == NET_CONF_TYPE_STATIC;
407 widget_set_visible(wl, show);
408 widget_set_visible(wf, show);
411 y += layout_pair(screen, y, screen->widgets.iface_l, wf) + 1;
413 /* conditionally show static IP params */
414 show = screen->net_conf_type == NET_CONF_TYPE_STATIC;
416 wl = widget_label_base(screen->widgets.ip_addr_l);
417 wf = widget_textbox_base(screen->widgets.ip_addr_f);
418 widget_set_visible(wl, show);
419 widget_set_visible(wf, show);
420 x = screen->field_x + widget_width(wf) + 1;
423 layout_pair(screen, y, screen->widgets.ip_addr_l, wf);
425 wl = widget_label_base(screen->widgets.ip_mask_l);
426 wf = widget_textbox_base(screen->widgets.ip_mask_f);
427 widget_set_visible(wl, show);
428 widget_set_visible(wf, show);
431 widget_move(wl, y, x);
432 widget_move(wf, y, x + 2);
435 /* help for IP/mask */
436 wh = widget_label_base(screen->widgets.ip_addr_mask_help_l);
437 widget_set_visible(wh, show);
439 widget_move(wh, y, help_x);
443 wl = widget_label_base(screen->widgets.gateway_l);
444 wf = widget_textbox_base(screen->widgets.gateway_f);
445 wh = widget_label_base(screen->widgets.gateway_help_l);
446 widget_set_visible(wl, show);
447 widget_set_visible(wf, show);
448 widget_set_visible(wh, show);
451 layout_pair(screen, y, screen->widgets.gateway_l, wf);
452 widget_move(wh, y, help_x);
456 wh = widget_label_base(screen->widgets.dns_help_l);
457 layout_pair(screen, y, screen->widgets.dns_l,
458 widget_textbox_base(screen->widgets.dns_f));
459 widget_move(wh, y, help_x);
462 /* we show the DNS/DHCP help if we're configuring DHCP */
463 show = screen->net_conf_type != NET_CONF_TYPE_STATIC;
464 wl = widget_label_base(screen->widgets.dns_dhcp_help_l);
465 widget_set_visible(wl, show);
467 widget_move(wl, y, screen->field_x);
473 widget_move(widget_button_base(screen->widgets.ok_b),
475 widget_move(widget_button_base(screen->widgets.help_b),
476 y, screen->field_x + 10);
477 widget_move(widget_button_base(screen->widgets.cancel_b),
478 y, screen->field_x + 20);
481 static void config_screen_network_change(void *arg, int value)
483 struct config_screen *screen = arg;
484 screen->net_conf_type = value;
485 widgetset_unpost(screen->widgetset);
486 config_screen_layout_widgets(screen);
487 widgetset_post(screen->widgetset);
490 static void config_screen_autoboot_change(void *arg, int value)
492 struct config_screen *screen = arg;
493 screen->autoboot_type = value;
494 widgetset_unpost(screen->widgetset);
495 config_screen_layout_widgets(screen);
496 widgetset_post(screen->widgetset);
499 static struct interface_config *first_active_interface(
500 const struct config *config)
504 for (i = 0; i < config->network.n_interfaces; i++) {
505 if (config->network.interfaces[i]->ignore)
507 return config->network.interfaces[i];
512 static enum net_conf_type find_net_conf_type(const struct config *config)
514 struct interface_config *ifcfg;
516 ifcfg = first_active_interface(config);
519 return NET_CONF_TYPE_DHCP_ALL;
521 else if (ifcfg->method == CONFIG_METHOD_DHCP)
522 return NET_CONF_TYPE_DHCP_ONE;
524 else if (ifcfg->method == CONFIG_METHOD_STATIC)
525 return NET_CONF_TYPE_STATIC;
528 return NET_CONF_TYPE_DHCP_ALL;
531 static void config_screen_setup_empty(struct config_screen *screen)
533 widget_new_label(screen->widgetset, 2, screen->field_x,
534 _("Waiting for configuration data..."));
535 screen->widgets.cancel_b = widget_new_button(screen->widgetset,
536 4, screen->field_x, 6, _("Cancel"),
537 cancel_click, screen);
541 static void config_screen_setup_widgets(struct config_screen *screen,
542 const struct config *config,
543 const struct system_info *sysinfo)
545 struct nc_widgetset *set = screen->widgetset;
546 struct interface_config *ifcfg;
547 char *str, *ip, *mask, *gw;
548 enum net_conf_type type;
552 build_assert(sizeof(screen->widgets) / sizeof(struct widget *)
555 type = screen->net_conf_type;
556 ifcfg = first_active_interface(config);
558 screen->widgets.autoboot_l = widget_new_label(set, 0, 0,
560 screen->widgets.autoboot_f = widget_new_select(set, 0, 0, 55);
562 widget_select_on_change(screen->widgets.autoboot_f,
563 config_screen_autoboot_change, screen);
565 screen->widgets.boot_device_f = widget_new_select(set, 0, 0, 55);
567 widget_select_add_option(screen->widgets.autoboot_f,
570 screen->autoboot_type ==
572 widget_select_add_option(screen->widgets.autoboot_f,
574 _("Autoboot from any "
575 "disk/network device"),
576 screen->autoboot_type ==
578 widget_select_add_option(screen->widgets.autoboot_f,
580 _("Only autoboot from a specific "
581 "disk/network device"),
582 screen->autoboot_type ==
587 for (i = 0; i < sysinfo->n_blockdevs; i++) {
588 struct blockdev_info *bd = sysinfo->blockdevs[i];
592 selected = config->boot_device &&
593 !strcmp(config->boot_device, bd->uuid);
597 label = talloc_asprintf(screen, _("disk: %s [uuid: %s]"),
600 widget_select_add_option(screen->widgets.boot_device_f, i,
604 for (i = 0; i < sysinfo->n_interfaces; i++) {
605 struct interface_info *info = sysinfo->interfaces[i];
606 char *label, mac[20];
609 mac_str(info->hwaddr, info->hwaddr_size, mac, sizeof(mac));
610 selected = config->boot_device &&
611 !strcmp(config->boot_device, mac);
615 label = talloc_asprintf(screen, _("net: %s [mac: %s]"),
618 widget_select_add_option(screen->widgets.boot_device_f,
619 i + sysinfo->n_blockdevs,
623 if (screen->autoboot_type == AUTOBOOT_ONE && !found) {
626 label = talloc_asprintf(screen, _("Unknown UUID: %s"),
627 config->boot_device);
629 widget_select_add_option(screen->widgets.boot_device_f, -1,
633 str = talloc_asprintf(screen, "%d", config->autoboot_timeout_sec);
634 screen->widgets.timeout_l = widget_new_label(set, 0, 0, _("Timeout:"));
635 screen->widgets.timeout_f = widget_new_textbox(set, 0, 0, 5, str);
636 screen->widgets.timeout_help_l = widget_new_label(set, 0, 0,
639 widget_textbox_set_fixed_size(screen->widgets.timeout_f);
640 widget_textbox_set_validator_integer(screen->widgets.timeout_f, 0, 999);
642 screen->widgets.network_l = widget_new_label(set, 0, 0, _("Network:"));
643 screen->widgets.network_f = widget_new_select(set, 0, 0, 50);
645 widget_select_add_option(screen->widgets.network_f,
646 NET_CONF_TYPE_DHCP_ALL,
647 _("DHCP on all active interfaces"),
648 type == NET_CONF_TYPE_DHCP_ALL);
649 widget_select_add_option(screen->widgets.network_f,
650 NET_CONF_TYPE_DHCP_ONE,
651 _("DHCP on a specific interface"),
652 type == NET_CONF_TYPE_DHCP_ONE);
653 widget_select_add_option(screen->widgets.network_f,
654 NET_CONF_TYPE_STATIC,
655 _("Static IP configuration"),
656 type == NET_CONF_TYPE_STATIC);
658 widget_select_on_change(screen->widgets.network_f,
659 config_screen_network_change, screen);
661 screen->widgets.iface_l = widget_new_label(set, 0, 0, _("Device:"));
662 screen->widgets.iface_f = widget_new_select(set, 0, 0, 50);
664 for (i = 0; i < sysinfo->n_interfaces; i++) {
665 struct interface_info *info = sysinfo->interfaces[i];
666 char str[50], mac[20];
669 is_default = ifcfg && !memcmp(ifcfg->hwaddr, info->hwaddr,
670 sizeof(ifcfg->hwaddr));
672 mac_str(info->hwaddr, info->hwaddr_size, mac, sizeof(mac));
673 snprintf(str, sizeof(str), "%s [%s, %s]", info->name, mac,
674 info->link ? _("link up") : _("link down"));
676 widget_select_add_option(screen->widgets.iface_f,
680 gw = ip = mask = NULL;
681 if (ifcfg && ifcfg->method == CONFIG_METHOD_STATIC) {
684 str = talloc_strdup(screen, ifcfg->static_config.address);
685 sep = strchr(str, '/');
692 gw = ifcfg->static_config.gateway;
695 screen->widgets.ip_addr_l = widget_new_label(set, 0, 0, _("IP/mask:"));
696 screen->widgets.ip_addr_f = widget_new_textbox(set, 0, 0, 16, ip);
697 screen->widgets.ip_mask_l = widget_new_label(set, 0, 0, "/");
698 screen->widgets.ip_mask_f = widget_new_textbox(set, 0, 0, 3, mask);
699 screen->widgets.ip_addr_mask_help_l =
700 widget_new_label(set, 0, 0, _("(eg. 192.168.0.10 / 24)"));
702 widget_textbox_set_fixed_size(screen->widgets.ip_addr_f);
703 widget_textbox_set_fixed_size(screen->widgets.ip_mask_f);
704 widget_textbox_set_validator_ipv4(screen->widgets.ip_addr_f);
705 widget_textbox_set_validator_integer(screen->widgets.ip_mask_f, 1, 31);
707 screen->widgets.gateway_l = widget_new_label(set, 0, 0, _("Gateway:"));
708 screen->widgets.gateway_f = widget_new_textbox(set, 0, 0, 16, gw);
709 screen->widgets.gateway_help_l =
710 widget_new_label(set, 0, 0, _("(eg. 192.168.0.1)"));
712 widget_textbox_set_fixed_size(screen->widgets.gateway_f);
713 widget_textbox_set_validator_ipv4(screen->widgets.gateway_f);
715 str = talloc_strdup(screen, "");
716 for (i = 0; i < config->network.n_dns_servers; i++) {
717 str = talloc_asprintf_append(str, "%s%s",
719 config->network.dns_servers[i]);
722 screen->widgets.dns_l = widget_new_label(set, 0, 0,
723 _("DNS Server(s):"));
724 screen->widgets.dns_f = widget_new_textbox(set, 0, 0, 32, str);
725 screen->widgets.dns_help_l =
726 widget_new_label(set, 0, 0, _("(eg. 192.168.0.2)"));
728 widget_textbox_set_validator_ipv4_multi(screen->widgets.dns_f);
730 screen->widgets.dns_dhcp_help_l = widget_new_label(set, 0, 0,
731 _("(if not provided by DHCP server)"));
733 screen->widgets.ok_b = widget_new_button(set, 0, 0, 6, _("OK"),
735 screen->widgets.help_b = widget_new_button(set, 0, 0, 6, _("Help"),
737 screen->widgets.cancel_b = widget_new_button(set, 0, 0, 6, _("Cancel"),
738 cancel_click, screen);
741 static void config_screen_widget_focus(struct nc_widget *widget, void *arg)
743 struct config_screen *screen = arg;
746 w_y = widget_y(widget) + widget_focus_y(widget);
747 s_max = getmaxy(screen->scr.sub_ncw) - 1;
749 if (w_y < screen->scroll_y)
750 screen->scroll_y = w_y;
752 else if (w_y + screen->scroll_y + 1 > s_max)
753 screen->scroll_y = 1 + w_y - s_max;
761 static void config_screen_draw(struct config_screen *screen,
762 const struct config *config,
763 const struct system_info *sysinfo)
768 /* The size of the pad we'll need depends on the number of interfaces.
770 * We use N_FIELDS (which is quite conservative, as some fields share
771 * a line) as a base, then add 3 (as the network select field is
772 * takes 3 lines), and n_interfaces (as the network interface field
773 * has n_interfaces lines).
775 height = N_FIELDS + 3;
777 height += sysinfo->n_interfaces;
778 if (!screen->pad || getmaxy(screen->pad) < height) {
781 screen->pad = newpad(height, COLS);
784 if (screen->widgetset) {
785 widgetset_unpost(screen->widgetset);
786 talloc_free(screen->widgetset);
790 screen->widgetset = widgetset_create(screen, screen->scr.main_ncw,
792 widgetset_set_widget_focus(screen->widgetset,
793 config_screen_widget_focus, screen);
795 if (!config || !sysinfo) {
796 config_screen_setup_empty(screen);
798 screen->net_conf_type = find_net_conf_type(config);
799 if (!config->autoboot_enabled)
800 screen->autoboot_type = AUTOBOOT_DISABLED;
802 screen->autoboot_type = config->boot_device ?
803 AUTOBOOT_ONE : AUTOBOOT_ANY;
805 config_screen_setup_widgets(screen, config, sysinfo);
806 config_screen_layout_widgets(screen);
810 widgetset_post(screen->widgetset);
813 void config_screen_update(struct config_screen *screen,
814 const struct config *config,
815 const struct system_info *sysinfo)
817 config_screen_draw(screen, config, sysinfo);
821 static int config_screen_destroy(void *arg)
823 struct config_screen *screen = arg;
829 struct config_screen *config_screen_init(struct cui *cui,
830 const struct config *config,
831 const struct system_info *sysinfo,
832 void (*on_exit)(struct cui *))
834 struct config_screen *screen;
836 screen = talloc_zero(cui, struct config_screen);
837 talloc_set_destructor(screen, config_screen_destroy);
838 nc_scr_init(&screen->scr, pb_config_screen_sig, 0,
839 cui, config_screen_process_key,
840 config_screen_post, config_screen_unpost,
841 config_screen_resize);
844 screen->on_exit = on_exit;
846 screen->field_x = 17;
848 screen->scr.frame.ltitle = talloc_strdup(screen,
849 _("Petitboot System Configuration"));
850 screen->scr.frame.rtitle = NULL;
851 screen->scr.frame.help = talloc_strdup(screen,
852 _("tab=next, shift+tab=previous, x=exit, h=help"));
853 nc_scr_frame_draw(&screen->scr);
855 scrollok(screen->scr.sub_ncw, true);
857 config_screen_draw(screen, config, sysinfo);