Logo Search packages:      
Sourcecode: xfree86 version File versions

text-mode.c

/*
 * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *  
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * CONECTIVA LINUX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * 
 * Except as contained in this notice, the name of Conectiva Linux shall
 * not be used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization from
 * Conectiva Linux.
 *
 * Author: Paulo CÚsar Pereira de Andrade <pcpa@conectiva.com.br>
 *
 * $XFree86: xc/programs/Xserver/hw/xfree86/xf86cfg/text-mode.c,v 1.22 2003/02/16 05:23:45 paulo Exp $
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _SCO_DS
#include <curses.h>
#else
#include <ncurses.h>
#endif
#include <ctype.h>
#include <X11/Xlib.h>
#include <X11/extensions/XKBstr.h>
#include <X11/extensions/XKBrules.h>
#include "cards.h"
#include "config.h"
#include "xf86config.h"
#include "loader.h"

#define XKB_RULES_DIR "/usr/X11R6/lib/X11/xkb/rules"

#define CONTROL_A 1
#define CONTROL_D 4
#define CONTROL_E 5
#define CONTROL_K 11
#define TAB 9
#define     MIN(a, b)   ((a) < (b) ? (a) : (b))
#define     MAX(a, b)   ((a) > (b) ? (a) : (b))

void TextMode(void);

static void ClearScreen(void);
static void PaintWindow(WINDOW*, char*, int, int, int, int);
static void PaintBox(WINDOW*, int, int, int, int);
static void PaintButton(WINDOW*, char*, int, int, int);
static void PrintWrap(WINDOW*, char*, int, int, int);
static int Dialog(char*, char*, int, int, char*, char*, int);
static void PaintItem(WINDOW*, char*, int, int);
static int DialogMenu(char*, char*, int, int, int, int, char**, char*, char*, int);
static void PaintCheckItem(WINDOW*, char*, int, int, int);
static int DialogCheckBox(char*, char*, int, int, int, int, char**, char*, char*, char*);
static char *DialogInput(char*, char*, int, int, char*, char*, char*, int);
static void PaintScroller(WINDOW*, int, int, int);

static int MouseConfig(void);
static int KeyboardConfig(void);
static int MonitorConfig(void);
static int CardConfig(void);
static int ScreenConfig(void);
static int LayoutConfig(void);
static int WriteXF86Config(void);

static XF86ConfLayoutPtr CopyLayout(XF86ConfLayoutPtr);
static XF86ConfAdjacencyPtr CopyAdjacency(XF86ConfAdjacencyPtr);
static XF86ConfInputrefPtr CopyInputref(XF86ConfInputrefPtr);
static XF86ConfInactivePtr CopyInactive(XF86ConfInactivePtr);
static void FreeLayout(XF86ConfLayoutPtr);

extern int string_to_parser_range(char*, parser_range*, int);
#define PARSER_RANGE_SIZE     256
/* string must have at least 256 bytes */
extern int parser_range_to_string(char*, parser_range*, int);

static Bool newconfig;

static chtype screen_attr = A_NORMAL;
static chtype dialog_attr = A_REVERSE;
static chtype highlight_border_attr = A_REVERSE;
static chtype shadow_border_attr = A_REVERSE;
static chtype title_attr = A_NORMAL;
static chtype button_active_attr = A_NORMAL;
static chtype button_inactive_attr = A_NORMAL;
static int menu_width, item_x;
static char Edit[] = "Edit ";

static char *main_menu[] = {
#define     CONF_MOUSE  0
    "Configure mouse",
#define     CONF_KEYBOARD     1
    "Configure keyboard",
#define     CONF_MONITOR      2
    "Configure monitor",
#define     CONF_CARD   3
    "Configure card",
#define     CONF_SCREEN 4
    "Configure screen",
#define     CONF_LAYOUT 5
    "Configure layout",
#define     CONF_FINISH 6
    "Write XF86Config and quit",
#define     CONF_QUIT   7
    "Quit",
};

void
TextMode(void)
{
    static int first = 1;
    int i, choice = CONF_MOUSE;

#ifdef USE_MODULES
    if (!nomodules)
      LoaderInitializeOptions();
#endif
    initscr();
    noecho();
    nonl();
    keypad(stdscr, TRUE);

    if (first) {
      const char *filename;

      first = 0;

      if (has_colors()) {
          start_color();
          init_pair(1, COLOR_BLACK, COLOR_BLACK);
          screen_attr = A_BOLD | COLOR_PAIR(1);

          init_pair(2, COLOR_BLACK, COLOR_WHITE);
          dialog_attr = COLOR_PAIR(2);

          init_pair(3, COLOR_BLACK, COLOR_WHITE);
          shadow_border_attr = A_BOLD | COLOR_PAIR(3);

          init_pair(4, COLOR_WHITE, COLOR_WHITE);
          highlight_border_attr = A_BOLD | COLOR_PAIR(4);

          init_pair(5, COLOR_WHITE, COLOR_BLUE);
          title_attr = A_BOLD | COLOR_PAIR(5);
          button_active_attr = title_attr;

          init_pair(6, COLOR_WHITE, COLOR_BLACK);
          button_inactive_attr = A_BOLD | COLOR_PAIR(6);
      }

      if ((filename = xf86openConfigFile(getuid() == 0 ?
                                 CONFPATH : USER_CONFPATH,
                                 XF86Config_path, NULL)) != NULL) {
          XF86Config_path = (char *)filename;
          if ((XF86Config = xf86readConfigFile()) == NULL) {
            ClearScreen();
            refresh();
            Dialog("Configuration error",
                   "Error parsing configuration file.",
                   7, 50, "  Ok  ", NULL, 0);
          }
      }
      if (XF86Config == NULL) {
          XF86Config = (XF86ConfigPtr)XtCalloc(1, sizeof(XF86ConfigRec));
          newconfig = True;
      }
      else
          newconfig = False;
    }

    ClearScreen();
    refresh();

    /*CONSTCOND*/
    while (1) {
      int cancel = FALSE;

      ClearScreen();
      refresh();
      if (Dialog("XFree86 Configuration",
               "This program will create the XF86Config file, based on "
               "menu selections you make.\n"
               "\n"
               "The XF86Config file usually resides in /usr/X11R6/etc/X11 "
               "or /etc/X11. A sample XF86Config file is supplied with "
               "XFree86; it is configured for a standard VGA card and "
               "monitor with 640x480 resolution. This program will ask for "
               "a pathname when it is ready to write the file.\n"
               "\n"
               "You can either take the sample XF86Config as a base and "
               "edit it for your configuration, or let this program "
               "produce a base XF86Config file for your configuration and "
               "fine-tune it.",
               20, 60, "   Ok   ", " Cancel ", 0) != 0)
          break;

          while (!cancel) {
            ClearScreen();
            refresh();
            switch (DialogMenu("Main menu",
                           "Choose one of the options:",
                           17, 60, 8, sizeof(main_menu) /
                           sizeof(main_menu[0]), main_menu,
                           "   Ok   ", " Cancel ", choice)) {
                case CONF_MOUSE:
                  i = MouseConfig();
                  if (i > 0 && choice == CONF_MOUSE)
                      choice = CONF_KEYBOARD;
                  else if (i == 0)
                      choice = CONF_MOUSE;
                  break;
                case CONF_KEYBOARD:
                  i = KeyboardConfig();
                  if (i > 0 && choice <= CONF_KEYBOARD)
                      choice = CONF_MONITOR;
                  else if (i == 0)
                      choice = CONF_KEYBOARD;
                  break;
                case CONF_MONITOR:
                  i = MonitorConfig();
                  if (i > 0 && choice <= CONF_MONITOR)
                      choice = CONF_CARD;
                  else if (i == 0)
                      choice = CONF_MONITOR;
                  break;
                case CONF_CARD:
                  i = CardConfig();
                  if (i > 0 && choice <= CONF_CARD)
                      choice = CONF_SCREEN;
                  else if (i == 0)
                      choice = CONF_CARD;
                  break;
                case CONF_SCREEN:
                  i = ScreenConfig();
                  if (i > 0 && choice <= CONF_SCREEN)
                      choice = CONF_LAYOUT;
                  else if (i == 0)
                      choice = CONF_SCREEN;
                  break;
                case CONF_LAYOUT:
                  i = LayoutConfig();
                  if (i > 0 && choice <= CONF_LAYOUT)
                      choice = CONF_FINISH;
                  else if (i == 0)
                      choice = CONF_LAYOUT;
                  break;
                case CONF_FINISH:
                  if (WriteXF86Config() < 0)
                      break;
                /*FALLTROUGH*/
                case CONF_QUIT:
                  endwin();
                  exit(0);
                default:
                  cancel = TRUE;
                  break;
            }
      }
    }

    endwin();
}

static int
WriteXF86Config(void)
{
    char *xf86config;

    ClearScreen();
    refresh();
    xf86config = DialogInput("Write XF86Config", "Write configuration to file:",
                       10, 60, XF86Config_path ? XF86Config_path :
                       "/etc/X11/XF86Config", "  Ok  ", " Cancel ", 0);

    if (xf86config == NULL)
      return (-1);

    if (newconfig) {
      if (XF86Config->conf_modules == NULL) {
          static char *modules[] = {"extmod", "glx", "dri", "dbe",
                              "record", "xtrap", "type1", "speedo"};
          XF86LoadPtr load;
          int i;

          XF86Config->conf_modules = (XF86ConfModulePtr)
            XtCalloc(1, sizeof(XF86ConfModuleRec));

          XF86Config->conf_modules->mod_comment =
            XtNewString("\t# Load \"freetype\"\n"
                      "\t# Load \"xtt\"\n");

          for (i = 0; i < sizeof(modules) / sizeof(modules[0]); i++) {
            load = (XF86LoadPtr)XtCalloc(1, sizeof(XF86LoadRec));
            load->load_name = XtNewString(modules[i]);
            XF86Config->conf_modules->mod_load_lst =
                xf86addModule(XF86Config->conf_modules->mod_load_lst, load);
          }
      }
    }

    if (!xf86writeConfigFile(xf86config, XF86Config)) {
      char msg[1024];

      XmuSnprintf(msg, sizeof(msg), "Failed to write configuration file %s.",
               xf86config);
      ClearScreen();
      refresh();
      (void)Dialog("Write failed!", msg, 8, 60, "  Ok  ", NULL, 0);
      XtFree(xf86config);
      return (-1);
    }
    XtFree(xf86config);

    return (1);
}

static char *protocols[] = {
#ifdef SCO
    "OsMouse",
#endif
#ifdef WSCONS_SUPPORT
    "wsmouse",
#endif
    "Auto",
    "SysMouse",
    "MouseSystems",
    "BusMouse",
    "PS/2",
    "Microsoft",
#ifndef __FreeBSD__
    "ImPS/2",
    "ExplorerPS/2",
    "GlidePointPS/2",
    "MouseManPlusPS/2",
    "NetMousePS/2",
    "NetScrollPS/2",
    "ThinkingMousePS/2",
#endif
    "AceCad",
    "GlidePoint",
    "IntelliMouse",
    "Logitech",
    "MMHitTab",
    "MMSeries",
    "MouseMan",
    "ThinkingMouse",
};

static int
MouseConfig(void)
{
    int i, nlist, def, proto, emul;
    char **list = NULL, *device, *str;
    XF86ConfInputPtr *inputs = NULL;
    XF86ConfInputPtr input = XF86Config->conf_input_lst;
    XF86OptionPtr option;

    nlist = 0;
    while (input) {
      if (strcmp(input->inp_driver, "mouse") == 0) {
          list = (char**)XtRealloc((XtPointer)list, (nlist + 1) * sizeof(char*));
          list[nlist] = XtMalloc(sizeof(Edit) +
                           strlen(input->inp_identifier) + 1);
          sprintf(list[nlist], "%s%s", Edit, input->inp_identifier);
          inputs = (XF86ConfInputPtr*)XtRealloc((XtPointer)inputs, (nlist + 1) *
                              sizeof(XF86ConfInputPtr));
          inputs[nlist] = input;
          ++nlist;
      }
      input = (XF86ConfInputPtr)(input->list.next);
    }

    input = NULL;

    if (nlist) {
      list = (char**)XtRealloc((XtPointer)list, (nlist + 2) * sizeof(char*));
      list[nlist++] = XtNewString("Add new mouse");
      if (nlist == 2) {
          i = strlen("Remove ") + strlen(inputs[0]->inp_identifier) + 1;
          list[nlist] = XtMalloc(i);
          XmuSnprintf(list[nlist], i, "Remove %s", inputs[0]->inp_identifier);
          ++nlist;
      }
      else
          list[nlist++] = XtNewString("Remove mouse");
      ClearScreen();
      refresh();
      i = DialogMenu("Mouse configuration",
                   "You can edit or remove a previously configured mouse, "
                   "or add a new one.", 14, 60, 4, nlist, list,
                   " Ok  ", " Cancel ", 0);
      if (i < 0) {
          for (i = 0; i < nlist; i++)
            XtFree(list[i]);
          XtFree((XtPointer)list);
          XtFree((XtPointer)inputs);
          return (-1);
      }
      if (nlist > 2 && i == nlist - 1) {
          if (nlist > 3) {
            for (i = 0; i < nlist - 2; i++) {
                /* XXX Remove the "Edit " from list entries */
                memmove(list[i], list[i] + sizeof(Edit) - 1,
                      strlen(list[i]) - sizeof(Edit) + 2);
            }
            ClearScreen();
            refresh();
            i = DialogMenu("Remove mouse",
                         "Select which mouse to remove",
                         13, 60, 4, nlist - 2, list,
                         " Remove ", " Cancel ", 0);
            if (i < 0) {
                for (i = 0; i < nlist; i++)
                  XtFree(list[i]);
                XtFree((XtPointer)list);
                XtFree((XtPointer)inputs);
                return (-1);
            }
            input = inputs[i];
          }
          else
            input = inputs[0];
          for (i = 0; i < nlist; i++)
            XtFree(list[i]);
          XtFree((XtPointer)list);
          XtFree((XtPointer)inputs);
          xf86removeInput(XF86Config, input);
          return (0);
      }
      if (i < nlist - 2)
          input = inputs[i];
    }
    for (i = 0; i < nlist; i++)
      XtFree(list[i]);
    XtFree((XtPointer)list);
    XtFree((XtPointer)inputs);

    if (input == NULL) {
      char label[32];

      input = (XF86ConfInputPtr)XtCalloc(1, sizeof(XF86ConfInputRec));
      XmuSnprintf(label, sizeof(label), "Mouse%d", nlist ? nlist - 2 : 0);
      ClearScreen();
      refresh();
      input->inp_identifier =
          DialogInput("Mouse identifier",
                  "Enter an identifier for your mouse definition:",
                  11, 40, label,
                  " Next >>", " Cancel ", 0);
      if (input->inp_identifier == NULL) {
          XtFree((XtPointer)input);
          return (-1);
      }
    }

    def = 0;
    option = xf86findOption(input->inp_option_lst, "Protocol");
    if (option)
      for (i = 0; i < sizeof(protocols)/sizeof(protocols[0]); i++)
          if (strcasecmp(option->opt_val, protocols[i]) == 0) {
            def = i;
            break;
          }

    ClearScreen();
    refresh();
    i = DialogMenu("Select mouse protocol",
               "If you have a serial mouse, it probably will work with "
               "the \"Auto\" protocol. But, if it is an old serial "
               "mouse probably it is not PNP; in that case, most serial "
               "mouses understand the \"Microsoft\" protocol.",
               19, 60, 7, sizeof(protocols) /
               sizeof(protocols[0]), protocols, " Next >>", " Cancel ", def);
    if (i < 0) {
      if (input->inp_driver == NULL) {
          XtFree(input->inp_driver);
          XtFree((XtPointer)input);
      }
      return (i);
    }
    proto = i;

    def = 0;
    if (input->inp_driver) {
      option = xf86findOption(input->inp_option_lst, "Emulate3Buttons");
      def = option ? 0 : 1;
    }
    ClearScreen();
    refresh();
    i = Dialog("Mouse 3 buttons emulation",
             "If your mouse has only two buttons, it is recommended that "
             "you enable Emulate3Buttons.\n"
             "\n"
             "Do you want to enable Emulate3Buttons?",
             10, 60, " Yes ", " No ", def);
    if (i < 0)
      return (i);
    emul = !i;

    str = NULL;
    option = xf86findOption(input->inp_option_lst, "Device");
    if (option)
      str = option->opt_val;
    if (str == NULL)
#ifdef WSCONS_SUPPORT
      str = "/dev/wsmouse";
#elif defined(__FreeBSD__)
      str = "/dev/sysmouse";
#else
      str = "/dev/mouse";
#endif

    ClearScreen();
    refresh();
    device = DialogInput("Select mouse device",
                   "Enter mouse device:", 10, 40, str,
                   " Finish ", " Cancel ", 0);
    if (device == NULL) {
      if (input->inp_driver == NULL) {
          XtFree(input->inp_driver);
          XtFree((XtPointer)input);
      }
      return (-1);
    }

    /* Finish mouse configuration */
    option = xf86findOption(input->inp_option_lst, "Protocol");
    if (option) {
      XtFree((XtPointer)option->opt_val);
      option->opt_val = XtNewString(protocols[proto]);
    }
    else
      input->inp_option_lst = xf86addNewOption(input->inp_option_lst,
            XtNewString("Protocol"), XtNewString(protocols[proto]));

    option = xf86findOption(input->inp_option_lst, "Emulate3Buttons");
    if (option && !emul) {
      xf86removeOption(&input->inp_option_lst, "Emulate3Buttons");
    }
    else if (option == NULL && emul)
      input->inp_option_lst = xf86addNewOption(input->inp_option_lst,
            XtNewString("Emulate3Buttons"), NULL);

    option = xf86findOption(input->inp_option_lst, "Device");
    if (option) {
      XtFree((XtPointer)option->opt_val);
      option->opt_val = device;
    }
    else
      input->inp_option_lst = xf86addNewOption(input->inp_option_lst,
            XtNewString("Device"), device);

    if (input->inp_driver == NULL) {
      input->inp_driver = XtNewString("mouse");
      XF86Config->conf_input_lst =
          xf86addInput(XF86Config->conf_input_lst, input);
    }

    return (1);
}

static int
KeyboardConfig(void)
{
    int i;
    char *rulesfile;
    static int first = 1;
    static XkbRF_RulesPtr rules;
    static char **models, **layouts;
    XF86ConfInputPtr *inputs = NULL, input = XF86Config->conf_input_lst;
    char **list = NULL, *model, *layout;
    int nlist, def;
    XF86OptionPtr option;

    nlist = 0;
    while (input) {
      if (strcmp(input->inp_driver, "keyboard") == 0) {
          list = (char**)XtRealloc((XtPointer)list, (nlist + 1) * sizeof(char*));
          list[nlist] = XtMalloc(sizeof(Edit) +
                           strlen(input->inp_identifier) + 1);
          sprintf(list[nlist], "%s%s", Edit, input->inp_identifier);
          inputs = (XF86ConfInputPtr*)XtRealloc((XtPointer)inputs, (nlist + 1) *
                              sizeof(XF86ConfInputPtr));
          inputs[nlist] = input;
          ++nlist;
      }
      input = (XF86ConfInputPtr)(input->list.next);
    }

    input = NULL;

    if (nlist) {
      list = (char**)XtRealloc((XtPointer)list, (nlist + 2) * sizeof(char*));
      list[nlist++] = XtNewString("Add new keyboard");
      if (nlist == 2) {
          i = strlen("Remove ") + strlen(inputs[0]->inp_identifier) + 1;
          list[nlist] = XtMalloc(i);
          XmuSnprintf(list[nlist], i, "Remove %s", inputs[0]->inp_identifier);
          ++nlist;
      }
      else
          list[nlist++] = XtNewString("Remove keyboard");
      ClearScreen();
      refresh();
      i = DialogMenu("Keyboard configuration",
                   "You can edit or remove a previously configured "
                   "keyboard, or add a new one.", 14, 60, 4, nlist, list,
                   " Ok  ", " Cancel ", 0);
      if (i < 0) {
          for (i = 0; i < nlist; i++)
            XtFree(list[i]);
          XtFree((XtPointer)list);
          XtFree((XtPointer)inputs);
          return (-1);
      }
      if (nlist > 2 && i == nlist - 1) {
          if (nlist > 3) {
            for (i = 0; i < nlist - 2; i++) {
                /* XXX Remove the "Edit " from list entries */
                memmove(list[i], list[i] + sizeof(Edit) - 1,
                      strlen(list[i]) - sizeof(Edit) + 2);
            }
            ClearScreen();
            refresh();
            i = DialogMenu("Remove keyboard",
                         "Select which keyboard to remove",
                         13, 60, 4, nlist - 2, list,
                         " Remove ", " Cancel ", 0);
            if (i < 0) {
                for (i = 0; i < nlist; i++)
                  XtFree(list[i]);
                XtFree((XtPointer)list);
                XtFree((XtPointer)inputs);
                return (-1);
            }
            input = inputs[i];
          }
          else
            input = inputs[0];
          for (i = 0; i < nlist; i++)
            XtFree(list[i]);
          XtFree((XtPointer)list);
          XtFree((XtPointer)inputs);
          xf86removeInput(XF86Config, input);
          return (0);
      }
      if (i < nlist - 2)
          input = inputs[i];
    }
    for (i = 0; i < nlist; i++)
      XtFree(list[i]);
    XtFree((XtPointer)list);
    XtFree((XtPointer)inputs);

    if (input == NULL) {
      char label[32];

      input = (XF86ConfInputPtr)XtCalloc(1, sizeof(XF86ConfInputRec));
      XmuSnprintf(label, sizeof(label), "Keyboard%d", nlist ? nlist - 2 : 0);
      ClearScreen();
      refresh();
      input->inp_identifier =
          DialogInput("Keyboard identifier",
                  "Enter an identifier for your keyboard definition:",
                  11, 40, label,
                  " Next >>", " Cancel ", 0);
      if (input->inp_identifier == NULL) {
          XtFree((XtPointer)input);
          return (-1);
      }
    }

    if (first) {
      first = 0;
#ifdef XFREE98_XKB
      rulesfile = XKB_RULES_DIR "/xfree98";
#else
      rulesfile = XKB_RULES_DIR "/xfree86";
#endif
      rules = XkbRF_Load(rulesfile, "", True, False);
      if (rules == NULL) {
          ClearScreen();
          refresh();
          Dialog("Configuration error",
               "XKB rules file not found.\n"
               "\n"
               "Keyboard XKB options will be set to default values.",
               10, 50, "  Ok  ", NULL, 0);
          if (input->inp_driver == NULL) {
            input->inp_option_lst =
                xf86addNewOption(input->inp_option_lst,
                  XtNewString("XkbModel"), XtNewString("pc101"));
            input->inp_option_lst =
                xf86addNewOption(input->inp_option_lst,
                  XtNewString("XkbLayout"), XtNewString("us"));
            input->inp_driver = XtNewString("keyboard");
            XF86Config->conf_input_lst =
                xf86addInput(XF86Config, input);
          }
          return (0);
      }
      models = (char**)XtMalloc(sizeof(char*) * rules->models.num_desc);
      for (i = 0; i < rules->models.num_desc; i++)
          models[i] = XtNewString(rules->models.desc[i].desc);
      layouts = (char**)XtMalloc(sizeof(char*) * rules->layouts.num_desc);
      for (i = 0; i < rules->layouts.num_desc; i++)
          layouts[i] = XtNewString(rules->layouts.desc[i].desc);
    }
    else if (rules == NULL)
      return (-1);

    def = 0;
    option = xf86findOption(input->inp_option_lst, "XkbModel");
    if (option) {
      for (i = 0; i < rules->models.num_desc; i++)
          if (strcasecmp(option->opt_val, rules->models.desc[i].name) == 0) {
            def = i;
            break;
          }
    }
    ClearScreen();
    refresh();
    i = DialogMenu("Keyboard model",
               "Please select one of the following keyboard types that is "
               "the better description of your keyboard. If nothing really "
               "matches, choose \"Generic 101-key PC\".\n",
               20, 60, 9, rules->models.num_desc,
               models, " Next >>", " Cancel ", def);
    if (i < 0)
      return (i);
    model = rules->models.desc[i].name;

    def = 0;
    option = xf86findOption(input->inp_option_lst, "XkbLayout");
    if (option) {
      for (i = 0; i < rules->layouts.num_desc; i++)
          if (strcasecmp(option->opt_val, rules->layouts.desc[i].name) == 0) {
            def = i;
            break;
          }
    }
    ClearScreen();
    refresh();
    i = DialogMenu("Keyboard layout",
               "Select keyboard layout:",
               20, 60, 11, rules->layouts.num_desc,
               layouts, " Finish ", " Cancel ", def);
    if (i < 0)
      return (i);
    layout = rules->layouts.desc[i].name;

    /* Finish keyboard configuration */
    option = xf86findOption(input->inp_option_lst, "XkbModel");
    if (option) {
      XtFree((XtPointer)option->opt_val);
      option->opt_val = XtNewString(model);
    }
    else
      input->inp_option_lst = xf86addNewOption(input->inp_option_lst,
            XtNewString("XkbModel"), XtNewString(model));

    option = xf86findOption(input->inp_option_lst, "XkbLayout");
    if (option) {
      XtFree((XtPointer)option->opt_val);
      option->opt_val = XtNewString(layout);
    }
    else
      input->inp_option_lst = xf86addNewOption(input->inp_option_lst,
            XtNewString("XkbLayout"), XtNewString(layout));

    if (input->inp_driver == NULL) {
      input->inp_driver = XtNewString("keyboard");
      XF86Config->conf_input_lst =
          xf86addInput(XF86Config->conf_input_lst, input);
    }

    return (1);
}

static char *hsync[] = {
#define     CONF_MONITOR_HSYNC      0
    "Enter your own horizontal sync range",
    "31.5; Standard VGA, 640x480 @ 60 Hz",
    "31.5 - 35.1; Super VGA, 800x600 @ 56 Hz",
    "31.5, 35.5; 8514 Compatible, 1024x768 @ 87 Hz interlaced (no 800x600)",
    "31.5, 35.15, 35.5; Super VGA, 1024x768 @ 87 Hz int., 800x600 @ 56 Hz",
    "31.5 - 37.9; Extended Super VGA, 800x600 @ 60 Hz, 640x480 @ 72 Hz",
    "31.5 - 48.5; Non-Interlaced SVGA, 1024x768 @ 60 Hz, 800x600 @ 72 Hz",
    "31.5 - 57.0; High Frequency SVGA, 1024x768 @ 70 Hz",
    "31.5 - 64.3; Monitor that can do 1280x1024 @ 60 Hz",
    "31.5 - 79.0; Monitor that can do 1280x1024 @ 74 Hz",
    "31.5 - 82.0; Monitor that can do 1280x1024 @ 76 Hz",
};

static char *vrefresh[] = {
#define     CONF_MONITOR_VREFRESH   0
    "Enter your own vertical sync range",
    "50 - 70",
    "50 - 90",
    "50 - 100",
    "40 - 150",
};

static int
MonitorConfig(void)
{
    int i;
    XF86ConfMonitorPtr *monitors = NULL, monitor = XF86Config->conf_monitor_lst;
    char **list = NULL, *identifier = NULL, *tmp;
    int nlist, def;
    char hsync_str[256], vrefresh_str[256];

    hsync_str[0] = vrefresh_str[0] = '\0';
    nlist = 0;
    while (monitor) {
      list = (char**)XtRealloc((XtPointer)list, (nlist + 1) * sizeof(char*));
      list[nlist] = XtMalloc(sizeof(Edit) +
                         strlen(monitor->mon_identifier) + 1);
      sprintf(list[nlist], "%s%s", Edit, monitor->mon_identifier);
      monitors = (XF86ConfMonitorPtr*)XtRealloc((XtPointer)monitors, (nlist + 1) *
                            sizeof(XF86ConfMonitorPtr));
      monitors[nlist] = monitor;
      ++nlist;
      monitor = (XF86ConfMonitorPtr)(monitor->list.next);
    }

    monitor = NULL;

    if (nlist) {
      list = (char**)XtRealloc((XtPointer)list, (nlist + 2) * sizeof(char*));
      list[nlist++] = XtNewString("Add new monitor");
      if (nlist == 2) {
          i = strlen("Remove ") + strlen(monitors[0]->mon_identifier) + 1;
          list[nlist] = XtMalloc(i);
          XmuSnprintf(list[nlist], i, "Remove %s", monitors[0]->mon_identifier);
          ++nlist;
      }
      else
          list[nlist++] = XtNewString("Remove monitor");
      ClearScreen();
      refresh();
      i = DialogMenu("Monitor configuration",
                   "You can edit or remove a previously configured "
                   "monitor, or add a new one.", 14, 60, 4, nlist, list,
                   " Ok  ", " Cancel ", 0);
      if (i < 0) {
          for (i = 0; i < nlist; i++)
            XtFree(list[i]);
          XtFree((XtPointer)list);
          XtFree((XtPointer)monitors);
          return (-1);
      }
      if (nlist > 2 && i == nlist - 1) {
          if (nlist > 3) {
            for (i = 0; i < nlist - 2; i++) {
                /* XXX Remove the "Edit " from list entries */
                memmove(list[i], list[i] + sizeof(Edit) - 1,
                      strlen(list[i]) - sizeof(Edit) + 2);
            }
            ClearScreen();
            refresh();
            i = DialogMenu("Remove monitor",
                         "Select which monitor to remove",
                         13, 60, 4, nlist - 2, list,
                         " Remove ", " Cancel ", 0);
            if (i < 0) {
                for (i = 0; i < nlist; i++)
                  XtFree(list[i]);
                XtFree((XtPointer)list);
                XtFree((XtPointer)monitors);
                return (-1);
            }
            monitor = monitors[i];
          }
          else
            monitor = monitors[0];
          for (i = 0; i < nlist; i++)
            XtFree(list[i]);
          XtFree((XtPointer)list);
          XtFree((XtPointer)monitors);
          xf86removeMonitor(XF86Config, monitor);
          return (0);
      }
      if (i < nlist - 2)
          monitor = monitors[i];
    }
    for (i = 0; i < nlist; i++)
      XtFree(list[i]);
    XtFree((XtPointer)list);
    XtFree((XtPointer)monitors);

    if (monitor == NULL) {
      char label[32];

      monitor = (XF86ConfMonitorPtr)XtCalloc(1, sizeof(XF86ConfMonitorRec));
      XmuSnprintf(label, sizeof(label), "Monitor%d", nlist ? nlist - 2 : 0);
      ClearScreen();
      refresh();
      identifier =
          DialogInput("Monitor identifier",
                  "Enter an identifier for your monitor definition:",
                  11, 40, label,
                  " Next >>", " Cancel ", 0);
      if (identifier == NULL) {
          XtFree((XtPointer)monitor);
          return (-1);
      }
    }

    if (monitor->mon_identifier == NULL) {
      ClearScreen();
      refresh();
      i = Dialog("Monitor configuration",
               "Now we want to set the specifications of the monitor. The "
               "two critical parameters are the vertical refresh rate, which "
               "is the rate at which the whole screen is refreshed, and most "
               "importantly the horizontal sync rate, which is the rate at "
               "which scanlines are displayed.\n"
               "\n"
               "The valid range for horizontal sync and vertical sync should "
               "be documented in the manual of your monitor.",
               15, 60, " Next >>", " Cancel ", 0);
      if (i != 0) {
          XtFree(identifier);
          XtFree((XtPointer)monitor);
          return (-1);
      }
    }

    def = 0;
    if (monitor->mon_identifier) {
      int len;

      parser_range_to_string(hsync_str, &(monitor->mon_hsync[0]),
                         monitor->mon_n_hsync);
      len = strlen(hsync_str);
      for (i = 1; i < sizeof(hsync) / sizeof(hsync[0]); i++) {
          tmp = strchr(hsync[i], ';');
          if (strncmp(hsync_str, hsync[i], len) == 0) {
            def = i;
            break;
          }
      }
    }
    if (hsync_str[0] == '\0')
      strcpy(hsync_str, "31.5");

    ClearScreen();
    refresh();
    i = DialogMenu("Monitor HorizSync",
               "You must indicate the horizontal sync range of your "
               "monitor. You can either select one of the predefined "
               "ranges below that correspond to industry-standard monitor "
               "types, or give a specific range.",
               22, 78, 11, sizeof(hsync) /
               sizeof(hsync[0]), hsync, " Next >>", " Cancel ", def);
    if (i < 0) {
      if (monitor->mon_identifier == NULL) {
          XtFree(identifier);
          XtFree((XtPointer)monitor);
      }
      return (-1);
    }
    if (i == CONF_MONITOR_HSYNC) {
      ClearScreen();
      refresh();
      tmp = DialogInput("Monitor HorizSync",
                    "Please enter the horizontal sync range of your "
                    "monitor, in the format used in the table of monitor "
                    "types above. You can either specify one or more "
                    "continuous ranges (e.g. 15-25, 30-50), or one or more "
                    "fixed sync frequencies.\n"
                    "\n"
                    "Horizontal sync range:", 16, 62, hsync_str,
                    "  Ok  ", " Cancel ", def);
      if (tmp == NULL) {
          if (monitor->mon_identifier == NULL) {
            XtFree(identifier);
            XtFree((XtPointer)monitor);
          }
          return (-1);
      }
      XmuSnprintf(hsync_str, sizeof(hsync_str), "%s", tmp);
      XtFree(tmp);
    }
    else {
      tmp = strchr(hsync[i], ';');
      strncpy(hsync_str, hsync[i], tmp - hsync[i]);
      hsync_str[tmp - hsync[i]] = '\0';
    }

    def = 0;
    if (monitor->mon_identifier) {
      parser_range_to_string(vrefresh_str, &(monitor->mon_vrefresh[0]),
                         monitor->mon_n_vrefresh);
      for (i = 1; i < sizeof(vrefresh) / sizeof(vrefresh[0]); i++) {
          if (strcmp(vrefresh_str, vrefresh[i]) == 0) {
            def = i;
            break;
          }
      }
    }
    if (vrefresh_str[0] == '\0')
      strcpy(vrefresh_str, "50 - 70");
    ClearScreen();
    refresh();
    i = DialogMenu("Monitor VertRefresh",
               "You must indicate the vertical sync range of your monitor. "
               "You can either select one of the predefined ranges below "
               "that correspond to industry-standard monitor types, or "
               "give a specific range. For interlaced modes, the number "
               "that counts is the high one (e.g. 87 Hz rather than 43 Hz).",
               19, 60, 5, sizeof(vrefresh) /
               sizeof(vrefresh[0]), vrefresh, " Finish ", " Cancel ", def);
    if (i < 0) {
      if (monitor->mon_identifier == NULL) {
          XtFree(identifier);
          XtFree((XtPointer)monitor);
      }
      return (i);
    }
    if (i == CONF_MONITOR_VREFRESH) {
      ClearScreen();
      refresh();
      tmp = DialogInput("Monitor VertRefresh",
                    "Vertical sync range:", 10, 50, vrefresh_str,
                    " Done ", " Cancel ", 0);
      if (tmp == NULL) {
          if (monitor->mon_identifier == NULL) {
            XtFree(identifier);
            XtFree((XtPointer)monitor);
          }
          return (-1);
      }
      XmuSnprintf(vrefresh_str, sizeof(vrefresh_str), "%s", tmp);
      XtFree(tmp);
    }
    else
      strcpy(vrefresh_str, vrefresh[i]);

    /* Finish monitor configuration */
    monitor->mon_n_hsync = string_to_parser_range(hsync_str,
      &(monitor->mon_hsync[0]), CONF_MAX_HSYNC);
    monitor->mon_n_vrefresh = string_to_parser_range(vrefresh_str,
      &(monitor->mon_vrefresh[0]), CONF_MAX_VREFRESH);
    if (monitor->mon_identifier == NULL) {
      monitor->mon_identifier = identifier;
      XF86Config->conf_monitor_lst =
          xf86addMonitor(XF86Config->conf_monitor_lst, monitor);
    }

    return (1);
}

static int
CardConfig(void)
{
    int i;
    XF86ConfDevicePtr *devices = NULL, device = XF86Config->conf_device_lst;
    char **list = NULL, *identifier = NULL, *driver, *busid, *tmp;
    int nlist, def;
    CardsEntry *entry = NULL;
    static char **drivers;
    static int ndrivers;
    static char *xdrivers[] = {
      "apm",
      "ark",
      "ati",
      "r128",
      "radeon",
      "chips",
      "cirrus",
      "cyrix",
      "fbdev",
      "glint",
      "i128",
      "i740",
      "i810",
      "imstt",
      "mga",
      "neomagic",
      "nv",
      "rendition",
      "s3",
      "s3virge",
      "savage",
      "siliconmotion",
      "sis",
      "tdfx",
      "tga",
      "trident",
      "tseng",
      "vmware",
      "vga",
      "vesa",
    };

#ifdef USE_MODULES
    if (!nomodules) {
      xf86cfgModuleOptions *opts = module_options;

      drivers = NULL;
      ndrivers = 0;
      while (opts) {
          if (opts->type == VideoModule) {
            ++ndrivers;
            drivers = (char**)XtRealloc((XtPointer)drivers,
                                  ndrivers * sizeof(char*));
            /* XXX no private copy */
            drivers[ndrivers - 1] = opts->name;
          }
          opts = opts->next;
      }
    }
    else
#endif
    {
      ndrivers = sizeof(xdrivers) / sizeof(xdrivers[0]);
      drivers = xdrivers;
    }

    nlist = 0;
    while (device) {
      list = (char**)XtRealloc((XtPointer)list, (nlist + 1) * sizeof(char*));
      list[nlist] = XtMalloc(sizeof(Edit) +
                         strlen(device->dev_identifier) + 1);
      sprintf(list[nlist], "%s%s", Edit, device->dev_identifier);
      devices = (XF86ConfDevicePtr*)XtRealloc((XtPointer)devices, (nlist + 1) *
                            sizeof(XF86ConfDevicePtr));
      devices[nlist] = device;
      ++nlist;
      device = (XF86ConfDevicePtr)(device->list.next);
    }

    device = NULL;

    if (nlist) {
      list = (char**)XtRealloc((XtPointer)list, (nlist + 2) * sizeof(char*));
      list[nlist++] = XtNewString("Add new card");
      if (nlist == 2) {
          i = strlen("Remove ") + strlen(devices[0]->dev_identifier) + 1;
          list[nlist] = XtMalloc(i);
          XmuSnprintf(list[nlist], i, "Remove %s", devices[0]->dev_identifier);
          ++nlist;
      }
      else
          list[nlist++] = XtNewString("Remove device");
      ClearScreen();
      refresh();
      i = DialogMenu("Card configuration",
                   "You can edit or remove a previously configured "
                   "card, or add a new one.", 14, 60, 4, nlist, list,
                   " Ok  ", " Cancel ", 0);
      if (i < 0) {
          for (i = 0; i < nlist; i++)
            XtFree(list[i]);
          XtFree((XtPointer)list);
          XtFree((XtPointer)devices);
          return (-1);
      }
      if (nlist > 2 && i == nlist - 1) {
          if (nlist > 3) {
            for (i = 0; i < nlist - 2; i++) {
                /* XXX Remove the "Edit " from list entries */
                memmove(list[i], list[i] + sizeof(Edit) - 1,
                      strlen(list[i]) - sizeof(Edit) + 2);
            }
            ClearScreen();
            refresh();
            i = DialogMenu("Remove card",
                         "Select which card to remove",
                         13, 60, 4, nlist - 2, list,
                         " Remove ", " Cancel ", 0);
            if (i < 0) {
                for (i = 0; i < nlist; i++)
                  XtFree(list[i]);
                XtFree((XtPointer)list);
                XtFree((XtPointer)devices);
                return (-1);
            }
            device = devices[i];
          }
          else
            device = devices[0];
          for (i = 0; i < nlist; i++)
            XtFree(list[i]);
          XtFree((XtPointer)list);
          XtFree((XtPointer)devices);
          xf86removeDevice(XF86Config, device);
          return (0);
      }
      if (i < nlist - 2)
          device = devices[i];
    }
    for (i = 0; i < nlist; i++)
      XtFree(list[i]);
    XtFree((XtPointer)list);
    XtFree((XtPointer)devices);

    if (device == NULL) {
      char label[32];

      device = (XF86ConfDevicePtr)XtCalloc(1, sizeof(XF86ConfDeviceRec));
      device->dev_chipid = device->dev_chiprev = device->dev_irq = -1;
      XmuSnprintf(label, sizeof(label), "Card%d", nlist ? nlist - 2 : 0);
      ClearScreen();
      refresh();
      identifier =
          DialogInput("Card identifier",
                  "Enter an identifier for your card definition:",
                  11, 40, label,
                  " Next >>", " Cancel ", 0);
      if (identifier == NULL) {
          XtFree((XtPointer)device);
          return (-1);
      }
    }

    ClearScreen();
    refresh();
    if (Dialog("Card configuration",
             "Now we must configure video card specific settings. At this "
             "point you can choose to make a selection out of a database of "
             "video card definitions.\n"
             "\n"
             "The database entries include information about the chipset, "
             "what driver to run, the Ramdac and ClockChip, and comments "
             "that will be included in the Device section. However, a lot "
             "of definitions only hint about what driver to run (based on "
             "the chipset the card uses) and are untested.\n"
             "\n"
             "Do you want to look at the card database?",
             18, 60, " Yes ", " No ", device->dev_identifier != NULL) == 0) {
      static char **cards;
      static int ncards;

      if (cards == NULL) {
          ReadCardsDatabase();
          cards = GetCardNames(&ncards);
          cards = (char**)XtRealloc((XtPointer)cards,
                              (ncards + 1) * sizeof(char*));
          for (i = ncards; i > 0; i--)
            cards[i] = cards[i - 1];
          cards[0] = "** Unlisted card **";
          ++ncards;
      }
      if (device->dev_card)
          entry = LookupCard(device->dev_card);
      def = 0;
      if (entry) {
          for (i = 0; i < NumCardsEntry; i++)
            if (strcasecmp(CardsDB[i]->name, entry->name) == 0) {
                def = i + 1;
                break;
            }
          /* make sure entry is set to null again */
          entry = NULL;
      }

      i = DialogMenu("Card database",
                   "Select name that better matches your card:",
                   20, 70, 11, ncards, cards, "Next >>", " Cancel ", def);
      if (i > 0)
          entry = LookupCard(cards[i]);
    }

    def = 0;
    tmp = device->dev_driver ? device->dev_driver : entry && entry->driver ?
        entry->driver : "vga";
    for (i = 0; i < ndrivers; i++)
      if (strcmp(drivers[i], tmp) == 0) {
          def = i;
          break;
      }

    ClearScreen();
    refresh();
    i = DialogMenu("Card driver",
               "You can select the driver for your card here, or just press "
               "Enter to use the default/current:", 20, 50, 9,
               ndrivers, drivers, "  Ok  ", " Cancel ", def);
    if (i < 0) {
      if (device->dev_identifier == NULL) {
          XtFree(identifier);
          XtFree((XtPointer)device);
      }
      return (-1);
    }
    driver = ndrivers ? drivers[i] : "vga";

    ClearScreen();
    refresh();
    tmp = device->dev_busid ? device->dev_busid : "";
    busid = DialogInput("Card BusID",
                  "You normally does not need to fill this field "
                  "if you have only one video card:", 11, 50, tmp,
                  " Finish ", " Cancel ", 0);

    /* Finish card configuration */
    if (entry) {
      XtFree(device->dev_card);
      device->dev_card = XtNewString(entry->name);
      if (entry->chipset) {
          XtFree(device->dev_chipset);
          device->dev_chipset = XtNewString(entry->chipset);
      }
      if (entry->ramdac) {
          XtFree(device->dev_ramdac);
          device->dev_ramdac = XtNewString(entry->ramdac);
      }
      if (entry->clockchip) {
          XtFree(entry->clockchip);
          device->dev_clockchip = XtNewString(entry->clockchip);
      }
    }
    if (busid) {
      XtFree(device->dev_busid);
      if (*busid)
          device->dev_busid = busid;
      else {
          device->dev_busid = NULL;
          XtFree(busid);
      }
    }
    XtFree(device->dev_driver);
    device->dev_driver = XtNewString(driver);
    if (device->dev_identifier == NULL) {
      device->dev_identifier = identifier;
      XF86Config->conf_device_lst =
          xf86addDevice(XF86Config->conf_device_lst, device);
    }

    return (1);
}

static char *depths[] = {
    "1 bit, monochrome",
    "4 bit, 16 colors",
    "8 bit, 256 colors",
    "15 bits, 32Kb colors",
    "16 bits, 65Kb colors",
    "24 bits, 16Mb colors",
};

static char *modes[] = {
    "1600x1200",
    "1400x1050",
    "1280x1024",
    "1280x960",
    "1152x864",
    "1024x768",
    "800x600",
    "640x480",
    "640x400",
    "512x384",
    "400x300",
    "320x240",
    "320x200",
};

static int
ScreenConfig(void)
{
    int i, disp_allocated;
    XF86ConfScreenPtr *screens = NULL, screen = XF86Config->conf_screen_lst;
    char **list = NULL, *identifier = NULL;
    int nlist, def;
    XF86ConfDevicePtr device = NULL;
    XF86ConfMonitorPtr monitor = NULL;
    XF86ConfDisplayPtr display;
    XF86ModePtr mode, ptr = NULL;
    char *checks;

    nlist = 0;
    while (screen) {
      list = (char**)XtRealloc((XtPointer)list, (nlist + 1) * sizeof(char*));
      list[nlist] = XtMalloc(sizeof(Edit) +
                         strlen(screen->scrn_identifier) + 1);
      sprintf(list[nlist], "%s%s", Edit, screen->scrn_identifier);
      screens = (XF86ConfScreenPtr*)XtRealloc((XtPointer)screens, (nlist + 1) *
                            sizeof(XF86ConfScreenPtr));
      screens[nlist] = screen;
      ++nlist;
      screen = (XF86ConfScreenPtr)(screen->list.next);
    }

    screen = NULL;

    if (nlist) {
      list = (char**)XtRealloc((XtPointer)list, (nlist + 2) * sizeof(char*));
      list[nlist++] = XtNewString("Add new screen");
      if (nlist == 2) {
          i = strlen("Remove ") + strlen(screens[0]->scrn_identifier) + 1;
          list[nlist] = XtMalloc(i);
          XmuSnprintf(list[nlist], i, "Remove %s", screens[0]->scrn_identifier);
          ++nlist;
      }
      else
          list[nlist++] = XtNewString("Remove screen");
      ClearScreen();
      refresh();
      i = DialogMenu("Screen configuration",
                   "You can edit or remove a previously configured "
                   "screen, or add a new one.", 14, 60, 4, nlist, list,
                   " Ok  ", " Cancel ", 0);
      if (i < 0) {
          for (i = 0; i < nlist; i++)
            XtFree(list[i]);
          XtFree((XtPointer)list);
          XtFree((XtPointer)screens);
          return (-1);
      }
      if (nlist > 2 && i == nlist - 1) {
          if (nlist > 3) {
            for (i = 0; i < nlist - 2; i++) {
                /* XXX Remove the "Edit " from list entries */
                memmove(list[i], list[i] + sizeof(Edit) - 1,
                      strlen(list[i]) - sizeof(Edit) + 2);
            }
            ClearScreen();
            refresh();
            i = DialogMenu("Remove screen",
                         "Select which screen to remove",
                         13, 60, 4, nlist - 2, list,
                         " Remove ", " Cancel ", 0);
            if (i < 0) {
                for (i = 0; i < nlist; i++)
                  XtFree(list[i]);
                XtFree((XtPointer)list);
                XtFree((XtPointer)screens);
                return (-1);
            }
            screen = screens[i];
          }
          else
            screen = screens[0];
          for (i = 0; i < nlist; i++)
            XtFree(list[i]);
          XtFree((XtPointer)list);
          XtFree((XtPointer)screens);
          xf86removeScreen(XF86Config, screen);
          return (0);
      }
      if (i < nlist - 2)
          screen = screens[i];
    }
    for (i = 0; i < nlist; i++)
      XtFree(list[i]);
    XtFree((XtPointer)list);
    XtFree((XtPointer)screens);

    if (screen == NULL) {
      char label[256];
      XF86ConfDevicePtr *devices = NULL;
      XF86ConfMonitorPtr *monitors = NULL;

      device = XF86Config->conf_device_lst;
      monitor = XF86Config->conf_monitor_lst;

      if (device == NULL || monitor == NULL) {
            ClearScreen();
            refresh();
            Dialog("Configuration error",
                   "You need to configure (at least) one card and one "
                   "monitor before creating a screen definition.",
                   9, 50, "  Ok  ", NULL, 0);

            return (-1);
      }

      XmuSnprintf(label, sizeof(label), "Screen%d", nlist ? nlist - 2 : 0);
      ClearScreen();
      refresh();
      identifier =
          DialogInput("Screen identifier",
                  "Enter an identifier for your screen definition:",
                  11, 40, label,
                  " Next >>", " Cancel ", 0);
      if (identifier == NULL)
          return (-1);

      nlist = 0;
      list = NULL;
      while (device) {
          list = (char**)XtRealloc((XtPointer)list, (nlist + 1) * sizeof(char*));
          list[nlist] = XtNewString(device->dev_identifier);
          devices = (XF86ConfDevicePtr*)XtRealloc((XtPointer)devices, (nlist + 1) *
                              sizeof(XF86ConfDevicePtr));
          devices[nlist] = device;
          ++nlist;
          device = (XF86ConfDevicePtr)(device->list.next);
      }
      ClearScreen();
      refresh();
      i = DialogMenu("Screen card", "Please select a video card:",
                   13, 60, 4, nlist, list, " Next >>", " Cancel ", 0);
      for (def = 0; def < nlist; def++)
          XtFree(list[def]);
      XtFree((XtPointer)list);
      if (i < 0) {
          XtFree(identifier);
          XtFree((XtPointer)devices);
          return (-1);
      }
      device = devices[i];
      XtFree((XtPointer)devices);

      nlist = 0;
      list = NULL;
      while (monitor) {
          list = (char**)XtRealloc((XtPointer)list, (nlist + 1) * sizeof(char*));
          list[nlist] = XtNewString(monitor->mon_identifier);
          monitors = (XF86ConfMonitorPtr*)XtRealloc((XtPointer)monitors, (nlist + 1) *
                              sizeof(XF86ConfMonitorPtr));
          monitors[nlist] = monitor;
          ++nlist;
          monitor = (XF86ConfMonitorPtr)(monitor->list.next);
      }
      XmuSnprintf(label, sizeof(label),
                "Select the monitor connected to \"%s\":",
                device->dev_identifier);
      ClearScreen();
      refresh();
      i = DialogMenu("Screen monitor", label,
                   13, 60, 4, nlist, list, " Next >>", " Cancel ", 0);
      for (def = 0; def < nlist; def++)
          XtFree(list[def]);
      XtFree((XtPointer)list);
      if (i < 0) {
          XtFree(identifier);
          XtFree((XtPointer)monitors);
          return (-1);
      }
      monitor = monitors[i];
      XtFree((XtPointer)monitors);

      screen = (XF86ConfScreenPtr)XtCalloc(1, sizeof(XF86ConfScreenRec));
      screen->scrn_device = device;
      screen->scrn_monitor = monitor;
    }

    if (screen->scrn_defaultdepth == 1)
      def = 0;
    else if (screen->scrn_defaultdepth == 4)
      def = 1;
    else if (screen->scrn_defaultdepth == 8)
      def = 2;
    else if (screen->scrn_defaultdepth == 15)
      def = 3;
    else if (screen->scrn_defaultdepth == 16)
      def = 4;
    else if (screen->scrn_defaultdepth == 24)
      def = 5;
    else {
      if (screen->scrn_device && screen->scrn_device->dev_driver &&
          strcmp(screen->scrn_device->dev_driver, "vga") == 0)
          def = 1;            /* 4bpp */
      else
          def = 2;            /* 8bpp */
    }
    ClearScreen();
    refresh();
    i = DialogMenu("Screen depth",
               "Please specify which color depth you want to use by default:",
               15, 60, 6, sizeof(depths) / sizeof(depths[0]), depths,
               " Next >>", " Cancel ", def);
    if (i < 0) {
      if (screen->scrn_identifier == NULL) {
          XtFree(identifier);
          XtFree((XtPointer)screen);
      }
      return (-1);
    }
    else
      /* XXX depths must begin with the depth number */
      screen->scrn_defaultdepth = atoi(depths[i]);

    def = 0;      /* use def to count how many modes are selected*/
    nlist = 0;
    list = NULL;
    checks = XtMalloc(sizeof(modes) / sizeof(modes[0]));
    /* XXX list fields in the code below are not allocated */
    disp_allocated = 0;
    display = screen->scrn_display_lst;
    while (display && display->disp_depth != screen->scrn_defaultdepth)
      display = (XF86ConfDisplayPtr)(display->list.next);
    if (display == NULL) {
      display = (XF86ConfDisplayPtr)XtCalloc(1, sizeof(XF86ConfDisplayRec));
      display->disp_white.red = display->disp_black.red = -1;
      display->disp_depth = screen->scrn_defaultdepth;
      disp_allocated = 1;
    }
    else {
      mode = display->disp_mode_lst;
      while (mode) {
          for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++)
            if (strcmp(modes[i], mode->mode_name) == 0) {
                break;
            }

          if (i == sizeof(modes) / sizeof(modes[0])) {
            list = (char**)XtRealloc((XtPointer)list,
                               (nlist + 1) * sizeof(char*));
            list[nlist] = mode->mode_name;
            checks = XtRealloc(checks, sizeof(modes) / sizeof(modes[0]) +
                           nlist + 1);
            checks[nlist] = 1;
            ++def;
            nlist++;
            break;
          }
          mode = (XF86ModePtr)(mode->list.next);
      }
    }

    for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++)
      checks[i + nlist] = 0;

    mode = display->disp_mode_lst;
    while (mode) {
      for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++)
          if (strcmp(modes[i], mode->mode_name) == 0) {
            ++def;
            checks[i + nlist] = 1;
            break;
      }
      mode = (XF86ModePtr)(mode->list.next);
    }

    if (nlist == 0 && def == 0)
      checks[7] = 1;    /* 640x480 */
    list = (char**)XtRealloc((XtPointer)list, (nlist + sizeof(modes) /
                       sizeof(modes[0])) * sizeof(char*));
    for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++)
      list[i + nlist] = modes[i];
    nlist += sizeof(modes) / sizeof(modes[0]);

    ClearScreen();
    refresh();
    i = DialogCheckBox("Screen modes",
                   "Select the video modes for this screen:",
                   17, 60, 8, sizeof(modes) / sizeof(modes[0]), modes,
                   " Finish ", " Cancel ", checks);
    if (i < 0) {
      if (screen->scrn_identifier == NULL) {
          XtFree(identifier);
          XtFree((XtPointer)screen);
          XtFree((XtPointer)list);
          if (disp_allocated)
            XtFree((XtPointer)display);
      }
      return (-1);
    }

    mode = display->disp_mode_lst;
    while (mode) {
      ptr = (XF86ModePtr)(mode->list.next);
      XtFree(mode->mode_name);
      XtFree((XtPointer)mode);
      mode = ptr;
    }
    display->disp_mode_lst = NULL;

    for (i = 0; i < nlist; i++) {
      if (checks[i]) {
          mode = (XF86ModePtr)XtCalloc(1, sizeof(XF86ModeRec));
          mode->mode_name = XtNewString(list[i]);
          if (display->disp_mode_lst == NULL)
            display->disp_mode_lst = ptr = mode;
          else {
            ptr->list.next = mode;
            ptr = mode;
          }
      }
    }
    XtFree((XtPointer)list);

    if (disp_allocated) {
      display->list.next = NULL;
      if (screen->scrn_display_lst == NULL)
          screen->scrn_display_lst = display;
      else
          screen->scrn_display_lst->list.next = display;
    }

    if (screen->scrn_identifier == NULL) {
      screen->scrn_identifier = identifier;
      screen->scrn_monitor_str = XtNewString(monitor->mon_identifier);
      screen->scrn_device_str = XtNewString(device->dev_identifier);
      XF86Config->conf_screen_lst =
          xf86addScreen(XF86Config->conf_screen_lst, screen);
    }

    return (1);
}

static XF86ConfAdjacencyPtr
CopyAdjacency(XF86ConfAdjacencyPtr ptr)
{
    XF86ConfAdjacencyPtr adj = (XF86ConfAdjacencyPtr)
      XtCalloc(1, sizeof(XF86ConfAdjacencyRec));

    adj->adj_scrnum = ptr->adj_scrnum;
    adj->adj_screen = ptr->adj_screen;
    adj->adj_screen_str = XtNewString(ptr->adj_screen_str);
    adj->adj_top = ptr->adj_top;
    if (ptr->adj_top_str)
      adj->adj_top_str = XtNewString(ptr->adj_top_str);
    adj->adj_bottom = ptr->adj_bottom;
    if (ptr->adj_bottom_str)
      adj->adj_bottom_str = XtNewString(ptr->adj_bottom_str);
    adj->adj_left = ptr->adj_left;
    if (ptr->adj_left_str)
      adj->adj_left_str = XtNewString(ptr->adj_left_str);
    adj->adj_right = ptr->adj_right;
    if (ptr->adj_right_str)
      adj->adj_right_str = XtNewString(ptr->adj_right_str);
    adj->adj_where = ptr->adj_where;
    adj->adj_x = ptr->adj_x;
    adj->adj_y = ptr->adj_y;
    if (ptr->adj_refscreen)
      adj->adj_refscreen = XtNewString(ptr->adj_refscreen);

    return (adj);
}

static XF86ConfInactivePtr
CopyInactive(XF86ConfInactivePtr ptr)
{
    XF86ConfInactivePtr inac = (XF86ConfInactivePtr)
      XtCalloc(1, sizeof(XF86ConfInactiveRec));

    inac->inactive_device = ptr->inactive_device;
    if (ptr->inactive_device_str)
      inac->inactive_device_str = XtNewString(ptr->inactive_device_str);

    return (inac);
}

static XF86ConfInputrefPtr
CopyInputref(XF86ConfInputrefPtr ptr)
{
    XF86ConfInputrefPtr iref = (XF86ConfInputrefPtr)
      XtCalloc(1, sizeof(XF86ConfInputrefRec));
    XF86OptionPtr opt = ptr->iref_option_lst;

    iref->iref_inputdev = ptr->iref_inputdev;
    if (ptr->iref_inputdev_str)
      iref->iref_inputdev_str = XtNewString(ptr->iref_inputdev_str);
    while (opt) {
      iref->iref_option_lst = xf86addNewOption(iref->iref_option_lst,
          XtNewString(opt->opt_name),
          opt->opt_val ? XtNewString(opt->opt_val) : NULL);
      opt = (XF86OptionPtr)(opt->list.next);
    }

    return (iref);
}

static XF86ConfLayoutPtr
CopyLayout(XF86ConfLayoutPtr ptr)
{
    XF86ConfLayoutPtr lay = (XF86ConfLayoutPtr)
      XtCalloc(1, sizeof(XF86ConfLayoutRec));
    XF86ConfAdjacencyPtr adj = ptr->lay_adjacency_lst, padj;
    XF86ConfInactivePtr inac = ptr->lay_inactive_lst, pinac;
    XF86ConfInputrefPtr iref = ptr->lay_input_lst, piref;
    XF86OptionPtr opt = ptr->lay_option_lst;

    if (ptr->lay_identifier)
      lay->lay_identifier = XtNewString(ptr->lay_identifier);
    if (adj) {
      padj = lay->lay_adjacency_lst = CopyAdjacency(adj);
      adj = (XF86ConfAdjacencyPtr)(adj->list.next);
      while (adj) {
          padj->list.next = CopyAdjacency(adj);
          padj = (XF86ConfAdjacencyPtr)(padj->list.next);
          adj = (XF86ConfAdjacencyPtr)(adj->list.next);
      }
    }
    if (inac) {
      pinac = lay->lay_inactive_lst = CopyInactive(inac);
      inac = (XF86ConfInactivePtr)(inac->list.next);
      while (inac) {
          pinac->list.next = CopyInactive(inac);
          pinac = (XF86ConfInactivePtr)(pinac->list.next);
          inac = (XF86ConfInactivePtr)(inac->list.next);
      }
    }
    if (iref) {
      piref = lay->lay_input_lst = CopyInputref(iref);
      iref = (XF86ConfInputrefPtr)(iref->list.next);
      while (iref) {
          piref->list.next = CopyInputref(iref);
          piref = (XF86ConfInputrefPtr)(piref->list.next);
          iref = (XF86ConfInputrefPtr)(iref->list.next);
      }
    }

    while (opt) {
      lay->lay_option_lst = xf86addNewOption(lay->lay_option_lst,
          XtNewString(opt->opt_name),
          opt->opt_val ? XtNewString(opt->opt_val) : NULL);
      opt = (XF86OptionPtr)(opt->list.next);
    }

    return (lay);
}

static void
FreeLayout(XF86ConfLayoutPtr lay)
{
    static XF86ConfigRec xf86config;

    xf86config.conf_layout_lst = lay;
    xf86removeLayout(&xf86config, lay);
}

static int
LayoutConfig(void)
{
    int i;
    XF86ConfLayoutPtr *layouts = NULL, rlayout = NULL,
                   layout = XF86Config->conf_layout_lst;
    XF86ConfInputPtr input = XF86Config->conf_input_lst;
    char **list = NULL, *identifier = NULL;
    XF86ConfInputPtr *mouses = NULL, *keyboards = NULL, mouse, keyboard;
    XF86ConfInputrefPtr iref, piref, mref, kref;
    XF86ConfAdjacencyPtr adj, padj;
    int nmouses, nkeyboards;
    int nlist;
    XF86OptionPtr option;
    XF86ConfScreenPtr screen, *screens;

    nmouses = nkeyboards = 0;
    while (input) {
      if (strcmp(input->inp_driver, "mouse") == 0) {
          mouses = (XF86ConfInputPtr*)XtRealloc((XtPointer)mouses,
                  (nmouses + 1) * sizeof(XF86ConfInputPtr));
          mouses[nmouses] = input;
          ++nmouses;
      }
      else if (strcmp(input->inp_driver, "keyboard") == 0) {
          keyboards = (XF86ConfInputPtr*)XtRealloc((XtPointer)keyboards,
                      (nkeyboards + 1) * sizeof(XF86ConfInputPtr));
          keyboards[nkeyboards] = input;
          ++nkeyboards;
      }
      input = (XF86ConfInputPtr)(input->list.next);
    }
    if (XF86Config->conf_screen_lst == NULL ||
      nmouses == 0 || nkeyboards == 0) {
      XtFree((XtPointer)mouses);
      XtFree((XtPointer)keyboards);
      ClearScreen();
      refresh();
      Dialog("Configuration error",
             "You need to configure (at least) one screen, mouse "
             "and keyboard before creating a layout definition.",
             9, 50, "  Ok  ", NULL, 0);
      return (-1);
    }

    nlist = 0;
    while (layout) {
      list = (char**)XtRealloc((XtPointer)list, (nlist + 1) * sizeof(char*));
      list[nlist] = XtMalloc(sizeof(Edit) +
                         strlen(layout->lay_identifier) + 1);
      sprintf(list[nlist], "%s%s", Edit, layout->lay_identifier);
      layouts = (XF86ConfLayoutPtr*)XtRealloc((XtPointer)layouts, (nlist + 1) *
                            sizeof(XF86ConfLayoutPtr));
      layouts[nlist] = layout;
      ++nlist;
      layout = (XF86ConfLayoutPtr)(layout->list.next);
    }

    layout = NULL;

    if (nlist) {
      list = (char**)XtRealloc((XtPointer)list, (nlist + 2) * sizeof(char*));
      list[nlist++] = XtNewString("Add new layout");
      if (nlist == 2) {
          i = strlen("Remove ") + strlen(layouts[0]->lay_identifier) + 1;
          list[nlist] = XtMalloc(i);
          XmuSnprintf(list[nlist], i, "Remove %s", layouts[0]->lay_identifier);
          ++nlist;
      }
      else
          list[nlist++] = XtNewString("Remove layout");
      ClearScreen();
      refresh();
      i = DialogMenu("Layout configuration",
                   "You can edit or remove a previously configured "
                   "layout, or add a new one.", 14, 60, 4, nlist, list,
                   " Ok  ", " Cancel ", 0);
      if (i < 0) {
          for (i = 0; i < nlist; i++)
            XtFree(list[i]);
          XtFree((XtPointer)list);
          XtFree((XtPointer)layouts);
          XtFree((XtPointer)mouses);
          XtFree((XtPointer)keyboards);
          return (-1);
      }
      if (nlist > 2 && i == nlist - 1) {
          if (nlist > 3) {
            for (i = 0; i < nlist - 2; i++) {
                /* XXX Remove the "Edit " from list entries */
                memmove(list[i], list[i] + sizeof(Edit) - 1,
                      strlen(list[i]) - sizeof(Edit) + 2);
            }
            ClearScreen();
            refresh();
            i = DialogMenu("Remove layout",
                         "Select which layout to remove",
                         13, 60, 4, nlist - 2, list,
                         " Remove ", " Cancel ", 0);
            if (i < 0) {
                for (i = 0; i < nlist; i++)
                  XtFree(list[i]);
                XtFree((XtPointer)list);
                XtFree((XtPointer)layouts);
                XtFree((XtPointer)mouses);
                XtFree((XtPointer)keyboards);
                return (-1);
            }
            layout = layouts[i];
          }
          else
            layout = layouts[0];
          for (i = 0; i < nlist; i++)
            XtFree(list[i]);
          XtFree((XtPointer)list);
          XtFree((XtPointer)layouts);
          XtFree((XtPointer)mouses);
          XtFree((XtPointer)keyboards);
          xf86removeLayout(XF86Config, layout);
          return (0);
      }
      if (i < nlist - 2)
          layout = layouts[i];
    }
    for (i = 0; i < nlist; i++)
      XtFree(list[i]);
    XtFree((XtPointer)list);
    XtFree((XtPointer)layouts);

    if (layout == NULL) {
      char label[32];

      layout = (XF86ConfLayoutPtr)XtCalloc(1, sizeof(XF86ConfLayoutRec));
      XmuSnprintf(label, sizeof(label), "Layout%d", nlist ? nlist - 2 : 0);
      ClearScreen();
      refresh();
      identifier =
          DialogInput("Layout identifier",
                  "Enter an identifier for your layout definition:",
                  11, 40, label,
                  " Next >>", " Cancel ", 0);
      if (identifier == NULL) {
          XtFree((XtPointer)layout);
          XtFree((XtPointer)mouses);
          XtFree((XtPointer)keyboards);
          return (-1);
      }
    }
    else {
      /* So that we can safely change it */
      rlayout = layout;
      layout = CopyLayout(rlayout);
    }


    mouse = keyboard = NULL;

    /*  Mouse */
    piref = NULL;
    iref = layout->lay_input_lst;
    while (iref) {
      if (strcmp(iref->iref_inputdev->inp_driver, "mouse") == 0) {
          if (mouse == NULL)
            piref = iref;
          if (xf86findOption(iref->iref_option_lst, "CorePointer")) {
            mouse = iref->iref_inputdev;
            piref = iref;
            break;
          }
      }
      iref = (XF86ConfInputrefPtr)(iref->list.next);
    }
    if (mouse == NULL) {
      if (piref) {
          mref = piref;
          mouse = piref->iref_inputdev;
          piref->iref_option_lst =
            xf86addNewOption(piref->iref_option_lst,
                         XtNewString("CorePointer"), NULL);
      }
      else {
          mouse = mouses[0];
          mref = iref = (XF86ConfInputrefPtr)XtCalloc(1, sizeof(XF86ConfInputrefRec));
          iref->iref_inputdev_str = XtNewString(mouse->inp_identifier);
          iref->iref_inputdev = mouse;
          iref->iref_option_lst =
                xf86addNewOption(iref->iref_option_lst,
                           XtNewString("CorePointer"), NULL);
          iref->list.next = layout->lay_input_lst;
          if (layout->lay_input_lst == NULL)
            layout->lay_input_lst = iref;
          else {
            iref->list.next = layout->lay_input_lst;
            layout->lay_input_lst = iref;
          }
      }
    }
    else
      mref = piref;

    /* XXX list fields are not allocated */
    if (nmouses > 1) {
      nlist = 0;
      list = (char**)XtMalloc(sizeof(char*));
      list[nlist++] = mouse->inp_identifier;
      input = XF86Config->conf_input_lst;
      while (input) {
          if (input != mouse && strcmp(input->inp_driver, "mouse") == 0) {
            list = (char**)XtRealloc((XtPointer)list, (nlist + 1) * sizeof(char*));
            list[nlist++] = input->inp_identifier;
          }
          input = (XF86ConfInputPtr)(input->list.next);
      }
      ClearScreen();
      refresh();
      i = DialogMenu("Select Core Pointer",
                   "Select the mouse connected to you computer",
                   12, 60, 4, nlist, list, "  Ok  ", " Cancel ", 0);
      if (i < 0) {
          XtFree((XtPointer)mouses);
          XtFree((XtPointer)keyboards);
          XtFree((XtPointer)list);
          if (layout->lay_identifier == NULL)
            XtFree(identifier);
          FreeLayout(layout);
          return (-1);
      }
      if (i > 0) {
          /* Did not select the default one */
          iref = layout->lay_input_lst;
          while (iref) {
            if (strcasecmp(iref->iref_inputdev_str, list[i]) == 0) {
                if ((option = xf86findOption(iref->iref_option_lst,
                                     "SendCoreEvents")) != NULL) {
                  XtFree(option->opt_name);
                  option->opt_name = XtNewString("CorePointer");
                }
                else
                  iref->iref_option_lst =
                      xf86addNewOption(iref->iref_option_lst,
                                "CorePointer", NULL);
                option = xf86findOption(mref->iref_option_lst,
                                  "CorePointer");
                XtFree(option->opt_name);
                option->opt_name = XtNewString("SendCoreEvents");
                break;
            }
            iref = (XF86ConfInputrefPtr)(iref->list.next);
          }
      }

      /* XXX Write code to add/remove more mouses here */
    }


    /*  Keyboard */
    piref = NULL;
    iref = layout->lay_input_lst;
    while (iref) {
      if (strcmp(iref->iref_inputdev->inp_driver, "keyboard") == 0) {
          if (keyboard == NULL)
            piref = iref;
          if (xf86findOption(iref->iref_option_lst, "CoreKeyboard")) {
            keyboard = iref->iref_inputdev;
            piref = iref;
            break;
          }
      }
      iref = (XF86ConfInputrefPtr)(iref->list.next);
    }
    if (keyboard == NULL) {
      if (piref) {
          kref = piref;
          keyboard = piref->iref_inputdev;
          piref->iref_option_lst =
            xf86addNewOption(piref->iref_option_lst,
                         XtNewString("CoreKeyboard"), NULL);
      }
      else {
          keyboard = keyboards[0];
          kref = iref = (XF86ConfInputrefPtr)XtCalloc(1, sizeof(XF86ConfInputrefRec));
          iref->iref_inputdev_str = XtNewString(keyboard->inp_identifier);
          iref->iref_inputdev = keyboard;
          iref->iref_option_lst =
                xf86addNewOption(iref->iref_option_lst,
                           XtNewString("CoreKeyboard"), NULL);
          iref->list.next = layout->lay_input_lst;
          if (layout->lay_input_lst == NULL)
            layout->lay_input_lst = iref;
          else {
            iref->list.next = layout->lay_input_lst;
            layout->lay_input_lst = iref;
          }
      }
    }
    else
      kref = piref;

    /* XXX list fields are not allocated */
    if (nkeyboards > 1) {
      nlist = 0;
      list = (char**)XtMalloc(sizeof(char*));
      list[nlist++] = keyboard->inp_identifier;
      input = XF86Config->conf_input_lst;
      while (input) {
          if (input != keyboard && strcmp(input->inp_driver, "keyboard") == 0) {
            list = (char**)XtRealloc((XtPointer)list, (nlist + 1) * sizeof(char*));
            list[nlist++] = input->inp_identifier;
          }
          input = (XF86ConfInputPtr)(input->list.next);
      }
      ClearScreen();
      refresh();
      i = DialogMenu("Select Core Keyboard",
                   "Select the keyboard connected to you computer",
                   12, 60, 4, nlist, list, "  Ok  ", " Cancel ", 0);
      if (i < 0) {
          XtFree((XtPointer)mouses);
          XtFree((XtPointer)keyboards);
          XtFree((XtPointer)list);
          if (layout->lay_identifier == NULL)
            XtFree(identifier);
          FreeLayout(layout);
          return (-1);
      }
      if (i > 0) {
          /* Did not select the default one */
          iref = layout->lay_input_lst;
          while (iref) {
            if (strcasecmp(iref->iref_inputdev_str, list[i]) == 0) {
                if ((option = xf86findOption(iref->iref_option_lst,
                                     "SendCoreEvents")) != NULL) {
                  XtFree(option->opt_name);
                  option->opt_name = XtNewString("CoreKeyboard");
                }
                else
                  iref->iref_option_lst =
                      xf86addNewOption(iref->iref_option_lst,
                                "CoreKeyboard", NULL);
                option = xf86findOption(kref->iref_option_lst,
                                  "CoreKeyboard");
                XtFree(option->opt_name);
                option->opt_name = XtNewString("SendCoreEvents");
                break;
            }
            iref = (XF86ConfInputrefPtr)(iref->list.next);
          }
      }

      /* XXX Write code to add/remove more keyboards here */
    }

    XtFree((XtPointer)mouses);
    XtFree((XtPointer)keyboards);

    /* Just one screen */
    if (XF86Config->conf_screen_lst->list.next == NULL) {
      ClearScreen();
      refresh();
      Dialog("Layout configuration",
             (nmouses > 1 || nkeyboards > 1) ?
             "As you have only one screen configured, I can now finish "
             "creating this Layout configuration."
            :
             "As you have only one screen, mouse and keyboard configured, "
             "I can now finish creating this Layout configuration.",
             12, 60, " Finish ", NULL, 0);

      goto LayoutFinish;
    }


    /* The code below just adds a screen to the right of the last
     * one, or allows removing a screen.
     * Needs some review, and adding more options.
     */

    /*CONSTCOND*/
    while (1) {
      static char *screen_opts[] = {
          "Add a new screen to layout",
          "Remove screen from layout",
          "Finish layout configuration",
      };

      ClearScreen();
      refresh();
      i = DialogMenu("Layout configuration", "Please choose one option:",
                   12, 60, 3, sizeof(screen_opts) / sizeof(screen_opts[0]),
                   screen_opts, " Done ", " Cancel all changes ", 2);

      /* cancel */
      if (i < 0) {
          XtFree(identifier);
          FreeLayout(layout);
          return (-1);
      }

      /* add new screen */
      else if (i == 0) {
          nlist = 0;
          list = NULL;
          screens = NULL;
          screen = XF86Config->conf_screen_lst;
          while (screen) {
            adj = layout->lay_adjacency_lst;
            while (adj) {
                if (adj->adj_screen == screen)
                  break;
                adj = (XF86ConfAdjacencyPtr)(adj->list.next);
            }
            if (adj == NULL) {
                list = (char**)XtRealloc((XtPointer)list, (nlist + 1) * sizeof(char*));
                screens = (XF86ConfScreenPtr*)XtRealloc((XtPointer)screens,
                         (nlist + 1) * sizeof(XF86ConfScreenPtr));
                /* NOT duplicated */
                list[nlist] = screen->scrn_identifier;
                screens[nlist] = screen;
                ++nlist;
            }
            screen = (XF86ConfScreenPtr)(screen->list.next);
          }

          if (nlist == 0)
            continue;

          ClearScreen();
          refresh();
          i = DialogMenu("Layout add screen", "Choose screen to add:",
                     12, 60, 3, nlist, list,
                     " Add ", " Cancel ", 0);
          if (i >= 0) {
            padj = layout->lay_adjacency_lst;
            adj = (XF86ConfAdjacencyPtr)
                  XtCalloc(1, sizeof(XF86ConfAdjacencyRec));
            adj->adj_screen = screens[i];
            if (padj == NULL) {
                adj->adj_where = CONF_ADJ_ABSOLUTE;
                layout->lay_adjacency_lst = adj;
            }
            else {
                while (padj->list.next)
                  padj = (XF86ConfAdjacencyPtr)(padj->list.next);
                padj->list.next = adj;
                adj->adj_where = CONF_ADJ_RIGHTOF;
                adj->adj_refscreen =
                  XtNewString(padj->adj_screen->scrn_identifier);
            }
          }
          XtFree((XtPointer)list);
          XtFree((XtPointer)screens);
      }

      /* remove a screen */
      else if (i == 1) {
          nlist = 0;
          list = NULL;
          screens = NULL;
          adj = layout->lay_adjacency_lst;

          while (adj) {
            list = (char**)XtRealloc((XtPointer)list, (nlist + 1) * sizeof(char*));
            screens = (XF86ConfScreenPtr*)XtRealloc((XtPointer)screens,
                     (nlist + 1) * sizeof(XF86ConfScreenPtr));
            list[nlist] = adj->adj_screen->scrn_identifier;
            screens[nlist] = adj->adj_screen;
            ++nlist;
            adj = (XF86ConfAdjacencyPtr)(adj->list.next);
          }

          if (nlist == 0)
            continue;

          ClearScreen();
          refresh();
          i = DialogMenu("Layout remove screen", "Choose screen to remove:",
                     12, 60, 3, nlist, list,
                     " Remove ", " Cancel ", 0);

          adj = padj = layout->lay_adjacency_lst;
          while (adj) {
            if (adj->adj_screen == screens[i]) {
                padj = (XF86ConfAdjacencyPtr)(padj->list.next);
                if (padj && adj->adj_where == CONF_ADJ_RIGHTOF &&
                  padj->adj_where == CONF_ADJ_RIGHTOF) {
                  XtFree(padj->adj_refscreen);
                  padj->adj_refscreen = XtNewString(adj->adj_refscreen);
                }
                xf86removeAdjacency(layout, adj);
                break;
            }
            padj = adj;
            adj = (XF86ConfAdjacencyPtr)(padj->list.next);
          }
          XtFree((XtPointer)list);
          XtFree((XtPointer)screens);
      }

      /* finish screen configuration */
      else
          break;
    }

LayoutFinish:
    if (layout->lay_adjacency_lst == NULL) {
      adj = (XF86ConfAdjacencyPtr)XtCalloc(1, sizeof(XF86ConfAdjacencyRec));
      adj->adj_screen = XF86Config->conf_screen_lst;
      adj->adj_screen_str = XtNewString(XF86Config->conf_screen_lst->scrn_identifier);
      adj->adj_where = CONF_ADJ_ABSOLUTE;
      layout->lay_adjacency_lst = adj;
    }
    if (rlayout) {
      /* just edited this layout */
      if (nmouses > 1 || nkeyboards > 1) {
          XF86ConfAdjacencyPtr tadj = rlayout->lay_adjacency_lst;
          XF86ConfInactivePtr tinac = rlayout->lay_inactive_lst;
          XF86ConfInputrefPtr tinp = rlayout->lay_input_lst;

          rlayout->lay_adjacency_lst = layout->lay_adjacency_lst;
          rlayout->lay_inactive_lst = layout->lay_inactive_lst;
          rlayout->lay_input_lst = layout->lay_input_lst;

          layout->lay_adjacency_lst = tadj;
          layout->lay_inactive_lst = tinac;
          layout->lay_input_lst = tinp;
          FreeLayout(layout);
      }
      return (0);
    }
    else {
      layout->lay_identifier = identifier;
      XF86Config->conf_layout_lst =
          xf86addLayout(XF86Config->conf_layout_lst, layout);
    }

    return (1);
}

static void
ClearScreen(void)
{
    int i, j;

    wattrset(stdscr, screen_attr);
    for (i = 0; i < LINES; i++) {
      wmove(stdscr, i, 0);
      for (j = 0; j < COLS; j++)
          waddch(stdscr, ACS_PLUS);
    }
    touchwin(stdscr);
}

static int
Dialog(char *title, char * prompt, int height, int width,
       char *label1, char *label2, int button)
{
    int x, x1, x2, y, key, l1len, l2len;
    WINDOW *dialog;

    x = (COLS - width) / 2;
    y = (LINES - height) / 2;
  
    dialog = newwin(height, width, y, x);
    keypad(dialog, TRUE);

    PaintWindow(dialog, title, 0, 0, height, width);
    wattrset(dialog, dialog_attr);
    PrintWrap(dialog, prompt, width - 3, 2, 3);

    l1len = strlen(label1);
    if (label2)
      l2len = strlen(label2);
    else {
      l2len = button = 0;
    }

    x1 = (width - (l1len + l2len)) / (label2 ? 3 : 2);
    x2 = x1 + x1 + l1len;
    y = height - 3;
    if (!button) {
      if (label2)
          PaintButton(dialog, label2, y, x2, FALSE);
      PaintButton(dialog, label1, y, x1, TRUE);
    }
    else {
      PaintButton(dialog, label1, y, x1, FALSE);
      if (label2)
          PaintButton(dialog, label2, y, x2, TRUE);
    }
    wrefresh(dialog);

    /*CONSTCOND*/
    while (1) {
      key = wgetch(dialog);
          switch (key) {
            case KEY_LEFT:
            case KEY_RIGHT:
                if (!button) {
                  if (label2) {
                      button = 1;
                      PaintButton(dialog, label1, y, x1, FALSE);
                      PaintButton(dialog, label2, y, x2, TRUE);
                  }

                }
                else {
                  if (label2) {
                      button = 0;
                      PaintButton(dialog, label2, y, x2, FALSE);
                      PaintButton(dialog, label1, y, x1, TRUE);
                  }
                }
                wrefresh(dialog);
                break;
            case ' ':
            case '\r':
            case '\n':
                delwin(dialog);
                return button;
      }
    }
    /*NOTREACHED*/
}

static void
PaintWindow(WINDOW *win, char *title_str, int y, int x, int height, int width)
{
    int i, j;

    if (title_str != NULL) {
      j = (width - strlen(title_str)) / 2 - 1;

      wattrset(win, title_attr);
      wmove(win, x, y);
      for (i = 0; i < j; i++)
          waddch(win, ' ');
      waddstr(win, title_str);
      for (; i < width; i++)
          waddch(win, ' ');
    }

    wattrset(win, 0);

    for (i = 1; i < height; i++) {
      wmove(win, y + i, x);
      for (j = 0; j < width; j++)
          if (i == height - 1 && !j)
            waddch(win, highlight_border_attr | ACS_LLCORNER);
          else if (i == height - 1 && j == width - 1)
            waddch(win, shadow_border_attr | ACS_LRCORNER);
          else if (i == height - 1)
            waddch(win, shadow_border_attr | ACS_HLINE);
          else if (!j)
            waddch(win, highlight_border_attr | ACS_VLINE);
          else if (j == width - 1)
            waddch(win, shadow_border_attr | ACS_VLINE);
          else
            waddch(win, dialog_attr | ' ');
    }

}

static void
PaintBox(WINDOW *win, int y, int x, int height, int width)
{
    int i, j;

    wattrset(win, 0);

    for (i = 0; i < height; i++) {
      wmove(win, y + i, x);
      for (j = 0; j < width; j++)
          if (!i && !j)
            waddch(win, shadow_border_attr | ACS_ULCORNER);
          else if (i == height - 1 && !j)
            waddch(win, shadow_border_attr | ACS_LLCORNER);
          else if (!i && j == width-1)
            waddch(win, highlight_border_attr | ACS_URCORNER);
          else if (i == height - 1 && j == width - 1)
            waddch(win, highlight_border_attr | ACS_LRCORNER);
          else if (!i)
            waddch(win, shadow_border_attr | ACS_HLINE);
          else if (i == height - 1)
            waddch(win, highlight_border_attr | ACS_HLINE);
          else if (!j)
            waddch(win, shadow_border_attr | ACS_VLINE);
          else if (j == width - 1)
            waddch(win, highlight_border_attr | ACS_VLINE);
          else
            waddch(win, dialog_attr | ' ');
    }

}

static void
PaintButton(WINDOW *win, char *label, int y, int x, int selected)
{
    int i, temp;

    wmove(win, y, x);
    wattrset(win, selected ? button_active_attr : button_inactive_attr);
    waddstr(win, selected ? "[" : " ");
    temp = strspn(label, " ");
    label += temp;
    wattrset(win, selected ? button_active_attr : button_inactive_attr);
    for (i = 0; i < temp; i++)
      waddch(win, ' ');
    wattrset(win, selected ? button_active_attr : button_inactive_attr);
    waddch(win, label[0]);
    wattrset(win, selected ? button_active_attr : button_inactive_attr);
    waddstr(win, label + 1);
    wattrset(win, selected ? button_active_attr : button_inactive_attr);
    waddstr(win, selected ? "]" : " ");
    wmove(win, y, x + temp + 1);
}

static void
PrintWrap(WINDOW *win, char *prompt, int width, int y, int x)
{
    int cur_x, cur_y, len, yinc;
    char *word, *tempstr = XtMalloc(strlen(prompt) + 1);

    cur_x = x;
    cur_y = y;

    while (*prompt == '\n') {
      ++cur_y;
      ++prompt;
    }

    strcpy(tempstr, prompt);

    for (word = strtok(tempstr, " \n"); word != NULL; word = strtok(NULL, " \n")) {
      yinc = 0;
      len = strlen(word);
      while (prompt[word - tempstr + len + yinc] == '\n')
          ++yinc;
      if (cur_x + strlen(word) > width) {
          cur_y++;
          cur_x = x;
      }
      wmove(win, cur_y, cur_x);
      waddstr(win, word);
      getyx(win, cur_y, cur_x);
      if (yinc) {
          cur_y += yinc;
          cur_x = x;
      }
      else
          cur_x++;
    }

    free(tempstr);
}

static int
DialogMenu(char *title, char *prompt, int height, int width, int menu_height,
         int item_no, char **items, char *label1, char *label2, int choice)
{
    int i, x, y, cur_x, cur_y, box_x, box_y, key = 0, button = 0,
      scrlx = 0, max_choice, nscroll, max_scroll, x1, x2, l1len, l2len;
    WINDOW *dialog, *menu;

    max_choice = MIN(menu_height, item_no);
    max_scroll = MAX(0, item_no - max_choice);

    x = (COLS - width) / 2;
    y = (LINES - height) / 2;
  
    dialog = newwin(height, width, y, x);
    keypad(dialog, TRUE);

    PaintWindow(dialog, title, 0, 0, height, width);

    wattrset(dialog, dialog_attr);
    PrintWrap(dialog, prompt, width - 3, 2, 3);

    l1len = strlen(label1);
    l2len = strlen(label2);

    x1 = (width - (l1len + l2len)) / 3;
    x2 = x1 + x1 + l1len;

    menu_width = width - 6;
    getyx(dialog, cur_y, cur_x);
    box_y = cur_y + 1;
    box_x = (width - menu_width) / 2 - 1;

    menu = subwin(dialog, menu_height, menu_width, y + box_y + 1, x + box_x + 1);
    keypad(menu, TRUE);

    /* draw a box around the menu items */
    PaintBox(dialog, box_y, box_x, menu_height + 2, menu_width + 2);

    item_x = 3;

    if (choice > menu_height) {
      scrlx = MIN(max_scroll, choice);
      choice -= scrlx;
    }

    for (i = 0; i < max_choice; i++)
      PaintItem(menu, items[i + scrlx], i, i == choice);
    PaintScroller(menu, scrlx + choice, item_no, menu_height);
    wnoutrefresh(menu);

    x = width / 2 - 11;
    y = height - 3;
    PaintButton(dialog, label2, y, x2, FALSE);
    PaintButton(dialog, label1, y, x1, TRUE);
    wrefresh(dialog);

    /*CONSTCOND*/
    while (1) {
      i = choice;
      key = wgetch(dialog);

      if (menu_height > 1 && key == KEY_PPAGE) {
          if (!choice) {
            if (scrlx) {
                /* Scroll menu down */
                getyx(dialog, cur_y, cur_x);

                nscroll = max_choice > scrlx ? -scrlx : -max_choice;
                scrollok(menu, TRUE);
                wscrl(menu, nscroll);
                scrollok(menu, FALSE);

                PaintItem(menu, items[i = scrlx + nscroll], 0, TRUE);
                for (++i; i <= scrlx; i++)
                  PaintItem(menu, items[i], i - (scrlx + nscroll), FALSE);
                scrlx += nscroll;
                PaintScroller(menu, scrlx + choice, item_no, menu_height);
                wnoutrefresh(menu);
                wrefresh(dialog);
                continue;
            }
          }
          i = 0;
      }
      else if (menu_height > 1 && key == KEY_NPAGE) {
          if (choice == max_choice - 1) {
            if (scrlx < max_scroll) {
                /* Scroll menu up */
                getyx(dialog, cur_y, cur_x);

                nscroll = (scrlx + max_choice > max_scroll ?
                         max_scroll : scrlx + max_choice) - scrlx;
                scrollok(menu, TRUE);
                wscrl(menu, nscroll);
                scrollok(menu, FALSE);

                scrlx += nscroll;
                for (i = 0; i < max_choice - 1; i++)
                  PaintItem(menu, items[i + scrlx], i, FALSE);
                PaintItem(menu, items[i + scrlx], max_choice - 1, TRUE);
                PaintScroller(menu, scrlx + choice, item_no, menu_height);
                wnoutrefresh(menu);
                wrefresh(dialog);
                continue;
            }
          }
          i = max_choice - 1;
      }
      else if (key == KEY_UP) {
          if (!choice) {
            if (scrlx) {
                /* Scroll menu down */
                getyx(dialog, cur_y, cur_x);
                if (menu_height > 1) {
                  PaintItem(menu, items[scrlx], 0, FALSE);
                  scrollok(menu, TRUE);
                  wscrl(menu, - 1);
                  scrollok(menu, FALSE);
                }
                scrlx--;
                PaintItem(menu, items[scrlx], 0, TRUE);
                PaintScroller(menu, scrlx + choice, item_no, menu_height);
                wnoutrefresh(menu);
                wrefresh(dialog);
                continue;
            }
          }
          else
            i = choice - 1;
      }
      else if (key == KEY_DOWN) {
          if (choice == max_choice - 1) {
            if (scrlx + choice < item_no - 1) {
                /* Scroll menu up */
                getyx(dialog, cur_y, cur_x);
                if (menu_height > 1) {
                  PaintItem(menu, items[scrlx + max_choice - 1], max_choice - 1, FALSE);
                  scrollok(menu, TRUE);
                  scroll(menu);
                  scrollok(menu, FALSE);
                }
                scrlx++;
                PaintItem(menu, items[scrlx + max_choice - 1], max_choice - 1, TRUE);
                PaintScroller(menu, scrlx + choice, item_no, menu_height);
                wnoutrefresh(menu);
                wrefresh(dialog);
                continue;
            }
          }
          else
            i = MIN(choice + 1, item_no - 1);
      }

      if (i != choice) {
          getyx(dialog, cur_y, cur_x);
          PaintItem(menu, items[scrlx + choice], choice, FALSE);

          choice = i;
          PaintItem(menu, items[scrlx + choice], choice, TRUE);
          PaintScroller(menu, scrlx + choice, item_no, menu_height);
          wnoutrefresh(menu);
          wmove(dialog, cur_y, cur_x);
          wrefresh(dialog);
          continue;
      }

      switch (key) {
          case TAB:
          case KEY_LEFT:
          case KEY_RIGHT:
            if (!button) {
                button = 1;
                PaintButton(dialog, label1, y, x1, FALSE);
                PaintButton(dialog, label2, y, x2, TRUE);
            }
            else {
                button = 0;
                PaintButton(dialog, label2, y, x2, FALSE);
                PaintButton(dialog, label1, y, x1, TRUE);
            }
            wrefresh(dialog);
            break;
          case ' ':
          case '\r':
          case '\n':
            delwin(dialog);
            return (!button ? scrlx + choice : -1);
          default:
            for (i = scrlx + choice + 1; i < item_no; i++)
                if (toupper(items[i][0]) == toupper(key))
                  break;
            if (i == item_no) {
                for (i = 0; i < scrlx + choice; i++)
                  if (toupper(items[i][0]) == toupper(key))
                      break;
            }
            getyx(dialog, cur_y, cur_x);
            if (i < item_no && i != scrlx + choice) {
                if (i >= scrlx && i < scrlx + max_choice) {
                  /* it is already visible */
                  PaintItem(menu, items[scrlx + choice], choice, FALSE);
                  choice = i - scrlx;
                }
                else {
                  scrlx = MIN(i, max_scroll);
                  choice = i - scrlx;
                  for (i = 0; i < max_choice; i++)
                      if (i != choice)
                        PaintItem(menu, items[scrlx + i], i, FALSE);
                }
                PaintItem(menu, items[scrlx + choice], choice, TRUE);
                PaintScroller(menu, scrlx + choice, item_no, menu_height);
                wnoutrefresh(menu);
                wmove(dialog, cur_y, cur_x);
                wrefresh(dialog);
            }
            break;
      }
    }
    /*NOTREACHED*/
}

static void
PaintItem(WINDOW *win, char *item, int choice, int selected)
{
    int i;

    wattrset(win, selected ? title_attr : dialog_attr);
    wmove(win, choice, 1);
    for (i = 1; i < menu_width; i++)
      waddch(win, ' ');
    wmove(win, choice, item_x);
    wattrset(win, selected ? title_attr : dialog_attr);
    waddstr(win, item);
}

static void
PaintScroller(WINDOW *win, int offset, int lenght, int visible)
{
    int i, pos;

    if (lenght > visible)
      pos = (visible / (double)lenght) * offset;
    else
      pos = offset;
    wattrset(win, shadow_border_attr);
    for (i = 0; i < visible; i++) {
      wmove(win, i, 0);
      waddch(win, i == pos ? ACS_BLOCK : ACS_VLINE);
    }
}

static int
DialogCheckBox(char *title, char *prompt, int height, int width, int menu_height,
             int item_no, char **items, char *label1, char *label2, char *checks)
{
    int i, x, y, cur_x, cur_y, box_x, box_y, key = 0, button = 0, choice = 0,
      scrlx = 0, max_choice, nscroll, max_scroll, x1, x2, l1len, l2len;
    WINDOW *dialog, *menu;

    max_choice = MIN(menu_height, item_no);
    max_scroll = MAX(0, item_no - max_choice);

    x = (COLS - width) / 2;
    y = (LINES - height) / 2;
  
    dialog = newwin(height, width, y, x);
    keypad(dialog, TRUE);

    PaintWindow(dialog, title, 0, 0, height, width);

    wattrset(dialog, dialog_attr);
    PrintWrap(dialog, prompt, width - 3, 2, 3);

    l1len = strlen(label1);
    l2len = strlen(label2);

    x1 = (width - (l1len + l2len)) / 3;
    x2 = x1 + x1 + l1len;

    menu_width = width - 6;
    getyx(dialog, cur_y, cur_x);
    box_y = cur_y + 1;
    box_x = (width - menu_width) / 2 - 1;

    menu = subwin(dialog, menu_height, menu_width, y + box_y + 1, x + box_x + 1);
    keypad(menu, TRUE);

    /* draw a box around the menu items */
    PaintBox(dialog, box_y, box_x, menu_height + 2, menu_width + 2);

    item_x = 3;

    for (i = 0; i < max_choice; i++)
      PaintCheckItem(menu, items[i + scrlx], i, i == 0, checks[i + scrlx]);
    PaintScroller(menu, scrlx + choice, item_no, menu_height);
    wnoutrefresh(menu);

    x = width / 2 - 11;
    y = height - 3;
    PaintButton(dialog, label2, y, x2, FALSE);
    PaintButton(dialog, label1, y, x1, TRUE);
    wrefresh(dialog);

    /*CONSTCOND*/
    while (1) {
      i = choice;
      key = wgetch(dialog);

      if (menu_height > 1 && key == KEY_PPAGE) {
          if (!choice) {
            if (scrlx) {
                /* Scroll menu down */
                getyx(dialog, cur_y, cur_x);

                nscroll = max_choice > scrlx ? -scrlx : -max_choice;
                scrollok(menu, TRUE);
                wscrl(menu, nscroll);
                scrollok(menu, FALSE);

                i = scrlx + nscroll;
                PaintCheckItem(menu, items[i], 0, TRUE, checks[i]);
                for (++i; i <= scrlx; i++)
                  PaintCheckItem(menu, items[i], i - (scrlx + nscroll), FALSE, checks[i]);
                scrlx += nscroll;
                PaintScroller(menu, scrlx + choice, item_no, menu_height);
                wnoutrefresh(menu);
                wrefresh(dialog);
                continue;
            }
          }
          i = 0;
      }
      else if (menu_height > 1 && key == KEY_NPAGE) {
          if (choice == max_choice - 1) {
            if (scrlx < max_scroll) {
                /* Scroll menu up */
                getyx(dialog, cur_y, cur_x);

                nscroll = (scrlx + max_choice > max_scroll ?
                         max_scroll : scrlx + max_choice) - scrlx;
                scrollok(menu, TRUE);
                wscrl(menu, nscroll);
                scrollok(menu, FALSE);

                scrlx += nscroll;
                for (i = 0; i < max_choice - 1; i++)
                  PaintCheckItem(menu, items[i + scrlx], i, FALSE, checks[i + scrlx]);
                PaintCheckItem(menu, items[i + scrlx], max_choice - 1, TRUE, checks[i + scrlx]);
                PaintScroller(menu, scrlx + choice, item_no, menu_height);
                wnoutrefresh(menu);
                wrefresh(dialog);
                continue;
            }
          }
          i = max_choice - 1;
      }
      else if (key == KEY_UP) {
          if (!choice) {
            if (scrlx) {
                /* Scroll menu down */
                getyx(dialog, cur_y, cur_x);
                if (menu_height > 1) {
                  PaintCheckItem(menu, items[scrlx], 0, FALSE, checks[scrlx]);
                  scrollok(menu, TRUE);
                  wscrl(menu, - 1);
                  scrollok(menu, FALSE);
                }
                scrlx--;
                PaintCheckItem(menu, items[scrlx], 0, TRUE, checks[scrlx]);
                PaintScroller(menu, scrlx + choice, item_no, menu_height);
                wnoutrefresh(menu);
                wrefresh(dialog);
                continue;
            }
          }
          else
            i = choice - 1;
      }
      else if (key == KEY_DOWN) {
          if (choice == max_choice - 1) {
            if (scrlx + choice < item_no - 1) {
                /* Scroll menu up */
                getyx(dialog, cur_y, cur_x);
                if (menu_height > 1) {
                  PaintCheckItem(menu, items[scrlx + max_choice - 1], max_choice - 1, FALSE, checks[scrlx + max_choice - 1]);
                  scrollok(menu, TRUE);
                  scroll(menu);
                  scrollok(menu, FALSE);
                }
                scrlx++;
                PaintCheckItem(menu, items[scrlx + max_choice - 1], max_choice - 1, TRUE, checks[scrlx + max_choice - 1]);
                PaintScroller(menu, scrlx + choice, item_no, menu_height);
                wnoutrefresh(menu);
                wrefresh(dialog);
                continue;
            }
          }
          else
            i = MIN(choice + 1, item_no - 1);
      }

      if (i != choice) {
          getyx(dialog, cur_y, cur_x);
          PaintCheckItem(menu, items[scrlx + choice], choice, FALSE, checks[scrlx + choice]);

          choice = i;
          PaintCheckItem(menu, items[scrlx + choice], choice, TRUE, checks[scrlx + choice]);
          PaintScroller(menu, scrlx + choice, item_no, menu_height);
          wnoutrefresh(menu);
          wmove(dialog, cur_y, cur_x);
          wrefresh(dialog);
          continue;
      }

      switch (key) {
          case TAB:
          case KEY_LEFT:
          case KEY_RIGHT:
            if (!button) {
                button = 1;
                PaintButton(dialog, label1, y, x1, FALSE);
                PaintButton(dialog, label2, y, x2, TRUE);
            }
            else {
                button = 0;
                PaintButton(dialog, label2, y, x2, FALSE);
                PaintButton(dialog, label1, y, x1, TRUE);
            }
            wrefresh(dialog);
            break;
          case ' ':
            getyx(dialog, cur_y, cur_x);
            checks[scrlx + choice] = !checks[scrlx + choice];
            PaintCheckItem(menu, items[scrlx + choice], choice, TRUE, checks[scrlx + choice]);
            wmove(dialog, cur_y, cur_x);
            wnoutrefresh(menu);
            wrefresh(dialog);
            break;
          case '\r':
          case '\n':
            delwin(dialog);
            return (!button ? 0 : -1);
          default:
            for (i = scrlx + choice + 1; i < item_no; i++)
                if (toupper(items[i][0]) == toupper(key))
                  break;
            if (i == item_no) {
                for (i = 0; i < scrlx + choice; i++)
                  if (toupper(items[i][0]) == toupper(key))
                      break;
            }
            getyx(dialog, cur_y, cur_x);
            if (i < item_no && i != scrlx + choice) {
                if (i >= scrlx && i < scrlx + max_choice) {
                  /* it is already visible */
                  PaintCheckItem(menu, items[scrlx + choice], choice, FALSE, checks[scrlx + choice]);
                  choice = i - scrlx;
                }
                else {
                  scrlx = MIN(i, max_scroll);
                  choice = i - scrlx;
                  for (i = 0; i < max_choice; i++)
                      if (i != choice)
                        PaintCheckItem(menu, items[scrlx + i], i, FALSE, checks[scrlx + i]);
                }
                PaintCheckItem(menu, items[scrlx + choice], choice, TRUE, checks[scrlx + choice]);
                PaintScroller(menu, scrlx + choice, item_no, menu_height);
                wnoutrefresh(menu);
                wmove(dialog, cur_y, cur_x);
                wrefresh(dialog);
            }
            break;
      }
    }
    /*NOTREACHED*/
}

static void
PaintCheckItem(WINDOW *win, char *item, int choice, int selected, int checked)
{
    int i;

    wattrset(win, selected ? title_attr : dialog_attr);
    wmove(win, choice, 1);
    for (i = 1; i < menu_width; i++)
      waddch(win, ' ');
    wmove(win, choice, item_x);
    wattrset(win, selected ? title_attr : dialog_attr);
    wprintw(win, "[%c] ", checked ? 'X' : ' ');
    waddstr(win, item);
}

static char *
DialogInput(char *title, char *prompt, int height, int width, char *init,
          char *label1, char *label2, int def_button)
{
    int i, x, y, box_y, box_x, box_width, len,
      input_x = 0, scrlx = 0, key = 0, button = -1, x1, x2, l1len, l2len;
    char instr[1024 + 1];
    WINDOW *dialog;

    x = (COLS - width) / 2;
    y = (LINES - height) / 2;

    dialog = newwin(height, width, y, x);
    keypad(dialog, TRUE);

    PaintWindow(dialog, title, 0, 0, height, width);

    wattrset(dialog, dialog_attr);
    PrintWrap(dialog, prompt, width - 3, 2, 3);

    l1len = strlen(label1);
    l2len = strlen(label2);

    x1 = (width - (l1len + l2len)) / 3;
    x2 = x1 + x1 + l1len;

    box_width = width - 6;
    getyx(dialog, y, x);
    box_y = y + 2;
    box_x = (width - box_width) / 2;
    PaintBox(dialog, y + 1, box_x - 1, 3, box_width + 2);

    x = width / 2 - 11;
    y = height - 3;
    PaintButton(dialog, label2, y, x2, def_button == 1);
    PaintButton(dialog, label1, y, x1, def_button == 0);

    memset(instr, '\0', sizeof(instr));
    wmove(dialog, box_y, box_x);
    wattrset(dialog, dialog_attr);
    if (init)
      strncpy(instr, init, sizeof(instr) - 2);

    input_x = len = strlen(instr);
    if (input_x >= box_width) {
      scrlx = input_x - box_width + 1;
      input_x = box_width - 1;
      for (i = 0; i < box_width - 1; i++)
          waddch(dialog, instr[scrlx + i]);
    }
    else
      waddstr(dialog, instr);

    wmove(dialog, box_y, box_x + input_x);
  
    wrefresh(dialog);

    while (1) {
      key = wgetch(dialog);
      if (button == -1) {         /* Input box selected */
          switch (key) {
            case TAB:
            case KEY_UP:
            case KEY_DOWN:
                break;
            case KEY_LEFT:
                if (scrlx && !input_x) {
                  --scrlx;
                  wmove(dialog, box_y, box_x);
                  for (i = 0; i < box_width; i++)
                      waddch(dialog, instr[scrlx + input_x + i] ? instr[scrlx + input_x + i] : ' ');
                  wmove(dialog, box_y, input_x + box_x);
                  wrefresh(dialog);
                }
                else if (input_x) {
                  wmove(dialog, box_y, --input_x + box_x);
                  wrefresh(dialog);
                }
                continue;
            case KEY_RIGHT:
                if (input_x + scrlx < len) {
                  if (input_x == box_width - 1) {
                      ++scrlx;
                      wmove(dialog, box_y, box_x);
                      for (i = scrlx; i < scrlx + box_width; i++)
                        waddch(dialog, instr[i] ? instr[i] : ' ');
                      wmove(dialog, box_y, input_x + box_x);
                      wrefresh(dialog);
                  }
                  else {
                      wmove(dialog, box_y, ++input_x + box_x);
                      wrefresh(dialog);
                  }
                }
                continue;
            case KEY_BACKSPACE:
            case 0177:
                if (input_x || scrlx) {
                  wattrset(dialog, dialog_attr);

                  if (scrlx + input_x < len)
                      memmove(instr + scrlx + input_x - 1,
                            instr + scrlx + input_x,
                            len - (scrlx + input_x));
                  instr[--len] = '\0';

                  if (!input_x) {
                      scrlx = scrlx < box_width - 1 ? 0 : scrlx - (box_width - 1);
                      wmove(dialog, box_y, box_x);
                      for (i = 0; i < box_width; i++)
                        waddch(dialog, instr[scrlx + input_x + i] ? instr[scrlx + input_x + i] : ' ');
                      input_x = len - scrlx;
                  }
                  else {
                      wmove(dialog, box_y, --input_x + box_x);
                      for (i = scrlx + input_x; i < len &&
                         i < scrlx + box_width; i++)
                        waddch(dialog, instr[i]);
                      if (i < scrlx + box_width)
                        waddch(dialog, ' ');
                  }
                  wmove(dialog, box_y, input_x + box_x);
                  wrefresh(dialog);
                }
                continue;
            case KEY_HOME:
            case CONTROL_A:
                wmove(dialog, box_y, box_x);
                if (scrlx != 0) {
                  scrlx = 0;
                  for (i = 0; i < box_width; i++)
                      waddch(dialog, instr[i] ? instr[i] : ' ');
                }
                input_x = 0;
                wmove(dialog, box_y, box_x);
                wrefresh(dialog);
                break;
            case CONTROL_D:
                if (input_x + scrlx < len) {
                  memmove(instr + scrlx + input_x,
                            instr + scrlx + input_x + 1,
                            len - (scrlx + input_x));
                  instr[--len] = '\0';
                  for (i = scrlx + input_x; i < len &&
                       i < scrlx + box_width; i++)
                      waddch(dialog, instr[i]);
                  if (i < scrlx + box_width)
                      waddch(dialog, ' ');
                  wmove(dialog, box_y, input_x + box_x);
                  wrefresh(dialog);
                }
                break;
            case CONTROL_E:
            case KEY_END:
                if (box_width + scrlx < len) {
                  input_x = box_width - 1;
                  scrlx = len - box_width + 1;
                  wmove(dialog, box_y, box_x);
                  for (i = scrlx; i < scrlx + box_width; i++)
                      waddch(dialog, instr[i] ? instr[i] : ' ');
                  wmove(dialog, box_y, input_x + box_x);
                  wrefresh(dialog);
                }
                else {
                  input_x = len - scrlx;
                  wmove(dialog, box_y, input_x + box_x);
                  wrefresh(dialog);
                }
                break;
            case CONTROL_K:
                if (len) {
                  for (i = input_x; i < box_width; i++)
                      waddch(dialog, ' ');
                  for (i = scrlx + input_x; i < len; i++)
                      instr[i] = '\0';
                  len = scrlx + input_x;
                  wmove(dialog, box_y, box_x + input_x);
                  wrefresh(dialog);
                }
                break;
            default:
                if (key < 0x100 && isprint(key)) {
                  if (scrlx + input_x < sizeof(instr) - 1) {
                      wattrset(dialog, dialog_attr);
                      if (scrlx + input_x < len) {
                        memmove(instr + scrlx + input_x + 1,
                              instr + scrlx + input_x,
                              len - (scrlx + input_x));
                      }
                      instr[scrlx + input_x] = key;
                      instr[++len] = '\0';
                      if (input_x == box_width - 1) {
                        scrlx++;
                        wmove(dialog, box_y, box_x);
                        for (i = 0; i < box_width - 1; i++)
                            waddch(dialog, instr[scrlx + i]);
                      }
                      else {
                        wmove(dialog, box_y, input_x++ + box_x);
                        for (i = scrlx + input_x - 1; i < len &&
                             i < scrlx + box_width; i++)
                            waddch(dialog, instr[i]);
                        wmove(dialog, box_y, input_x + box_x);
                      }
                      wrefresh(dialog);
                  }
                  else
                      flash();          /* Alarm user about overflow */
                  continue;
                }
            }
          }

      switch (key) {
          case KEY_UP:
          case KEY_LEFT:
              switch (button) {
                case -1:
                  button = 1; /* Indicates "Cancel" button is selected */
                  PaintButton(dialog, label1, y, x1, FALSE);
                  PaintButton(dialog, label2, y, x2, TRUE);
                  wrefresh(dialog);
                  break;
                case 0:
                  button = -1;      /* Indicates input box is selected */
                  PaintButton(dialog, label2, y, x2, FALSE);
                  PaintButton(dialog, label1, y, x1, TRUE);
                  wmove(dialog, box_y, box_x + input_x);
                  wrefresh(dialog);
                  break;
                case 1:
                  button = 0; /* Indicates "OK" button is selected */
                  PaintButton(dialog, label2, y, x2, FALSE);
                  PaintButton(dialog, label1, y, x1, TRUE);
                  wrefresh(dialog);
                  break;
            }
            break;
          case TAB:
          case KEY_DOWN:
          case KEY_RIGHT:
            switch (button) {
                case -1:
                  button = 0; /* Indicates "OK" button is selected */
                  PaintButton(dialog, label2, y, x2, FALSE);
                  PaintButton(dialog, label1, y, x1, TRUE);
                  wrefresh(dialog);
                  break;
                case 0:
                  button = 1; /* Indicates "Cancel" button is selected */
                  PaintButton(dialog, label1, y, x1, FALSE);
                  PaintButton(dialog, label2, y, x2, TRUE);
                  wrefresh(dialog);
                  break;
                case 1:
                  button = -1;      /* Indicates input box is selected */
                  PaintButton(dialog, label2, y, x2, FALSE);
                  PaintButton(dialog, label1, y, x1, TRUE);
                  wmove(dialog, box_y, box_x + input_x);
                  wrefresh(dialog);
                  break;
            }
            break;
          case ' ':
          case '\r':
          case '\n':
            delwin(dialog);
            return (button != 1 ? XtNewString(instr) : NULL);
      }
    }
}

Generated by  Doxygen 1.6.0   Back to index