Activate -path and -file options
[xboard.git] / xoptions.c
index bc22faf..5ac5b02 100644 (file)
@@ -619,20 +619,10 @@ void TimeControlProc(w, event, prms, nprms)
 
 //--------------------------- Engine-specific options menu ----------------------------------
 
-int SettingsUp;
-Widget SettingsShell;
 int values[MAX_OPTIONS];
 ChessProgramState *currentCps;
-
-void SettingsPopDown()
-{
-    if (!SettingsUp) return;
-    previous = NULL;
-    XtPopdown(SettingsShell);
-    XtDestroyWidget(SettingsShell);
-    SettingsUp = False;
-    ModeHighlight();
-}
+static Option *currentOption;
+extern Widget shells[];
 
 void SpinCallback(w, client_data, call_data)
      Widget w;
@@ -649,104 +639,28 @@ void SpinCallback(w, client_data, call_data)
 
     j = 0;
     XtSetArg(args[0], XtNstring, &val);
-    XtGetValues(currentCps->option[data].handle, args, 1);
+    XtGetValues(currentOption[data].handle, args, 1);
     sscanf(val, "%d", &j);
     if (strcmp(name, "browse") == 0) {
-       if(XsraSelFile(SettingsShell, currentCps->option[data].name, NULL, NULL, "", "", 
-                                 currentCps->option[data].type == PathName ? "p" : "f", NULL, &p)) {
+       if(XsraSelFile(shells[0], currentOption[data].name, NULL, NULL, "", "", 
+                                 currentOption[data].type == PathName ? "p" : "f", NULL, &p)) {
                int len = strlen(p);
                if(len && p[len-1] == '/') p[len-1] = NULLCHAR;
                XtSetArg(args[0], XtNstring, p);
-               XtSetValues(currentCps->option[data].handle, args, 1);
+               XtSetValues(currentOption[data].handle, args, 1);
        }
-       SetFocus(currentCps->option[data].handle, SettingsShell, (XEvent*) NULL, False);
+       SetFocus(currentOption[data].handle, shells[0], (XEvent*) NULL, False);
        return;
     } else
     if (strcmp(name, "+") == 0) {
-       if(++j > currentCps->option[data].max) return;
+       if(++j > currentOption[data].max) return;
     } else
     if (strcmp(name, "-") == 0) {
-       if(--j < currentCps->option[data].min) return;
+       if(--j < currentOption[data].min) return;
     } else return;
     snprintf(buf, MSG_SIZ,  "%d", j);
     XtSetArg(args[0], XtNstring, buf);
-    XtSetValues(currentCps->option[data].handle, args, 1);
-}
-
-void SettingsCallback(w, client_data, call_data)
-     Widget w;
-     XtPointer client_data, call_data;
-{
-    String name, val;
-    Arg args[16];
-    char buf[MSG_SIZ];
-    int i, j;
-    int data = (intptr_t) client_data;
-
-    XtSetArg(args[0], XtNlabel, &name);
-    XtGetValues(w, args, 1);
-
-    if (strcmp(name, _("cancel")) == 0) {
-        SettingsPopDown();
-        return;
-    }
-    if (strcmp(name, _("OK")) == 0 || data) { // save buttons imply OK
-       for(i=0; i<currentCps->nrOptions; i++) { // send all options that had to be OK-ed to engine
-           switch(currentCps->option[i].type) {
-               case TextBox:
-                   XtSetArg(args[0], XtNstring, &val);
-                   XtGetValues(currentCps->option[i].handle, args, 1);
-                   if(strcmp(currentCps->option[i].textValue, val)) {
-                     safeStrCpy(currentCps->option[i].textValue, val, MSG_SIZ - (currentCps->option[i].textValue - currentCps->option[i].name) );
-                     snprintf(buf, MSG_SIZ,  "option %s=%s\n", currentCps->option[i].name, val);
-                     SendToProgram(buf, currentCps);
-                   }
-                   break;
-               case Spin:
-                   XtSetArg(args[0], XtNstring, &val);
-                   XtGetValues(currentCps->option[i].handle, args, 1);
-                   sscanf(val, "%d", &j);
-                   if(j > currentCps->option[i].max) j = currentCps->option[i].max;
-                   if(j < currentCps->option[i].min) j = currentCps->option[i].min;
-                   if(currentCps->option[i].value != j) {
-                       currentCps->option[i].value = j;
-                       snprintf(buf, MSG_SIZ,  "option %s=%d\n", currentCps->option[i].name, j);
-                       SendToProgram(buf, currentCps);
-                   }
-                   break;
-               case CheckBox:
-                   j = 0;
-                   XtSetArg(args[0], XtNstate, &j);
-                   XtGetValues(currentCps->option[i].handle, args, 1);
-                   if(currentCps->option[i].value != j) {
-                       currentCps->option[i].value = j;
-                       snprintf(buf, MSG_SIZ,  "option %s=%d\n", currentCps->option[i].name, j);
-                       SendToProgram(buf, currentCps);
-                   }
-                   break;
-               case ComboBox:
-                   if(currentCps->option[i].value != values[i]) {
-                       currentCps->option[i].value = values[i];
-                       snprintf(buf, MSG_SIZ,  "option %s=%s\n", currentCps->option[i].name,
-                               ((char**)currentCps->option[i].textValue)[values[i]]);
-                       SendToProgram(buf, currentCps);
-                   }
-                   break;
-           default:
-             if( appData.debugMode )
-               fprintf(debugFP, "SettingsPopUp: unexpected case in switch.\n");
-             break;
-           }
-       }
-       if(data) { // send save-button command to engine
-         snprintf(buf, MSG_SIZ,  "option %s\n", name);
-         SendToProgram(buf, currentCps);
-       }
-        SettingsPopDown();
-        return;
-    }
-    snprintf(buf, MSG_SIZ,  "option %s\n", name);
-    SendToProgram(buf, currentCps);
+    XtSetValues(currentOption[data].handle, args, 1);
 }
 
 void ComboSelect(w, addr, index) // callback for all combo items
@@ -759,8 +673,8 @@ void ComboSelect(w, addr, index) // callback for all combo items
     int j = 255 & (intptr_t) addr;
 
     values[i] = j; // store in temporary, for transfer at OK
-    XtSetArg(args[0], XtNlabel, ((char**)currentCps->option[i].textValue)[j]);
-    XtSetValues(currentCps->option[i].handle, args, 1);
+    XtSetArg(args[0], XtNlabel, ((char**)currentOption[i].textValue)[j]);
+    XtSetValues(currentOption[i].handle, args, 1);
 }
 
 void CreateComboPopup(parent, name, n, mb)
@@ -788,240 +702,14 @@ void CreateComboPopup(parent, name, n, mb)
     }
 }
 
-void
-SettingsPopUp(ChessProgramState *cps)
-{
-    Arg args[16];
-    Widget popup, layout, dialog, edit=NULL, form,  last, b_ok, b_cancel, leftMargin = NULL, textField = NULL;
-    Window root, child;
-    int x, y, i, j, height, width, h, c;
-    int win_x, win_y, maxWidth, maxTextWidth;
-    unsigned int mask;
-    char def[MSG_SIZ];
-    static char pane[6] = "paneX";
-    Widget texts[100], forelast = NULL, anchor, widest;
-
-    // to do: start up second engine if needed
-    if(!cps->initDone || !cps->nrOptions) return; // nothing to be done
-    currentCps = cps;
-
-    if(cps->nrOptions > 50) width = 4; else if(cps->nrOptions>24) width = 2; else width = 1;
-    height = cps->nrOptions / width + 1;
-     i = 0;
-    XtSetArg(args[i], XtNresizable, True); i++;
-    SettingsShell = popup =
-      XtCreatePopupShell(_("Settings Menu"), transientShellWidgetClass,
-                        shellWidget, args, i);
-
-    layout =
-      XtCreateManagedWidget(layoutName, formWidgetClass, popup,
-                           layoutArgs, XtNumber(layoutArgs));
-  for(c=0; c<width; c++) {
-    pane[4] = 'A'+c;
-    form =
-      XtCreateManagedWidget(pane, formWidgetClass, layout,
-                           formArgs, XtNumber(formArgs));
-    j=0;
-    XtSetArg(args[j], XtNfromHoriz, leftMargin);  j++;
-    XtSetValues(form, args, j);
-    leftMargin = form;
-
-    last = widest = NULL; anchor = forelast;
-    for(h=0; h<height; h++) {
-       forelast = last;
-       i = h + c*height;
-        if(i >= cps->nrOptions) break;
-       switch(cps->option[i].type) {
-         case Spin:
-           snprintf(def, MSG_SIZ,  "%d", cps->option[i].value);
-         case TextBox:
-           j=0;
-           XtSetArg(args[j], XtNfromVert, last);  j++;
-           XtSetArg(args[j], XtNborderWidth, 0);  j++;
-           XtSetArg(args[j], XtNjustify, XtJustifyLeft);  j++;
-           texts[h] =
-           dialog = XtCreateManagedWidget(cps->option[i].name, labelWidgetClass, form, args, j);
-           j=0;
-           XtSetArg(args[j], XtNfromVert, last);  j++;
-           XtSetArg(args[j], XtNfromHoriz, dialog);  j++;
-           XtSetArg(args[j], XtNborderWidth, 1); j++;
-           XtSetArg(args[j], XtNwidth, cps->option[i].type == Spin ? 40 : 175); j++;
-           XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
-           XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
-           XtSetArg(args[j], XtNdisplayCaret, False);  j++;
-           XtSetArg(args[j], XtNright, XtChainRight);  j++;
-           XtSetArg(args[j], XtNresizable, True);  j++;
-           XtSetArg(args[j], XtNstring, cps->option[i].type==Spin ? def : cps->option[i].textValue);  j++;
-           XtSetArg(args[j], XtNinsertPosition, 9999);  j++;
-           edit = last;
-           cps->option[i].handle = (void*)
-               (textField = last = XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j));
-           XtAddEventHandler(last, ButtonPressMask, False, SetFocus, (XtPointer) popup);
-           if(cps->option[i].type == TextBox) break;
-
-           // add increment and decrement controls for spin
-           j=0;
-           XtSetArg(args[j], XtNfromVert, edit);  j++;
-           XtSetArg(args[j], XtNfromHoriz, last);  j++;
-           XtSetArg(args[j], XtNheight, 10);  j++;
-           XtSetArg(args[j], XtNwidth, 20);  j++;
-           edit = XtCreateManagedWidget("+", commandWidgetClass, form, args, j);
-           XtAddCallback(edit, XtNcallback, SpinCallback,
-                         (XtPointer)(intptr_t) i);
-
-           j=0;
-           XtSetArg(args[j], XtNfromVert, edit);  j++;
-           XtSetArg(args[j], XtNfromHoriz, last);  j++;
-           XtSetArg(args[j], XtNheight, 10);  j++;
-           XtSetArg(args[j], XtNwidth, 20);  j++;
-           last = XtCreateManagedWidget("-", commandWidgetClass, form, args, j);
-           XtAddCallback(last, XtNcallback, SpinCallback,
-                         (XtPointer)(intptr_t) i);
-           break;
-         case CheckBox:
-           j=0;
-           XtSetArg(args[j], XtNfromVert, last);  j++;
-           XtSetArg(args[j], XtNwidth, 10);  j++;
-           XtSetArg(args[j], XtNheight, 10);  j++;
-           XtSetArg(args[j], XtNstate, cps->option[i].value);  j++;
-           cps->option[i].handle = (void*)
-               (dialog = XtCreateManagedWidget(" ", toggleWidgetClass, form, args, j));
-           j=0;
-           XtSetArg(args[j], XtNfromVert, last);  j++;
-           XtSetArg(args[j], XtNfromHoriz, dialog);  j++;
-           XtSetArg(args[j], XtNborderWidth, 0);  j++;
-           XtSetArg(args[j], XtNjustify, XtJustifyLeft);  j++;
-           last = XtCreateManagedWidget(cps->option[i].name, labelWidgetClass, form, args, j);
-           break;
-         case SaveButton:
-         case Button:
-           j=0;
-           XtSetArg(args[j], XtNfromVert, last);  j++;
-           XtSetArg(args[j], XtNstate, cps->option[i].value);  j++;
-           cps->option[i].handle = (void*)
-               (dialog = last = XtCreateManagedWidget(cps->option[i].name, commandWidgetClass, form, args, j));
-           XtAddCallback(last, XtNcallback, SettingsCallback,
-                         (XtPointer)(intptr_t) (cps->option[i].type == SaveButton));
-           break;
-         case ComboBox:
-           j=0;
-           XtSetArg(args[j], XtNfromVert, last);  j++;
-           XtSetArg(args[j], XtNborderWidth, 0);  j++;
-           XtSetArg(args[j], XtNjustify, XtJustifyLeft);  j++;
-           dialog = XtCreateManagedWidget(cps->option[i].name, labelWidgetClass, form, args, j);
-
-           j=0;
-           XtSetArg(args[j], XtNfromVert, last);  j++;
-           XtSetArg(args[j], XtNfromHoriz, dialog);  j++;
-           XtSetArg(args[j], XtNwidth, 100);  j++;
-           XtSetArg(args[j], XtNmenuName, XtNewString(cps->option[i].name));  j++;
-           XtSetArg(args[j], XtNlabel, ((char**)cps->option[i].textValue)[cps->option[i].value]);  j++;
-           cps->option[i].handle = (void*)
-               (last = XtCreateManagedWidget(" ", menuButtonWidgetClass, form, args, j));
-           CreateComboPopup(last, cps->option[i].name, i, (char **) cps->option[i].textValue);
-           values[i] = cps->option[i].value;
-           break;
-       default:
-         if( appData.debugMode )
-           fprintf(debugFP, "SettingsPopUp: unexpected case in switch.\n");
-         break;
-       }
-    }
-
-    // make an attempt to align all spins and textbox controls
-    maxWidth = maxTextWidth = 0;
-    for(h=0; h<height; h++) {
-       i = h + c*height;
-        if(i >= cps->nrOptions) break;
-       if(cps->option[i].type == Spin || cps->option[i].type == TextBox) {
-           Dimension w;
-           j=0;
-           XtSetArg(args[j], XtNwidth, &w);  j++;
-           XtGetValues(texts[h], args, j);
-           if(cps->option[i].type == Spin) {
-               if(w > maxWidth) maxWidth = w;
-               widest = texts[h];
-           } else {
-               if(w > maxTextWidth) maxTextWidth = w;
-               if(!widest) widest = texts[h];
-           }
-       }
-    }
-    if(maxTextWidth + 110 < maxWidth)
-        maxTextWidth = maxWidth - 110;
-    else maxWidth = maxTextWidth + 110;
-    for(h=0; h<height; h++) {
-       i = h + c*height;
-        if(i >= cps->nrOptions) break;
-       j=0;
-       if(cps->option[i].type == Spin) {
-           XtSetArg(args[j], XtNwidth, maxWidth);  j++;
-           XtSetValues(texts[h], args, j);
-       } else
-       if(cps->option[i].type == TextBox) {
-           XtSetArg(args[j], XtNwidth, maxTextWidth);  j++;
-           XtSetValues(texts[h], args, j);
-       }
-    }
-  }
-    j=0;
-    XtSetArg(args[j], XtNfromVert, anchor ? anchor : last);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainRight);  j++;
-    XtSetArg(args[j], XtNright, XtChainRight);  j++;
-    XtSetArg(args[j], XtNfromHoriz, widest ? widest : dialog);  j++;
-    b_ok = XtCreateManagedWidget(_("OK"), commandWidgetClass, form, args, j);
-    XtAddCallback(b_ok, XtNcallback, SettingsCallback, (XtPointer) 0);
-
-    XtSetArg(args[j-1], XtNfromHoriz, b_ok);
-    b_cancel = XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
-    XtAddCallback(b_cancel, XtNcallback, SettingsPopDown, (XtPointer) 0);
-
-    XtRealizeWidget(popup);
-    CatchDeleteWindow(popup, "SettingsPopDown");
-
-    XQueryPointer(xDisplay, xBoardWindow, &root, &child,
-                 &x, &y, &win_x, &win_y, &mask);
-
-    XtSetArg(args[0], XtNx, x - 10);
-    XtSetArg(args[1], XtNy, y - 30);
-    XtSetValues(popup, args, 2);
-
-    XtPopup(popup, XtGrabExclusive);
-    SettingsUp = True;
-
-    previous = NULL;
-    if(textField)SetFocus(textField, popup, (XEvent*) NULL, False);
-}
-
-void FirstSettingsProc(w, event, prms, nprms)
-     Widget w;
-     XEvent *event;
-     String *prms;
-     Cardinal *nprms;
-{
-   SettingsPopUp(&first);
-}
-
-void SecondSettingsProc(w, event, prms, nprms)
-     Widget w;
-     XEvent *event;
-     String *prms;
-     Cardinal *nprms;
-{
-   if(WaitForSecond(SettingsMenuIfReady)) return;
-   SettingsPopUp(&second);
-}
 
 //----------------------------Generic dialog --------------------------------------------
 
-// cloned from Engine Settings dialog
+// cloned from Engine Settings dialog (and later merged with it)
 
 typedef void ButtonCallback(int n);
 
 char *trialSound;
-static Option *currentOption;
 static int oldCores, oldPonder;
 int MakeColors P((void));
 void CreateGCs P((int redo));
@@ -1067,6 +755,7 @@ int PopDown(int n)
        XtSetArg(args[0], XtNleftBitmap, None);
        XtSetValues(marked[n], args, 1);
     }
+    if(!n) currentCps = NULL; // if an Engine Settings dialog was up, we must be popping it down now
     return 1;
 }
 
@@ -1474,7 +1163,7 @@ void GenericReadout()
     int i, j;
     String name, val;
     Arg args[16];
-    char buf[MSG_SIZ];
+    char buf[MSG_SIZ], **dest;
     float x;
        for(i=0; ; i++) { // send all options that had to be OK-ed to engine
            switch(currentOption[i].type) {
@@ -1483,9 +1172,13 @@ void GenericReadout()
                case PathName:
                    XtSetArg(args[0], XtNstring, &val);
                    XtGetValues(currentOption[i].handle, args, 1);
-                   if(*(char**) currentOption[i].target == NULL || strcmp(*(char**) currentOption[i].target, val)) {
-                       safeStrCpy(currentOption[i].name + 100, val, MSG_SIZ-100); // text value kept in pivate storage for each option
-                       *(char**) currentOption[i].target = currentOption[i].name + 100; // option gets to point to that
+                   dest = currentCps ? &(currentOption[i].textValue) : (char**) currentOption[i].target;
+                   if(*dest == NULL || strcmp(*dest, val)) {
+                       if(currentCps) {
+                           snprintf(buf, MSG_SIZ,  "option %s=%s\n", currentOption[i].name, val);
+                           SendToProgram(buf, currentCps);
+                       } else *dest = currentOption[i].name + 100; // option gets to point to private storage;
+                       safeStrCpy(*dest, val, MSG_SIZ - (*dest - currentOption[i].name)); // copy text there
                    }
                    break;
                case Spin:
@@ -1497,7 +1190,10 @@ void GenericReadout()
                    if(x < currentOption[i].min) x = currentOption[i].min;
                    if(currentOption[i].value != x) {
                        currentOption[i].value = x;
-                       if(currentOption[i].type == Spin) *(int*) currentOption[i].target = x;
+                       if(currentCps) { // engines never have float options, so no decimals!
+                           snprintf(buf, MSG_SIZ,  "option %s=%.0f\n", currentOption[i].name, x);
+                           SendToProgram(buf, currentCps);
+                       } else if(currentOption[i].type == Spin) *(int*) currentOption[i].target = x;
                        else *(float*) currentOption[i].target = x;
                    }
                    break;
@@ -1507,12 +1203,21 @@ void GenericReadout()
                    XtGetValues(currentOption[i].handle, args, 1);
                    if(currentOption[i].value != j) {
                        currentOption[i].value = j;
-                       *(Boolean*) currentOption[i].target = j;
+                       if(currentCps) {
+                           snprintf(buf, MSG_SIZ,  "option %s=%d\n", currentOption[i].name, j);
+                           SendToProgram(buf, currentCps);
+                       } else *(Boolean*) currentOption[i].target = j;
                    }
                    break;
                case ComboBox:
                    val = ((char**)currentOption[i].choice)[values[i]];
-                   if(val && (*(char**) currentOption[i].target == NULL || strcmp(*(char**) currentOption[i].target, val))) {
+                   if(currentCps) {
+                       if(currentOption[i].value == values[i]) break; // not changed
+                       currentOption[i].value = values[i];
+                       snprintf(buf, MSG_SIZ,  "option %s=%s\n", currentOption[i].name,
+                               ((char**)currentOption[i].textValue)[values[i]]);
+                       SendToProgram(buf, currentCps);
+                   } else if(val && (*(char**) currentOption[i].target == NULL || strcmp(*(char**) currentOption[i].target, val))) {
                      if(*(char**) currentOption[i].target) free(*(char**) currentOption[i].target);
                      *(char**) currentOption[i].target = strdup(val);
                    }
@@ -1524,6 +1229,7 @@ void GenericReadout()
            default:
                printf("GenericReadout: unexpected case in switch.\n");
                case Button:
+               case SaveButton:
                case Label:
              break;
            }
@@ -1555,8 +1261,11 @@ void GenericCallback(w, client_data, call_data)
         PopDown(data);
         return;
     }
-    if(currentOption[data].textValue);
-    ((ButtonCallback*) currentOption[data].target)(data);
+    if(currentCps) {
+       if(currentOption[data].type == SaveButton) GenericReadout();
+       snprintf(buf, MSG_SIZ,  "option %s\n", name);
+       SendToProgram(buf, currentCps);
+    } else ((ButtonCallback*) currentOption[data].target)(data);
 }
 
 int
@@ -1580,12 +1289,17 @@ GenericPopUp(Option *option, char *title, int dlgNr)
     }
 
     dialogOptions[dlgNr] = option; // make available to callback
-    // kludge: fake address of a ChessProgramState struct that contains the options, so Spin and Combo callbacks work on it
+    // post currentOption globally, so Spin and Combo callbacks can already use it
     // WARNING: this kludge does not work for persistent dialogs, so that these cannot have spin or combo controls!
-    currentCps = (ChessProgramState *) ((char *) option - ((char *)&first.option - (char *)&first));
-
-//    if(cps->nrOptions > 50) width = 4; else if(cps->nrOptions>24) width = 2; else width = 1;
-//    height = cps->nrOptions / width + 1;
+    currentOption = option;
+
+    if(currentCps) { // Settings popup for engine: format through heuristic
+       int n = currentCps->nrOptions;
+       if(n > 50) width = 4; else if(n>24) width = 2; else width = 1;
+       height = n / width + 1;
+       if(currentOption[n-1].type == Button || currentOption[n-1].type == SaveButton) currentOption[n].min = 1; // OK on same line
+       currentOption[n].type = EndMark; currentOption[n].target = NULL; // delimit list by callback-less end mark
+    }
      i = 0;
     XtSetArg(args[i], XtNresizable, True); i++;
     popup = shells[dlgNr] =
@@ -1617,7 +1331,8 @@ GenericPopUp(Option *option, char *title, int dlgNr)
            option[i].value = *(float*)option[i].target;
            goto tBox;
          case Spin:
-           snprintf(def, MSG_SIZ,  "%d", option[i].value = *(int*)option[i].target);
+           if(!currentCps) option[i].value = *(int*)option[i].target;
+           snprintf(def, MSG_SIZ,  "%d", option[i].value);
          case TextBox:
          case FileName:
          case PathName:
@@ -1652,8 +1367,9 @@ GenericPopUp(Option *option, char *title, int dlgNr)
            XtSetArg(args[j], XtNdisplayCaret, False);  j++;
            XtSetArg(args[j], XtNright, XtChainRight);  j++;
            XtSetArg(args[j], XtNresizable, True);  j++;
-           XtSetArg(args[j], XtNstring, option[i].type==Spin || option[i].type==Fractional ? def : *(char**)option[i].target);  j++;
            XtSetArg(args[j], XtNinsertPosition, 9999);  j++;
+           XtSetArg(args[j], XtNstring, option[i].type==Spin || option[i].type==Fractional ? def : 
+                               currentCps ? option[i].textValue : *(char**)option[i].target);  j++;
            edit = last;
            option[i].handle = (void*)
                (textField = last = XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j));
@@ -1692,13 +1408,14 @@ GenericPopUp(Option *option, char *title, int dlgNr)
                          (XtPointer)(intptr_t) i);
            break;
          case CheckBox:
+           if(!currentCps) option[i].value = *(Boolean*)option[i].target;
            j=0;
            XtSetArg(args[j], XtNfromVert, last);  j++;
            XtSetArg(args[j], XtNwidth, 10);  j++;
            XtSetArg(args[j], XtNheight, 10);  j++;
            XtSetArg(args[j], XtNleft, XtChainLeft); j++;
            XtSetArg(args[j], XtNright, XtChainLeft); j++;
-           XtSetArg(args[j], XtNstate, option[i].value = *(Boolean*)option[i].target);  j++;
+           XtSetArg(args[j], XtNstate, option[i].value);  j++;
            option[i].handle = (void*)
                (dialog = XtCreateManagedWidget(" ", toggleWidgetClass, form, args, j));
          case Label:
@@ -1713,6 +1430,7 @@ GenericPopUp(Option *option, char *title, int dlgNr)
            XtSetArg(args[j], XtNjustify, XtJustifyLeft);  j++;
            last = XtCreateManagedWidget(msg, labelWidgetClass, form, args, j);
            break;
+         case SaveButton:
          case Button:
            j=0;
            XtSetArg(args[j], XtNfromVert, option[i].min & 1 ? lastrow : last);  j++;
@@ -1726,7 +1444,7 @@ GenericPopUp(Option *option, char *title, int dlgNr)
            }
            option[i].handle = (void*)
                (dialog = last = XtCreateManagedWidget(option[i].name, commandWidgetClass, form, args, j));
-           if(option[i].target == NULL) SetColor( *(char**) option[i-1].target, last); else
+           if(option[i].target == NULL && !currentCps) SetColor( *(char**) option[i-1].target, last); else
            XtAddCallback(last, XtNcallback, GenericCallback,
                          (XtPointer)(intptr_t) i + (dlgNr<<16));
            if(option[i].textValue) SetColor( option[i].textValue, last);
@@ -1741,14 +1459,16 @@ GenericPopUp(Option *option, char *title, int dlgNr)
            XtSetArg(args[j], XtNjustify, XtJustifyLeft);  j++;
            texts[h] = dialog = XtCreateManagedWidget(option[i].name, labelWidgetClass, form, args, j);
 
-           for(j=0; option[i].choice[j]; j++)
+           if(currentCps) option[i].choice = (char**) option[i].textValue; else {
+             for(j=0; option[i].choice[j]; j++)
                if(*(char**)option[i].target && !strcmp(*(char**)option[i].target, option[i].choice[j])) break;
-           option[i].value = j + (option[i].choice[j] == NULL);
+             option[i].value = j + (option[i].choice[j] == NULL);
+           }
 
            j=0;
            XtSetArg(args[j], XtNfromVert, last);  j++;
            XtSetArg(args[j], XtNfromHoriz, dialog);  j++;
-           XtSetArg(args[j], XtNwidth, option[i].max ? option[i].max : 100);  j++;
+           XtSetArg(args[j], XtNwidth, option[i].max && !currentCps ? option[i].max : 100);  j++;
            XtSetArg(args[j], XtNleft, XtChainLeft); j++;
            XtSetArg(args[j], XtNmenuName, XtNewString(option[i].name));  j++;
            XtSetArg(args[j], XtNlabel, ((char**)option[i].textValue)[option[i].value]);  j++;
@@ -1945,6 +1665,32 @@ void MatchOptionsProc(w, event, prms, nprms)
    GenericPopUp(matchOptions, _("Match Options"), 0);
 }
 
+void
+SettingsPopUp(ChessProgramState *cps)
+{
+   currentCps = cps;
+   GenericPopUp(cps->option, _("Engine Settings"), 0);
+}
+
+void FirstSettingsProc(w, event, prms, nprms)
+     Widget w;
+     XEvent *event;
+     String *prms;
+     Cardinal *nprms;
+{
+   SettingsPopUp(&first);
+}
+
+void SecondSettingsProc(w, event, prms, nprms)
+     Widget w;
+     XEvent *event;
+     String *prms;
+     Cardinal *nprms;
+{
+   if(WaitForSecond(SettingsMenuIfReady)) return;
+   SettingsPopUp(&second);
+}
+
 //---------------------------- Chat Windows ----------------------------------------------
 
 void OutputChatMessage(int partner, char *mess)