Deselect first char in Move Type-in and ICS Input Box
[xboard.git] / xoptions.c
index af309a1..583ab9d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * xoptions.c -- Move list window, part of X front end for XBoard
  *
- * Copyright 2000, 2009, 2010 Free Software Foundation, Inc.
+ * Copyright 2000, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
  * ------------------------------------------------------------------------
  *
  * GNU XBoard is free software: you can redistribute it and/or modify
@@ -47,28 +47,17 @@ extern char *getenv();
 #endif
 #include <stdint.h>
 
-#include <X11/Intrinsic.h>
-#include <X11/StringDefs.h>
-#include <X11/Shell.h>
-#include <X11/Xaw/Dialog.h>
-#include <X11/Xaw/Form.h>
-#include <X11/Xaw/List.h>
-#include <X11/Xaw/Label.h>
-#include <X11/Xaw/SimpleMenu.h>
-#include <X11/Xaw/SmeBSB.h>
-#include <X11/Xaw/SmeLine.h>
-#include <X11/Xaw/Box.h>
-#include <X11/Xaw/Paned.h>
-#include <X11/Xaw/MenuButton.h>
-#include <X11/cursorfont.h>
-#include <X11/Xaw/Text.h>
-#include <X11/Xaw/AsciiText.h>
-#include <X11/Xaw/Viewport.h>
-#include <X11/Xaw/Toggle.h>
+#include <cairo/cairo.h>
+#include <cairo/cairo-xlib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>  
 
 #include "common.h"
 #include "backend.h"
 #include "xboard.h"
+#include "xboard2.h"
+#include "dialogs.h"
+#include "menus.h"
 #include "gettext.h"
 
 #ifdef ENABLE_NLS
@@ -79,1602 +68,1710 @@ extern char *getenv();
 # define N_(s)  s
 #endif
 
-extern void SendToProgram P((char *message, ChessProgramState *cps));
-
-extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
-extern Display *xDisplay;
-extern int squareSize;
-extern Pixmap xMarkPixmap;
-extern char *layoutName;
-extern Window xBoardWindow;
-extern Arg layoutArgs[2], formArgs[2];
-Pixel timerForegroundPixel, timerBackgroundPixel;
-extern int searchTime;
-
 // [HGM] the following code for makng menu popups was cloned from the FileNamePopUp routines
 
+#ifdef TODO_GTK
 static Widget previous = NULL;
+#endif
+static Option *currentOption;
+static Boolean browserUp;
 
-void SetFocus(Widget w, XtPointer data, XEvent *event, Boolean *b)
+void
+UnCaret ()
 {
-    Arg args;
+#ifdef TODO_GTK
+    Arg args[2];
 
     if(previous) {
-       XtSetArg(args, XtNdisplayCaret, False);
-       XtSetValues(previous, &args, 1);
+       XtSetArg(args[0], XtNdisplayCaret, False);
+       XtSetValues(previous, args, 1);
     }
-    XtSetArg(args, XtNdisplayCaret, True);
-    XtSetValues(w, &args, 1);
-    XtSetKeyboardFocus((Widget) data, w);
-    previous = w;
-}
-
-//--------------------------- New Shuffle Game --------------------------------------------
-extern int shuffleOpenings;
-extern int startedFromPositionFile;
-int shuffleUp;
-Widget shuffleShell;
-
-void ShufflePopDown()
-{
-    if (!shuffleUp) return;
-    XtPopdown(shuffleShell);
-    XtDestroyWidget(shuffleShell);
-    shuffleUp = False;
-    ModeHighlight();
+    previous = NULL;
+#endif
 }
 
-void ShuffleCallback(w, client_data, call_data)
-     Widget w;
-     XtPointer client_data, call_data;
+#ifdef TODO_GTK
+void
+SetFocus (Widget w, XtPointer data, XEvent *event, Boolean *b)
 {
-    String name;
-    Widget w2;
-    Arg args[16];
-    char buf[MSG_SIZ];
+    Arg args[2];
+    char *s;
+    int j;
 
-    XtSetArg(args[0], XtNlabel, &name);
+    UnCaret();
+    XtSetArg(args[0], XtNstring, &s);
     XtGetValues(w, args, 1);
-
-    if (strcmp(name, _("cancel")) == 0) {
-        ShufflePopDown();
-        return;
-    }
-    if (strcmp(name, _("off")) == 0) {
-        ShufflePopDown();
-       shuffleOpenings = False; // [HGM] should be moved to New Variant menu, once we have it!
-       ResetGameEvent();
-        return;
-    }
-    if (strcmp(name, _("random")) == 0) {
-      snprintf(buf, MSG_SIZ,  "%d", rand());
-       XtSetArg(args[0],XtNvalue, buf); // erase bad (non-numeric) value
-       XtSetValues(XtParent(w), args, 1);
-        return;
-    }
-    if (strcmp(name, _("ok")) == 0) {
-       int nr; String name;
-        name = XawDialogGetValueString(w2 = XtParent(w));
-       if(sscanf(name ,"%d",&nr) != 1) {
-         snprintf(buf, MSG_SIZ,  "%d", appData.defaultFrcPosition);
-           XtSetArg(args[0],XtNvalue, buf); // erase bad (non-numeric) value
-           XtSetValues(w2, args, 1);
-           return;
-       }
-       appData.defaultFrcPosition = nr;
-       shuffleOpenings = True;
-        ShufflePopDown();
-       ResetGameEvent();
-        return;
-    }
+    j = 1;
+    XtSetArg(args[0], XtNdisplayCaret, True);
+    if(!strchr(s, '\n') && strlen(s) < 80) XtSetArg(args[1], XtNinsertPosition, strlen(s)), j++;
+    XtSetValues(w, args, j);
+    XtSetKeyboardFocus((Widget) data, w);
+    previous = w;
 }
+#endif
 
-void ShufflePopUp()
+void
+BoardFocus ()
 {
-    Arg args[16];
-    Widget popup, layout, dialog, edit;
-    Window root, child;
-    int x, y, i;
-    int win_x, win_y;
-    unsigned int mask;
-    char def[MSG_SIZ];
-
-    i = 0;
-    XtSetArg(args[i], XtNresizable, True); i++;
-    XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
-    shuffleShell = popup =
-      XtCreatePopupShell(_("New Shuffle Game"), transientShellWidgetClass,
-                        shellWidget, args, i);
-
-    layout =
-      XtCreateManagedWidget(layoutName, formWidgetClass, popup,
-                           layoutArgs, XtNumber(layoutArgs));
-
-    snprintf(def, MSG_SIZ,  "%d\n", appData.defaultFrcPosition);
-    i = 0;
-    XtSetArg(args[i], XtNlabel, _("Start-position number:")); i++;
-    XtSetArg(args[i], XtNvalue, def); i++;
-    XtSetArg(args[i], XtNborderWidth, 0); i++;
-    dialog = XtCreateManagedWidget(_("Shuffle"), dialogWidgetClass,
-                                  layout, args, i);
+#ifdef TODO_GTK
+    XtSetKeyboardFocus(shellWidget, formWidget);
+#endif
+}
 
-//    XtSetArg(args[0], XtNeditType, XawtextEdit);  // [HGM] can't get edit to work decently
-//    XtSetArg(args[1], XtNuseStringInPlace, False);
-//    XtSetValues(dialog, args, 2);
+//--------------------------- Engine-specific options menu ----------------------------------
 
-    XawDialogAddButton(dialog, _("ok"), ShuffleCallback, (XtPointer) dialog);
-    XawDialogAddButton(dialog, _("cancel"), ShuffleCallback, (XtPointer) dialog);
-    XawDialogAddButton(dialog, _("random"), ShuffleCallback, (XtPointer) dialog);
-    XawDialogAddButton(dialog, _("off"), ShuffleCallback, (XtPointer) dialog);
+int dialogError;
+Option *dialogOptions[NrOfDialogs];
 
-    XtRealizeWidget(popup);
-    CatchDeleteWindow(popup, "ShufflePopDown");
+#ifdef TODO_GTK
+static Arg layoutArgs[] = {
+    { XtNborderWidth, 0 },
+    { XtNdefaultDistance, 0 },
+};
 
-    XQueryPointer(xDisplay, xBoardWindow, &root, &child,
-                 &x, &y, &win_x, &win_y, &mask);
+static Arg formArgs[] = {
+    { XtNborderWidth, 0 },
+    { XtNresizable, (XtArgVal) True },
+};
+#endif
 
-    XtSetArg(args[0], XtNx, x - 10);
-    XtSetArg(args[1], XtNy, y - 30);
-    XtSetValues(popup, args, 2);
+void
+MarkMenuItem (char *menuRef, int state)
+{
+    MenuItem *item = MenuNameToItem(menuRef);
 
-    XtPopup(popup, XtGrabExclusive);
-    shuffleUp = True;
+    if(item) {
+        ((GtkCheckMenuItem *) (item->handle))->active = state;
+    }
+}
 
-    edit = XtNameToWidget(dialog, "*value");
+void GetWidgetTextGTK(GtkWidget *w, char **buf)
+{        
+    GtkTextIter start;
+    GtkTextIter end;    
 
-    XtSetKeyboardFocus(popup, edit);
+    if (GTK_IS_ENTRY(w)) {
+       *buf = gtk_entry_get_text(GTK_ENTRY (w));
+    } else
+    if (GTK_IS_TEXT_BUFFER(w)) {
+        gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(w), &start);
+        gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(w), &end);
+        *buf = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(w), &start, &end, FALSE);
+    }
+    else {
+        printf("error in GetWidgetText, invalid widget\n");
+        *buf = NULL; 
+    }
 }
 
-void ShuffleMenuProc(w, event, prms, nprms)
-     Widget w;
-     XEvent *event;
-     String *prms;
-     Cardinal *nprms;
+void
+GetWidgetText (Option *opt, char **buf)
 {
-//    if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
-//     Reset(FALSE, TRUE);
-//    }
-    ShufflePopUp();
+    int x;
+    static char val[12];
+    switch(opt->type) {
+      case Fractional:
+      case FileName:
+      case PathName:
+      case TextBox: GetWidgetTextGTK((GtkWidget *) opt->handle, buf); break;
+      case Spin:
+       x = gtk_spin_button_get_value (GTK_SPIN_BUTTON(opt->handle));                   
+       snprintf(val, 12, "%d", x); *buf = val;
+       break;
+      default:
+       printf("unexpected case (%d) in GetWidgetText\n", opt->type);
+       *buf = NULL;
+    }
 }
 
-//--------------------------- Time-Control Menu Popup ----------------------------------
-int TimeControlUp;
-Widget TimeControlShell;
-int tcInc;
-Widget tcMess1, tcMess2, tcData, tcTime, tcOdds1, tcOdds2;
-int tcIncrement, tcMoves;
+void SetSpinValue(Option *opt, char *val, int n)
+{    
+    if (opt->type == Spin)
+      {
+        if (!strcmp(val, _("Unused")))
+           gtk_widget_set_sensitive(opt->handle, FALSE);
+        else
+          {
+            gtk_widget_set_sensitive(opt->handle, TRUE);      
+            gtk_spin_button_set_value(opt->handle, atoi(val));
+          }
+      }
+    else
+      printf("error in SetSpinValue, unknown type %d\n", opt->type);    
+}
 
-void TimeControlPopDown()
+void SetWidgetTextGTK(GtkWidget *w, char *text)
 {
-    if (!TimeControlUp) return;
-    previous = NULL;
-    XtPopdown(TimeControlShell);
-    XtDestroyWidget(TimeControlShell);
-    TimeControlUp = False;
-    ModeHighlight();
+    if (GTK_IS_ENTRY(w)) {
+       gtk_entry_set_text (GTK_ENTRY (w), text);
+    } else
+    if (GTK_IS_TEXT_BUFFER(w)) {
+       gtk_text_buffer_set_text(GTK_TEXT_BUFFER(w), text, -1);
+    } else
+       printf("error: SetWidgetTextGTK arg is neitherGtkEntry nor GtkTextBuffer\n");
 }
 
-void TimeControlCallback(w, client_data, call_data)
-     Widget w;
-     XtPointer client_data, call_data;
+void
+SetWidgetText (Option *opt, char *buf, int n)
 {
-    String name, txt;
-    Arg args[16];
-    char buf[MSG_SIZ];
-    int j;
-
-    XtSetArg(args[0], XtNlabel, &name);
-    XtGetValues(w, args, 1);
-
-    if (strcmp(name, _("classical")) == 0) {
-       if(tcInc == 0) return;
-       j=0;
-       XtSetArg(args[j], XtNlabel, _("minutes for each")); j++;
-       XtSetValues(tcMess1, args, j);
-       j=0;
-       XtSetArg(args[j], XtNlabel, _("moves")); j++;
-       XtSetValues(tcMess2, args, j);
-       if(tcInc == 1) {
-           j=0;
-           XtSetArg(args[j], XtNstring, &name); j++;
-           XtGetValues(tcData, args, j);
-           tcIncrement = 0; sscanf(name, "%d", &tcIncrement);
-       }
-       snprintf(buf, MSG_SIZ,  "%d", tcMoves);
-       j=0;
-       XtSetArg(args[j], XtNstring, buf); j++;
-       XtSetValues(tcData, args, j);
-       tcInc = 0;
-        return;
-    }
-    if (strcmp(name, _("incremental")) == 0) {
-       if(tcInc == 1) return;
-       j=0;
-       XtSetArg(args[j], XtNlabel, _("minutes, plus")); j++;
-       XtSetValues(tcMess1, args, j);
-       j=0;
-       XtSetArg(args[j], XtNlabel, _("sec/move")); j++;
-       XtSetValues(tcMess2, args, j);
-       if(tcInc == 0) {
-           j=0;
-           XtSetArg(args[j], XtNstring, &name); j++;
-           XtGetValues(tcData, args, j);
-           tcMoves = appData.movesPerSession; sscanf(name, "%d", &tcMoves);
-       }
-       snprintf(buf, MSG_SIZ,  "%d", tcIncrement);
-       j=0;
-       XtSetArg(args[j], XtNstring, buf); j++;
-       XtSetValues(tcData, args, j);
-       tcInc = 1;
-        return;
-    }
-    if (strcmp(name, _("fixed time")) == 0) {
-       if(tcInc == 2) return;
-       j=0;
-       XtSetArg(args[j], XtNlabel, _("sec/move (max)")); j++;
-       XtSetValues(tcMess1, args, j);
-       j=0;
-       XtSetArg(args[j], XtNlabel, _("")); j++;
-       XtSetValues(tcMess2, args, j);
-       j=0;
-       XtSetArg(args[j], XtNstring, ""); j++;
-       XtSetValues(tcData, args, j);
-       tcInc = 2;
-        return;
-    }
-    if (strcmp(name, _(" OK ")) == 0) {
-       int inc, mps, ok;
-       XtSetArg(args[0], XtNstring, &txt);
-       XtGetValues(tcData, args, 1);
-       switch(tcInc) {
-         case 1:
-           ok = sscanf(txt, "%d", &inc); mps = 0;
-           if(!ok && txt[0] == 0) { inc = 0; ok = 1; } // accept empty string as zero
-           ok &= (inc >= 0);
-           break;
-         case 0:
-           ok = sscanf(txt, "%d", &mps); inc = -1;
-           ok &= (mps > 0);
-           break;
-         case 2:
-           ok = 1; inc = -1; mps = 40;
-       }
-       if(ok != 1) {
-           XtSetArg(args[0], XtNstring, ""); // erase any offending input
-           XtSetValues(tcData, args, 1);
-           return;
-       }
-       XtSetArg(args[0], XtNstring, &txt);
-       XtGetValues(tcTime, args, 1);
-       if(tcInc == 2) {
-           if(sscanf(txt, "%d", &inc) != 1) {
-               XtSetArg(args[0], XtNstring, ""); // erase any offending input
-               XtSetValues(tcTime, args, 1);
-               DisplayError(_("Bad Time-Control String"), 0);
-               return;
-           }
-           searchTime = inc;
-       } else {
-           if(!ParseTimeControl(txt, inc, mps)) {
-               XtSetArg(args[0], XtNstring, ""); // erase any offending input
-               XtSetValues(tcTime, args, 1);
-               DisplayError(_("Bad Time-Control String"), 0);
-               return;
-           }
-           searchTime = 0;
-           appData.movesPerSession = mps;
-           appData.timeIncrement = inc;
-           appData.timeControl = strdup(txt);
-       }
-       XtSetArg(args[0], XtNstring, &txt);
-       XtGetValues(tcOdds1, args, 1);
-       appData.firstTimeOdds = first.timeOdds
-               = (sscanf(txt, "%d", &j) == 1 && j > 0) ? j : 1;
-       XtGetValues(tcOdds2, args, 1);
-       appData.secondTimeOdds = second.timeOdds
-               = (sscanf(txt, "%d", &j) == 1 && j > 0) ? j : 1;
-
-       Reset(True, True);
-        TimeControlPopDown();
-        return;
+    switch(opt->type) {
+      case Fractional:
+      case FileName:
+      case PathName:
+      case TextBox: SetWidgetTextGTK((GtkWidget *) opt->handle, buf); break;
+      case Spin: SetSpinValue(opt, buf, n); break;
+      default:
+       printf("unexpected case (%d) in GetWidgetText\n", opt->type);
     }
+#ifdef TODO_GTK
+// focus is automatic in GTK?
+    if(n >= 0) SetFocus(opt->handle, shells[n], NULL, False);
+#endif
 }
 
-void TimeControlPopUp()
+void
+GetWidgetState (Option *opt, int *state)
 {
-    Arg args[16];
-    Widget popup, layout, form,  b_ok, b_cancel, b_clas, b_inc, mess;
-    Window root, child;
-    int x, y, i, j;
-    int win_x, win_y;
-    unsigned int mask;
-    char def[MSG_SIZ];
-
-    tcInc = searchTime > 0 ? 2 : (appData.timeIncrement >= 0);
-    tcMoves = appData.movesPerSession; tcIncrement = appData.timeIncrement;
-    if(!tcInc) tcIncrement = 0;
-    snprintf(def, MSG_SIZ,  "%d", tcInc ? tcIncrement : tcMoves);
-
-    i = 0;
-    XtSetArg(args[i], XtNresizable, True); i++;
-//    XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
-    TimeControlShell = popup =
-      XtCreatePopupShell(_("TimeControl Menu"), transientShellWidgetClass,
-                        shellWidget, args, i);
-
-    layout =
-      XtCreateManagedWidget(layoutName, formWidgetClass, popup,
-                           layoutArgs, XtNumber(layoutArgs));
-
-    form =
-      XtCreateManagedWidget(layoutName, formWidgetClass, layout,
-                           formArgs, XtNumber(formArgs));
-
-    j = 0;
-//    XtSetArg(args[j], XtNwidth,     (XtArgVal) 300); j++;
-//    XtSetArg(args[j], XtNheight,    (XtArgVal) 85); j++;
-    XtSetValues(popup, args, j);
-
-    j= 0;
-    XtSetArg(args[j], XtNborderWidth, 1); j++;
-    XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
-    XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
-    XtSetArg(args[j], XtNstring, appData.timeControl);  j++;
-    XtSetArg(args[j], XtNdisplayCaret, False);  j++;
-    XtSetArg(args[j], XtNtop, XtChainTop);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainRight);  j++;
-    XtSetArg(args[j], XtNresizable, True);  j++;
-    XtSetArg(args[j], XtNwidth,  85);  j++;
-    XtSetArg(args[j], XtNinsertPosition, 9999);  j++;
-    tcTime = XtCreateManagedWidget("TC", asciiTextWidgetClass, form, args, j);
-    XtAddEventHandler(tcTime, ButtonPressMask, False, SetFocus, (XtPointer) popup);
-
-    j= 0;
-    XtSetArg(args[j], XtNlabel, tcInc ? tcInc == 2 ? _("sec/move (max)   ") : _("   minutes, plus   ") : _("minutes for each")); j++;
-    XtSetArg(args[j], XtNborderWidth, 0); j++;
-    XtSetArg(args[j], XtNfromHoriz, tcTime); j++;
-    XtSetArg(args[j], XtNtop, XtChainTop);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
-    XtSetArg(args[j], XtNleft, XtChainRight);  j++;
-    XtSetArg(args[j], XtNright, XtChainRight);  j++;
-  //  XtSetArg(args[j], XtNwidth,  100);  j++;
-  //  XtSetArg(args[j], XtNheight, 20);  j++;
-    tcMess1 = XtCreateManagedWidget("TCtext", labelWidgetClass, form, args, j);
-
-    j= 0;
-    XtSetArg(args[j], XtNborderWidth, 1); j++;
-    XtSetArg(args[j], XtNfromHoriz, tcMess1); j++;
-    XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
-    XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
-    XtSetArg(args[j], XtNstring, def);  j++;
-    XtSetArg(args[j], XtNdisplayCaret, False);  j++;
-    XtSetArg(args[j], XtNtop, XtChainTop);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
-    XtSetArg(args[j], XtNleft, XtChainRight);  j++;
-    XtSetArg(args[j], XtNright, XtChainRight);  j++;
-    XtSetArg(args[j], XtNresizable, True);  j++;
-    XtSetArg(args[j], XtNwidth,  40);  j++;
-//    XtSetArg(args[j], XtNheight, 20);  j++;
-    tcData = XtCreateManagedWidget("MPS", asciiTextWidgetClass, form, args, j);
-    XtAddEventHandler(tcData, ButtonPressMask, False, SetFocus, (XtPointer) popup);
-
-    j= 0;
-    XtSetArg(args[j], XtNlabel, tcInc ? tcInc == 2 ? _("             ") : _("sec/move") : _("moves     ")); j++;
-    XtSetArg(args[j], XtNjustify, XtJustifyLeft); j++;
-    XtSetArg(args[j], XtNborderWidth, 0); j++;
-    XtSetArg(args[j], XtNfromHoriz, tcData); j++;
-    XtSetArg(args[j], XtNtop, XtChainTop);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
-    XtSetArg(args[j], XtNleft, XtChainRight);  j++;
-    XtSetArg(args[j], XtNright, XtChainRight);  j++;
-//    XtSetArg(args[j], XtNwidth,  80);  j++;
-//    XtSetArg(args[j], XtNheight, 20);  j++;
-    tcMess2 = XtCreateManagedWidget("MPStext", labelWidgetClass,
-                                  form, args, j);
-
-    j= 0;
-    XtSetArg(args[j], XtNborderWidth, 1); j++;
-    XtSetArg(args[j], XtNfromVert, tcTime); j++;
-    XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
-    XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
-    XtSetArg(args[j], XtNstring, "1");  j++;
-    XtSetArg(args[j], XtNdisplayCaret, False);  j++;
-    XtSetArg(args[j], XtNtop, XtChainTop);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNresizable, True);  j++;
-    XtSetArg(args[j], XtNwidth,  40);  j++;
-//    XtSetArg(args[j], XtNheight, 20);  j++;
-    tcOdds1 = XtCreateManagedWidget("Odds1", asciiTextWidgetClass, form, args, j);
-    XtAddEventHandler(tcOdds1, ButtonPressMask, False, SetFocus, (XtPointer) popup);
-
-    j= 0;
-    XtSetArg(args[j], XtNborderWidth, 1); j++;
-    XtSetArg(args[j], XtNfromVert, tcTime); j++;
-    XtSetArg(args[j], XtNfromHoriz, tcOdds1); j++;
-    XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
-    XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
-    XtSetArg(args[j], XtNstring, "1");  j++;
-    XtSetArg(args[j], XtNdisplayCaret, False);  j++;
-    XtSetArg(args[j], XtNtop, XtChainTop);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNresizable, True);  j++;
-    XtSetArg(args[j], XtNwidth,  40);  j++;
-//    XtSetArg(args[j], XtNheight, 20);  j++;
-    tcOdds2 = XtCreateManagedWidget("Odds2", asciiTextWidgetClass, form, args, j);
-    XtAddEventHandler(tcOdds2, ButtonPressMask, False, SetFocus, (XtPointer) popup);
-
-    j= 0;
-    XtSetArg(args[j], XtNlabel, _("Engine #1 and #2 Time-Odds Factors")); j++;
-    XtSetArg(args[j], XtNjustify, XtJustifyLeft); j++;
-    XtSetArg(args[j], XtNborderWidth, 0); j++;
-    XtSetArg(args[j], XtNfromVert, tcTime); j++;
-    XtSetArg(args[j], XtNfromHoriz, tcOdds2); j++;
-    XtSetArg(args[j], XtNtop, XtChainTop);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainRight);  j++;
-//    XtSetArg(args[j], XtNwidth,  200);  j++;
-//    XtSetArg(args[j], XtNheight, 20);  j++;
-    mess = XtCreateManagedWidget("Oddstext", labelWidgetClass,
-                                  form, args, j);
-    j=0;
-    XtSetArg(args[j], XtNfromVert, tcOdds1);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNstate, tcInc==0); j++;
-    b_clas= XtCreateManagedWidget(_("classical"), toggleWidgetClass,
-                                  form, args, j);
-    XtAddCallback(b_clas, XtNcallback, TimeControlCallback, (XtPointer) 0);
-
-    j=0;
-    XtSetArg(args[j], XtNradioGroup, b_clas); j++;
-    XtSetArg(args[j], XtNfromVert, tcOdds1);  j++;
-    XtSetArg(args[j], XtNfromHoriz, b_clas);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNstate, tcInc==1); j++;
-    b_inc = XtCreateManagedWidget(_("incremental"), toggleWidgetClass,
-                                  form, args, j);
-    XtAddCallback(b_inc, XtNcallback, TimeControlCallback, (XtPointer) 0);
-
-    j=0;
-    XtSetArg(args[j], XtNradioGroup, b_inc); j++;
-    XtSetArg(args[j], XtNfromVert, tcOdds1);  j++;
-    XtSetArg(args[j], XtNfromHoriz, b_inc);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNstate, tcInc==2); j++;
-    b_inc = XtCreateManagedWidget(_("fixed time"), toggleWidgetClass,
-                                  form, args, j);
-    XtAddCallback(b_inc, XtNcallback, TimeControlCallback, (XtPointer) 0);
+    *state = gtk_toggle_button_get_active(opt->handle);
+}
 
-    j=0;
-    XtSetArg(args[j], XtNfromVert, tcOdds1);  j++;
-    XtSetArg(args[j], XtNfromHoriz, tcData);  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++;
-    b_ok= XtCreateManagedWidget(_(" OK "), commandWidgetClass,
-                                  form, args, j);
-    XtAddCallback(b_ok, XtNcallback, TimeControlCallback, (XtPointer) 0);
+void
+SetWidgetState (Option *opt, int state)
+{
+    gtk_toggle_button_set_active(opt->handle, state);
+}
 
-    j=0;
-    XtSetArg(args[j], XtNfromVert, tcOdds1);  j++;
-    XtSetArg(args[j], XtNfromHoriz, b_ok);  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++;
-    b_cancel= XtCreateManagedWidget(_("cancel"), commandWidgetClass,
-                                  form, args, j);
-    XtAddCallback(b_cancel, XtNcallback, TimeControlPopDown, (XtPointer) 0);
+void
+SetWidgetLabel (Option *opt, char *buf)
+{
+    gtk_label_set_text(opt->handle, buf);
+}
 
-    XtRealizeWidget(popup);
-    CatchDeleteWindow(popup, "TimeControlPopDown");
+void
+SetDialogTitle (DialogClass dlg, char *title)
+{
+    gtk_window_set_title(GTK_WINDOW(shells[dlg]), title);
+}
 
-    XQueryPointer(xDisplay, xBoardWindow, &root, &child,
-                 &x, &y, &win_x, &win_y, &mask);
+void
+SetListBoxItem (GtkListStore *store, int n, char *msg)
+{
+    GtkTreeIter iter;
+    GtkTreePath *path = gtk_tree_path_new_from_indices(n, -1);
+    gtk_tree_model_get_iter(GTK_TREE_MODEL (store), &iter, path);
+    gtk_tree_path_free(path);
+    gtk_list_store_set(store, &iter, 0, msg, -1);
+}
 
-    XtSetArg(args[0], XtNx, x - 10);
-    XtSetArg(args[1], XtNy, y - 30);
-    XtSetValues(popup, args, 2);
+void
+LoadListBox (Option *opt, char *emptyText, int n1, int n2)
+{
+    char **data = (char **) (opt->target);
+    GtkWidget *list = (GtkWidget *) (opt->handle);
+    GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
+    GtkListStore *store = GTK_LIST_STORE(model);
+    GtkTreeIter iter;
+    if(n1 >= 0 && n2 >= 0) {
+       SetListBoxItem(store, n1, data[n1]);
+       SetListBoxItem(store, n2, data[n2]);
+       return;
+    }
 
-    XtPopup(popup, XtGrabExclusive);
-    TimeControlUp = True;
+    if (gtk_tree_model_get_iter_first(model, &iter)) 
+       gtk_list_store_clear(store);
 
-    previous = NULL;
-    SetFocus(tcTime, popup, (XEvent*) NULL, False);
-//    XtSetKeyboardFocus(popup, tcTime);
+    while(*data) { // add elements to listbox one by one
+        gtk_list_store_append(store, &iter);
+        gtk_list_store_set(store, &iter, 0, *data++, -1); // 0 = first column
+    }
 }
 
-void TimeControlProc(w, event, prms, nprms)
-     Widget w;
-     XEvent *event;
-     String *prms;
-     Cardinal *nprms;
+void
+HighlightItem (Option *opt, int index, int scroll)
 {
-   TimeControlPopUp();
+    char *value, **data = (char **) (opt->target);
+    GtkWidget *list = (GtkWidget *) (opt->handle);
+    GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
+    GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
+    GtkListStore *store = GTK_LIST_STORE(model);
+    GtkTreePath *path = gtk_tree_path_new_from_indices(index, -1);
+    GtkTreeIter iter;
+    gtk_tree_selection_select_path(selection, path);
+    if(scroll) gtk_tree_view_scroll_to_cell(list, path, NULL, 0, 0, 0);
+    gtk_tree_path_free(path);
 }
 
-//--------------------------- Engine-Options Menu Popup ----------------------------------
-int EngineUp;
-Widget EngineShell;
-extern int adjudicateLossThreshold;
-
-Widget engDrawMoves, engThreshold, engRule, engRepeat;
-
-void EnginePopDown()
+void
+HighlightListBoxItem (Option *opt, int index)
 {
-    if (!EngineUp) return;
-    previous = NULL;
-    XtPopdown(EngineShell);
-    XtDestroyWidget(EngineShell);
-    EngineUp = False;
-    ModeHighlight();
+    HighlightItem (opt, index, FALSE);
 }
 
-int ReadToggle(Widget w)
+void
+HighlightWithScroll (Option *opt, int index, int max)
 {
-    Arg args; Boolean res;
+    HighlightItem (opt, index, TRUE); // ignore max
+}
 
-    XtSetArg(args, XtNstate, &res);
-    XtGetValues(w, &args, 1);
+int
+SelectedListBoxItem (Option *opt)
+{
+    int i;
+    char *value, **data = (char **) (opt->target);
+    GtkWidget *list = (GtkWidget *) (opt->handle);
+    GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
+
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    if (!gtk_tree_selection_get_selected(GTK_TREE_SELECTION(selection), &model, &iter)) return -1;
+    gtk_tree_model_get(model, &iter, 0, &value,  -1);
+    for(i=0; data[i]; i++) if(!strcmp(data[i], value)) return i;
+    g_free(value);
+    return -1;
+}
 
-    return res;
+void
+FocusOnWidget (Option *opt, DialogClass dlg)
+{
+    UnCaret();
+#ifdef TODO_GTK
+    XtSetKeyboardFocus(shells[dlg], opt->handle);
+#endif
+    gtk_widget_grab_focus(opt->handle);
 }
 
-Widget w1, w2, w3, w4, w5, w6, w7, w8;
+void
+SetIconName (DialogClass dlg, char *name)
+{
+#ifdef TODO_GTK
+       Arg args[16];
+       int j = 0;
+       XtSetArg(args[j], XtNiconName, (XtArgVal) name);  j++;
+//     XtSetArg(args[j], XtNtitle, (XtArgVal) name);  j++;
+       XtSetValues(shells[dlg], args, j);
+#endif
+}
 
-void EngineCallback(w, client_data, call_data)
-     Widget w;
-     XtPointer client_data, call_data;
+void ComboSelect(GtkWidget *widget, gpointer addr)
 {
-    String name;
-    Arg args[16];
-    int j;
+    Option *opt = dialogOptions[((intptr_t)addr)>>8]; // applicable option list
+    gint i = ((intptr_t)addr) & 255; // option number
+    gint g;
 
-    XtSetArg(args[0], XtNlabel, &name);
-    XtGetValues(w, args, 1);
+    g = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));    
+    values[i] = g; // store in temporary, for transfer at OK
 
-    if (strcmp(name, _("OK")) == 0) {
-       // read all switches
-       appData.periodicUpdates = ReadToggle(w1);
-//     appData.hideThinkingFromHuman = ReadToggle(w2);
-       first.scoreIsAbsolute  = appData.firstScoreIsAbsolute  = ReadToggle(w3);
-       second.scoreIsAbsolute = appData.secondScoreIsAbsolute = ReadToggle(w4);
-       appData.testClaims    = ReadToggle(w5);
-       appData.checkMates    = ReadToggle(w6);
-       appData.materialDraws = ReadToggle(w7);
-       appData.trivialDraws  = ReadToggle(w8);
-
-       // adjust setting in other menu for duplicates
-       // (perhaps duplicates should be removed from general Option Menu?)
-//     XtSetArg(args[0], XtNleftBitmap, appData.showThinking ? xMarkPixmap : None);
-//     XtSetValues(XtNameToWidget(menuBarWidget,
-//                                "menuOptions.Show Thinking"), args, 1);
-
-       // read out numeric controls, simply ignore bad formats for now
-       XtSetArg(args[0], XtNstring, &name);
-       XtGetValues(engDrawMoves, args, 1);
-       if(sscanf(name, "%d", &j) == 1) appData.adjudicateDrawMoves = j;
-       XtGetValues(engThreshold, args, 1);
-       if(sscanf(name, "%d", &j) == 1)
-               adjudicateLossThreshold = appData.adjudicateLossThreshold = -j; // inverted!
-       XtGetValues(engRule, args, 1);
-       if(sscanf(name, "%d", &j) == 1) appData.ruleMoves = j;
-       XtGetValues(engRepeat, args, 1);
-       if(sscanf(name, "%d", &j) == 1) appData.drawRepeats = j;
-
-        EnginePopDown();
-       ShowThinkingEvent(); // [HGM] thinking: score adjudication might need thinking output
-        return;
+#if TODO_GTK
+// Note: setting text on button is probably automatic
+// Is this still needed? Could be all comboboxes that needed a callbak are now listboxes!
+#endif
+    if(opt[i].type == Graph || opt[i].min & COMBO_CALLBACK && (!currentCps || shellUp[BrowserDlg])) {
+       ((ButtonCallback*) opt[i].target)(i);
+       return;
     }
 }
 
-void EnginePopUp()
+#ifdef TODO_GTK
+Widget
+CreateMenuItem (Widget menu, char *msg, XtCallbackProc CB, int n)
 {
+    int j=0;
+    Widget entry;
     Arg args[16];
-    Widget popup, layout, form,  b_ok, b_cancel,  s1;
-    Window root, child;
-    int x, y, i, j, width;
-    int win_x, win_y;
-    unsigned int mask;
-    char def[MSG_SIZ];
-
-    tcInc = (appData.timeIncrement >= 0);
-    tcMoves = appData.movesPerSession; tcIncrement = appData.timeIncrement;
-    if(!tcInc) tcIncrement = 0;
-    snprintf(def, MSG_SIZ,  "%d", tcInc ? tcIncrement : tcMoves);
-
-    i = 0;
-    XtSetArg(args[i], XtNresizable, True); i++;
-//    XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
-    EngineShell = popup =
-      XtCreatePopupShell(_("Adjudications"), transientShellWidgetClass,
-                        shellWidget, args, i);
-
-    layout =
-      XtCreateManagedWidget(layoutName, formWidgetClass, popup,
-                           layoutArgs, XtNumber(layoutArgs));
-
-    form =
-      XtCreateManagedWidget(layoutName, formWidgetClass, layout,
-                           formArgs, XtNumber(formArgs));
-
-    j = 0;
-//    XtSetArg(args[j], XtNwidth,     (XtArgVal) 250); j++;
-//    XtSetArg(args[j], XtNheight,    (XtArgVal) 400); j++;
-//    XtSetValues(popup, args, j);
-
-    j = 0;
-//    XtSetArg(args[j], XtNwidth,       (XtArgVal) 250); j++;
-//    XtSetArg(args[j], XtNheight,      (XtArgVal) 20); j++;
-    XtSetArg(args[j], XtNleft,        (XtArgVal) XtChainLeft); j++;
-    XtSetArg(args[j], XtNright,       (XtArgVal) XtChainRight); j++;
-    XtSetArg(args[j], XtNstate,       appData.periodicUpdates); j++;
-//    XtSetArg(args[j], XtNjustify,     (XtArgVal) XtJustifyLeft); j++;
-    w1 = XtCreateManagedWidget(_("Periodic Updates (Analysis Mode)"), toggleWidgetClass, form, args, j);
-
-    XtSetArg(args[j], XtNwidth,       (XtArgVal) &width);
-    XtGetValues(w1, &args[j], 1);
-
-//    XtSetArg(args[j-1], XtNfromVert,  (XtArgVal) w1);
-//    XtSetArg(args[j-3], XtNstate,       appData.hideThinkingFromHuman);
-//    w2 = XtCreateManagedWidget(_("Hide Thinking from Human"), toggleWidgetClass, form, args, j);
-
-    XtSetArg(args[j], XtNwidth,       (XtArgVal) width); j++;
-    XtSetArg(args[j-2], XtNstate,     appData.firstScoreIsAbsolute);
-    XtSetArg(args[j], XtNfromVert,    (XtArgVal) w1); j++;
-    w3 = XtCreateManagedWidget(_("Engine #1 Score is Absolute"), toggleWidgetClass, form, args, j);
-
-    XtSetArg(args[j-1], XtNfromVert,  (XtArgVal) w3);
-    XtSetArg(args[j-3], XtNstate,       appData.secondScoreIsAbsolute);
-    w4 = XtCreateManagedWidget(_("Engine #2 Score is Absolute"), toggleWidgetClass, form, args, j);
-
-    s1 = XtCreateManagedWidget(_("\nAdjudications in non-ICS games:"), labelWidgetClass, form, args, 3);
-
-    XtSetArg(args[j-1], XtNfromVert,  (XtArgVal) s1);
-    XtSetArg(args[j-3], XtNstate,       appData.testClaims);
-    w5 = XtCreateManagedWidget(_("Verify Engine Result Claims"), toggleWidgetClass, form, args, j);
-
-    XtSetArg(args[j-1], XtNfromVert,  (XtArgVal) w5);
-    XtSetArg(args[j-3], XtNstate,       appData.checkMates);
-    w6 = XtCreateManagedWidget(_("Detect All Mates"), toggleWidgetClass, form, args, j);
-
-    XtSetArg(args[j-1], XtNfromVert,  (XtArgVal) w6);
-    XtSetArg(args[j-3], XtNstate,       appData.materialDraws);
-    w7 = XtCreateManagedWidget(_("Draw when Insuff. Mating Material"), toggleWidgetClass, form, args, j);
-
-    XtSetArg(args[j-1], XtNfromVert,  (XtArgVal) w7);
-    XtSetArg(args[j-3], XtNstate,       appData.trivialDraws);
-    w8 = XtCreateManagedWidget(_("Adjudicate Trivial Draws"), toggleWidgetClass, form, args, j);
-
-    XtSetArg(args[0], XtNfromVert,  (XtArgVal) w4);
-    XtSetArg(args[1], XtNborderWidth, (XtArgVal) 0);
-    XtSetValues(s1, args, 2);
-
-    snprintf(def, MSG_SIZ,  "%d", appData.adjudicateDrawMoves);
-    j= 0;
-    XtSetArg(args[j], XtNborderWidth, 1); j++;
-    XtSetArg(args[j], XtNfromVert, w8); j++;
-    XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
-    XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
-    XtSetArg(args[j], XtNstring, def);  j++;
-    XtSetArg(args[j], XtNdisplayCaret, False);  j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNresizable, True);  j++;
-    XtSetArg(args[j], XtNwidth,  60);  j++;
-//    XtSetArg(args[j], XtNheight, 20);  j++;
-    engDrawMoves = XtCreateManagedWidget("Length", asciiTextWidgetClass, form, args, j);
-    XtAddEventHandler(engDrawMoves, ButtonPressMask, False, SetFocus, (XtPointer) popup);
-
-    j= 0;
-    XtSetArg(args[j], XtNlabel, _(" moves maximum, then draw")); j++;
-    XtSetArg(args[j], XtNjustify,     (XtArgVal) XtJustifyLeft); j++;
-    XtSetArg(args[j], XtNborderWidth, 0); j++;
-    XtSetArg(args[j], XtNfromVert, w8); j++;
-    XtSetArg(args[j], XtNfromHoriz, engDrawMoves); j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-//    XtSetArg(args[j], XtNwidth,  170);  j++;
-//    XtSetArg(args[j], XtNheight, 20);  j++;
-    tcMess1 = XtCreateManagedWidget("TCtext", labelWidgetClass, form, args, j);
-
-    snprintf(def, MSG_SIZ,  "%d", -appData.adjudicateLossThreshold); // inverted!
-    j= 0;
-    XtSetArg(args[j], XtNborderWidth, 1); j++;
-    XtSetArg(args[j], XtNfromVert, engDrawMoves); j++;
-    XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
-    XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
-    XtSetArg(args[j], XtNstring, def);  j++;
-    XtSetArg(args[j], XtNdisplayCaret, False);  j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNresizable, True);  j++;
-    XtSetArg(args[j], XtNwidth,  60);  j++;
-    XtSetArg(args[j], XtNinsertPosition, 9999);  j++;
-    engThreshold = XtCreateManagedWidget("Threshold", asciiTextWidgetClass, form, args, j);
-    XtAddEventHandler(engThreshold, ButtonPressMask, False, SetFocus, (XtPointer) popup);
-
-    j= 0;
-    XtSetArg(args[j], XtNlabel, _("-centiPawn lead is win")); j++;
-    XtSetArg(args[j], XtNjustify, XtJustifyLeft); j++;
-    XtSetArg(args[j], XtNborderWidth, 0); j++;
-    XtSetArg(args[j], XtNfromVert, engDrawMoves); j++;
-    XtSetArg(args[j], XtNfromHoriz, engThreshold); j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-//    XtSetArg(args[j], XtNwidth,  150);  j++;
-//    XtSetArg(args[j], XtNheight, 20);  j++;
-    tcMess2 = XtCreateManagedWidget("MPStext", labelWidgetClass, form, args, j);
-
-    snprintf(def, MSG_SIZ,  "%d", appData.ruleMoves);
-    j= 0;
-    XtSetArg(args[j], XtNborderWidth, 1); j++;
-    XtSetArg(args[j], XtNfromVert, engThreshold); j++;
-    XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
-    XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
-    XtSetArg(args[j], XtNstring, def);  j++;
-    XtSetArg(args[j], XtNdisplayCaret, False);  j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNresizable, True);  j++;
-    XtSetArg(args[j], XtNwidth,  30);  j++;
-//    XtSetArg(args[j], XtNheight, 20);  j++;
-    engRule = XtCreateManagedWidget("Rule", asciiTextWidgetClass, form, args, j);
-    XtAddEventHandler(engRule, ButtonPressMask, False, SetFocus, (XtPointer) popup);
-
-    j= 0;
-    XtSetArg(args[j], XtNlabel, _("-move rule applied")); j++;
-    XtSetArg(args[j], XtNjustify,     (XtArgVal) XtJustifyLeft); j++;
-    XtSetArg(args[j], XtNborderWidth, 0); j++;
-    XtSetArg(args[j], XtNfromVert, engThreshold); j++;
-    XtSetArg(args[j], XtNfromHoriz, engRule); j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-//    XtSetArg(args[j], XtNwidth,  130);  j++;
-//    XtSetArg(args[j], XtNheight, 20);  j++;
-    tcMess1 = XtCreateManagedWidget("TCtext", labelWidgetClass, form, args, j);
-
-    snprintf(def, MSG_SIZ,  "%d", appData.drawRepeats);
-    j= 0;
-    XtSetArg(args[j], XtNborderWidth, 1); j++;
-    XtSetArg(args[j], XtNfromVert, engRule); j++;
-    XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
-    XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
-    XtSetArg(args[j], XtNstring, def);  j++;
-    XtSetArg(args[j], XtNdisplayCaret, False);  j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNresizable, True);  j++;
-    XtSetArg(args[j], XtNwidth,  30);  j++;
-//    XtSetArg(args[j], XtNheight, 20);  j++;
-    engRepeat = XtCreateManagedWidget("Repeats", asciiTextWidgetClass, form, args, j);
-    XtAddEventHandler(engRepeat, ButtonPressMask, False, SetFocus, (XtPointer) popup);
-
-    j= 0;
-    XtSetArg(args[j], XtNlabel, _("-fold repeat is draw")); j++;
-    XtSetArg(args[j], XtNjustify, XtJustifyLeft); j++;
-    XtSetArg(args[j], XtNborderWidth, 0); j++;
-    XtSetArg(args[j], XtNfromVert, engRule); j++;
-    XtSetArg(args[j], XtNfromHoriz, engRepeat); j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-//    XtSetArg(args[j], XtNwidth,  130);  j++;
-//    XtSetArg(args[j], XtNheight, 20);  j++;
-    tcMess2 = XtCreateManagedWidget("MPStext", labelWidgetClass, form, args, j);
-
-    j=0;
-    XtSetArg(args[j], XtNfromVert, engRepeat);  j++;
-    XtSetArg(args[j], XtNfromHoriz, tcMess2);  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++;
-    b_ok= XtCreateManagedWidget(_("OK"), commandWidgetClass, form, args, j);
-    XtAddCallback(b_ok, XtNcallback, EngineCallback, (XtPointer) 0);
-
-    j=0;
-    XtSetArg(args[j], XtNfromVert, engRepeat);  j++;
-    XtSetArg(args[j], XtNfromHoriz, b_ok);  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++;
-    b_cancel= XtCreateManagedWidget(_("cancel"), commandWidgetClass,
-                                  form, args, j);
-    XtAddCallback(b_cancel, XtNcallback, EnginePopDown, (XtPointer) 0);
-
-    XtRealizeWidget(popup);
-    CatchDeleteWindow(popup, "EnginePopDown");
-
-    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);
+    XtSetArg(args[j], XtNleftMargin, 20);   j++;
+    XtSetArg(args[j], XtNrightMargin, 20);  j++;
+    if(!strcmp(msg, "----")) { XtCreateManagedWidget(msg, smeLineObjectClass, menu, args, j); return NULL; }
+    XtSetArg(args[j], XtNlabel, msg);
+    entry = XtCreateManagedWidget("item", smeBSBObjectClass, menu, args, j+1);
+    XtAddCallback(entry, XtNcallback, CB, (caddr_t)(intptr_t) n);
+    return entry;
+}
+#endif
 
-    XtPopup(popup, XtGrabExclusive);
-    EngineUp = True;
+static void
+MenuSelect (gpointer addr) // callback for all combo items
+{
+    Option *opt = dialogOptions[((intptr_t)addr)>>24]; // applicable option list
+    int i = ((intptr_t)addr)>>16 & 255; // option number
+    int j = 0xFFFF & (intptr_t) addr;
 
-    previous = NULL;
-    SetFocus(engThreshold, popup, (XEvent*) NULL, False);
+    values[i] = j; // store selected value in Option struct, for retrieval at OK
+    ((ButtonCallback*) opt[i].target)(i);
 }
 
-void EngineMenuProc(w, event, prms, nprms)
-     Widget w;
-     XEvent *event;
-     String *prms;
-     Cardinal *nprms;
-{
-   EnginePopUp();
+static GtkWidget *
+CreateMenuPopup (Option *opt, int n, int def)
+{   // fromList determines if the item texts are taken from a list of strings, or from a menu table
+    int i;
+    GtkWidget *menu, *entry;
+    MenuItem *mb = (MenuItem *) opt->choice;
+
+    menu = gtk_menu_new();
+//    menu = XtCreatePopupShell(opt->name, simpleMenuWidgetClass, parent, NULL, 0);
+    for (i=0; 1; i++) 
+      {
+       char *msg = mb[i].string;
+       if(!msg) break;
+       if(strcmp(msg, "----")) { // 
+         if(!(opt->min & NO_GETTEXT)) msg = _(msg);
+         if(mb[i].handle) {
+           entry = gtk_check_menu_item_new_with_label(msg); // should be used for items that can be checkmarked
+           if(mb[i].handle == RADIO) gtk_check_menu_item_set_draw_as_radio(entry, True);
+         } else
+           entry = gtk_menu_item_new_with_label(msg);
+         gtk_signal_connect_object (GTK_OBJECT (entry), "activate", GTK_SIGNAL_FUNC(MenuSelect), (gpointer) (n<<16)+i);
+         gtk_widget_show(entry);
+       } else entry = gtk_separator_menu_item_new();
+       gtk_menu_append(GTK_MENU (menu), entry);
+//CreateMenuItem(menu, opt->min & NO_GETTEXT ? msg : _(msg), (XtCallbackProc) ComboSelect, (n<<16)+i);
+       mb[i].handle = (void*) entry; // save item ID, for enabling / checkmarking
+//     if(i==def) {
+//         XtSetArg(arg, XtNpopupOnEntry, entry);
+//         XtSetValues(menu, &arg, 1);
+//     }
+      }
+      return menu;
 }
 
-//--------------------------- New-Variant Menu PopUp -----------------------------------
-struct NewVarButton {
-  char   *name;
-  char *color;
-  Widget handle;
-  VariantClass variant;
-};
+char moveTypeInTranslations[] =
+    "<Key>Return: TypeInProc(1) \n"
+    "<Key>Escape: TypeInProc(0) \n";
+extern char filterTranslations[];
+extern char gameListTranslations[];
+extern char memoTranslations[];
 
-struct NewVarButton buttonDesc[] = {
-    {N_("normal"),            "#FFFFFF", 0, VariantNormal},
-    {N_("FRC"),               "#FFFFFF", 0, VariantFischeRandom},
-    {N_("wild castle"),       "#FFFFFF", 0, VariantWildCastle},
-    {N_("no castle"),         "#FFFFFF", 0, VariantNoCastle},
-    {N_("knightmate"),        "#FFFFFF", 0, VariantKnightmate},
-    {N_("berolina"),          "#FFFFFF", 0, VariantBerolina},
-    {N_("cylinder"),          "#FFFFFF", 0, VariantCylinder},
-    {N_("shatranj"),          "#FFFFFF", 0, VariantShatranj},
-    {N_("makruk"),            "#FFFFFF", 0, VariantMakruk},
-    {N_("atomic"),            "#FFFFFF", 0, VariantAtomic},
-    {N_("two kings"),         "#FFFFFF", 0, VariantTwoKings},
-    {N_("3-checks"),          "#FFFFFF", 0, Variant3Check},
-    {N_("suicide"),           "#FFFFBF", 0, VariantSuicide},
-    {N_("give-away"),         "#FFFFBF", 0, VariantGiveaway},
-    {N_("losers"),            "#FFFFBF", 0, VariantLosers},
-    {N_("fairy"),             "#BFBFBF", 0, VariantFairy},
-    {N_("Seirawan"),          "#FFBFBF", 0, VariantSChess},
-    {N_("Superchess"),        "#FFBFBF", 0, VariantSuper},
-    {N_("crazyhouse"),        "#FFBFBF", 0, VariantCrazyhouse},
-    {N_("bughouse"),          "#FFBFBF", 0, VariantBughouse},
-    {N_("shogi (9x9)"),       "#BFFFFF", 0, VariantShogi},
-    {N_("xiangqi (9x10)"),    "#BFFFFF", 0, VariantXiangqi},
-    {N_("courier (12x8)"),    "#BFFFBF", 0, VariantCourier},
-    {N_("janus (10x8)"),      "#BFBFFF", 0, VariantJanus},
-    {N_("Capablanca (10x8)"), "#BFBFFF", 0, VariantCapablanca},
-    {N_("CRC (10x8)"),        "#BFBFFF", 0, VariantCapaRandom},
-#ifdef GOTHIC
-    {N_("Gothic (10x8)"),     "#BFBFFF", 0, VariantGothic},
-#endif
-#ifdef FALCON
-    {N_("Falcon (10x8)"),     "#BFBFFF", 0, VariantFalcon},
-#endif
-    {NULL,                0, 0, (VariantClass) 0}
+
+char *translationTable[] = { // beware: order is essential!
+   historyTranslations, commentTranslations, moveTypeInTranslations, ICSInputTranslations,
+   filterTranslations, gameListTranslations, memoTranslations
 };
 
-int NewVariantUp;
-Widget NewVariantShell;
+Option *typeIn; // kludge to distinguish type-in callback from input-box callback
 
-void NewVariantPopDown()
+void
+CursorAtEnd (Option *opt)
 {
-    if (!NewVariantUp) return;
-    XtPopdown(NewVariantShell);
-    XtDestroyWidget(NewVariantShell);
-    NewVariantUp = False;
-    ModeHighlight();
+    gtk_editable_set_position(opt->handle, -1);
 }
 
-void NewVariantCallback(w, client_data, call_data)
-     Widget w;
-     XtPointer client_data, call_data;
+static gboolean
+ICSKeyEvent(GtkWidget *widget, GdkEventKey *event, gpointer g)
 {
-    String name;
-    Arg args[16];
-    VariantClass v;
-
-    XtSetArg(args[0], XtNlabel, &name);
-    XtGetValues(w, args, 1);
-
-    if (strcmp(name, _("  OK  ")) == 0) {
-       int nr = (intptr_t) XawToggleGetCurrent(buttonDesc[0].handle) - 1;
-       if(nr < 0) return;
-       v = buttonDesc[nr].variant;
-       if(!appData.noChessProgram) {
-           char *name = VariantName(v), buf[MSG_SIZ];
-           if (first.protocolVersion > 1 && StrStr(first.variants, name) == NULL) {
-               /* [HGM] in protocol 2 we check if variant is suported by engine */
-             snprintf(buf, MSG_SIZ,  _("Variant %s not supported by %s"), name, first.tidy);
-               DisplayError(buf, 0);
-//             NewVariantPopDown();
-               return; /* ignore OK if first engine does not support it */
-           } else
-           if (second.initDone && second.protocolVersion > 1 && StrStr(second.variants, name) == NULL) {
-             snprintf(buf, MSG_SIZ,  _("Warning: second engine (%s) does not support this!"), second.tidy);
-               DisplayError(buf, 0);   /* use of second engine is optional; only warn user */
-           }
+    Option *opt = (Option *) g;
+    if(opt == typeIn) {
+       if(event->keyval == GDK_Return) {
+           char *val;
+           GetWidgetText(opt, &val);
+           TypeInDoneEvent(val);
+           PopDown(TransientDlg);
+           return TRUE;
        }
+       return FALSE;
+    }
 
-       gameInfo.variant = v;
-       appData.variant = VariantName(v);
+    switch(event->keyval) {
+      case GDK_Return: IcsKey(0); return TRUE;
+      case GDK_Up:     IcsKey(1); return TRUE;
+      case GDK_Down:  IcsKey(-1); return TRUE;
+      default: return FALSE;
+    }
+}
 
-       shuffleOpenings = FALSE; /* [HGM] shuffle: possible shuffle reset when we switch */
-       startedFromPositionFile = FALSE; /* [HGM] loadPos: no longer valid in new variant */
-       appData.pieceToCharTable = NULL;
-       Reset(True, True);
-        NewVariantPopDown();
-        return;
+int shiftState, controlState;
+
+static gboolean
+TypeInProc (GtkWidget *widget, GdkEventKey *event, gpointer gdata)
+{   // This callback catches key presses on text-entries, and uses <Enter> and <Esc> as synonyms for dialog OK or Cancel
+    // *** kludge alert *** If a dialog does want some other action, like sending the line typed in the text-entry to an ICS,
+    // it should define an OK handler that does so, and returns FALSE to suppress the popdown.
+    int n = (intptr_t) gdata;
+    int dlg = n >> 16;
+    Option *opt;
+    n &= 0xFFFF;
+    opt = &dialogOptions[dlg][n];
+
+    if(opt == icsBox) return ICSKeyEvent(event->keyval); // Intercept ICS Input Box, which needs special treatment
+
+    shiftState = event->state & GDK_SHIFT_MASK;
+    controlState = event->state & GDK_CONTROL_MASK;
+    switch(event->keyval) {
+      case GDK_Return:
+       if(GenericReadout(dialogOptions[dlg], -1)) PopDown(dlg);
+       break;
+      case GDK_Escape:
+       PopDown(dlg);
+       break;
+      default:
+       return FALSE;
     }
+    return TRUE;
 }
 
-void NewVariantPopUp()
+void
+HighlightText (Option *opt, int from, int to, Boolean highlight)
 {
-    Arg args[16];
-    Widget popup, layout, form, last = NULL, b_ok, b_cancel;
-    Window root, child;
-    int x, y, i, j;
-    int win_x, win_y;
-    unsigned int mask;
-    XrmValue vFrom, vTo;
-
-    i = 0;
-    XtSetArg(args[i], XtNresizable, True); i++;
-//    XtSetArg(args[i], XtNwidth, 250); i++;
-//    XtSetArg(args[i], XtNheight, 300); i++;
-    NewVariantShell = popup =
-      XtCreatePopupShell(_("NewVariant Menu"), transientShellWidgetClass,
-                        shellWidget, args, i);
+#   define INIT 0x8000
+    static GtkTextIter start, end;
 
-    layout =
-      XtCreateManagedWidget(layoutName, formWidgetClass, popup,
-                           layoutArgs, XtNumber(layoutArgs));
+    if(!(opt->min & INIT)) {
+       opt->min |= INIT; // each memo its own init flag!
+       gtk_text_buffer_create_tag(opt->handle, "highlight", "background", "yellow", NULL);
+       gtk_text_buffer_create_tag(opt->handle, "normal", "background", "white", NULL);
+    }
+    gtk_text_buffer_get_iter_at_offset(opt->handle, &start, from);
+    gtk_text_buffer_get_iter_at_offset(opt->handle, &end, to);
+    gtk_text_buffer_apply_tag_by_name(opt->handle, highlight ? "highlight" : "normal", &start, &end);
+}
 
-    form =
-      XtCreateManagedWidget("form", formWidgetClass, layout,
-                           formArgs, XtNumber(formArgs));
+int
+ShiftKeys ()
+{   // bassic primitive for determining if modifier keys are pressed
+    return 3*(shiftState != 0) + 0xC*(controlState != 0); // rely on what last mouse button press left us
+}
 
-    for(i = 0; buttonDesc[i].name != NULL; i++) {
-       Pixel buttonColor;
-       if (!appData.monoMode) {
-           vFrom.addr = (caddr_t) buttonDesc[i].color;
-           vFrom.size = strlen(buttonDesc[i].color);
-           XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
-           if (vTo.addr == NULL) {
-               buttonColor = (Pixel) -1;
-           } else {
-               buttonColor = *(Pixel *) vTo.addr;
-           }
-       }
+static gboolean
+GameListEvent(GtkWidget *widget, GdkEvent *event, gpointer gdata)
+{
+    int n = (int) gdata;
 
-       j = 0;
-       XtSetArg(args[j], XtNradioGroup, last); j++;
-       XtSetArg(args[j], XtNwidth, 125); j++;
-//     XtSetArg(args[j], XtNheight, 16); j++;
-       XtSetArg(args[j], XtNfromVert, i == 15 ? NULL : last); j++;
-       XtSetArg(args[j], XtNfromHoriz, i < 15 ? NULL : buttonDesc[i-15].handle); j++;
-       XtSetArg(args[j], XtNradioData, i+1); j++;
-       XtSetArg(args[j], XtNbackground, buttonColor); j++;
-       XtSetArg(args[j], XtNstate, gameInfo.variant == buttonDesc[i].variant); j++;
-       buttonDesc[i].handle = last =
-           XtCreateManagedWidget(buttonDesc[i].name, toggleWidgetClass, form, args, j);
+    if(n == 4) {
+       if(((GdkEventKey *) event)->keyval != GDK_Return) return FALSE;
+       SetFilter();
+       return TRUE;
     }
 
-    j=0;
-    XtSetArg(args[j], XtNfromVert, buttonDesc[12].handle);  j++;
-    XtSetArg(args[j], XtNfromHoriz, buttonDesc[12].handle);  j++;
-    XtSetArg(args[j], XtNheight, 35); j++;
-//    XtSetArg(args[j], XtNwidth, 60); 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++;
-    b_cancel= XtCreateManagedWidget(_("CANCEL"), commandWidgetClass, form, args, j);
-    XtAddCallback(b_cancel, XtNcallback, NewVariantPopDown, (XtPointer) 0);
-
-    j=0;
-    XtSetArg(args[j], XtNfromHoriz, b_cancel);  j++;
-    XtSetArg(args[j], XtNfromVert, buttonDesc[12].handle);  j++;
-    XtSetArg(args[j], XtNheight, 35); j++;
-//    XtSetArg(args[j], XtNwidth, 60); 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++;
-    b_ok= XtCreateManagedWidget(_("  OK  "), commandWidgetClass, form, args, j);
-    XtAddCallback(b_ok, XtNcallback, NewVariantCallback, (XtPointer) 0);
+    if(event->type == GDK_KEY_PRESS) {
+       int ctrl = (((GdkEventKey *) event)->state & GDK_CONTROL_MASK) != 0;
+       switch(((GdkEventKey *) event)->keyval) {
+         case GDK_Up: GameListClicks(-1 - 2*ctrl); return TRUE;
+         case GDK_Left: GameListClicks(-1); return TRUE;
+         case GDK_Down: GameListClicks(1 + 2*ctrl); return TRUE;
+         case GDK_Right: GameListClicks(1); return TRUE;
+         case GDK_Prior: GameListClicks(-4); return TRUE;
+         case GDK_Next: GameListClicks(4); return TRUE;
+         case GDK_Home: GameListClicks(-2); return TRUE;
+         case GDK_End: GameListClicks(2); return TRUE;
+         case GDK_Return: GameListClicks(0); return TRUE;
+         default: return FALSE;
+       }
+    }
+    if(event->type != GDK_2BUTTON_PRESS || ((GdkEventButton *) event)->button != 1) return FALSE;
+    GameListClicks(0);
+    return TRUE;
+}
 
-    j=0;
-    XtSetArg(args[j], XtNfromVert, buttonDesc[14].handle);  j++;
-//    XtSetArg(args[j], XtNheight, 70); j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainRight);  j++;
-    XtSetArg(args[j], XtNlabel, _("WARNING: variants with un-orthodox\n"
-                                 "pieces only have built-in bitmaps\n"
-                                 "for -boardSize middling, bulky and\n"
-                                 "petite, and substitute king or amazon\n"
-                                 "for missing bitmaps. (See manual.)")); j++;
-    XtCreateManagedWidget("warning", labelWidgetClass, form, args, j);
-
-           XtRealizeWidget(popup);
-    CatchDeleteWindow(popup, "NewVariantPopDown");
-
-    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);
-    NewVariantUp = True;
+static gboolean
+MemoEvent(GtkWidget *widget, GdkEvent *event, gpointer gdata)
+{   // handle mouse clicks on text widgets that need it
+    int w, h;
+    int button=10, f=1;
+    Option *opt, *memo = (Option *) gdata;
+    MemoCallback *userHandler = (MemoCallback *) memo->choice;
+    GdkEventButton *bevent = (GdkEventButton *) event;
+    GdkEventMotion *mevent = (GdkEventMotion *) event;
+    GtkTextIter start, end;
+    String val = NULL;
+    gboolean res;
+    gint index, x, y;
+
+    if(memo->type == Label) { ((ButtonCallback*) memo->target)(memo->value); return TRUE; } // only clock widgets use this
+
+    switch(event->type) { // figure out what's up
+       case GDK_MOTION_NOTIFY:
+           f = 0;
+           w = mevent->x; h = mevent->y;
+           break;
+       case GDK_BUTTON_RELEASE:
+           f = -1; // release indicated by negative button numbers
+           w = bevent->x; h = bevent->y;
+           button = bevent->button;
+           break;
+       case GDK_BUTTON_PRESS:
+           w = bevent->x; h = bevent->y;
+           button = bevent->button;
+           shiftState = bevent->state & GDK_SHIFT_MASK;
+           controlState = bevent->state & GDK_CONTROL_MASK;
+// GTK_TODO: is this really the most efficient way to get the character at the mouse cursor???
+           gtk_text_view_window_to_buffer_coords(widget, GTK_TEXT_WINDOW_WIDGET, w, h, &x, &y);
+           gtk_text_view_get_iter_at_location(widget, &start, x, y);
+           gtk_text_buffer_place_cursor(memo->handle, &start);
+           /* get cursor position into index */
+           g_object_get(memo->handle, "cursor-position", &index, NULL);
+           /* get text from textbuffer */
+           gtk_text_buffer_get_start_iter (memo->handle, &start);
+           gtk_text_buffer_get_end_iter (memo->handle, &end);
+           val = gtk_text_buffer_get_text (memo->handle, &start, &end, FALSE); 
+           break;
+       default:
+           return FALSE; // should not happen
+    }
+    button *= f;
+    // hand click parameters as well as text & location to user
+    res = (userHandler) (memo, button, w, h, val, index);
+    if(val) g_free(val);
+    return res;
 }
 
-void NewVariantProc(w, event, prms, nprms)
-     Widget w;
-     XEvent *event;
-     String *prms;
-     Cardinal *nprms;
+void
+AddHandler (Option *opt, DialogClass dlg, int nr)
 {
-   NewVariantPopUp();
+    switch(nr) {
+      case 0: // history (now uses generic textview callback)
+      case 1: // comment (likewise)
+       break;
+      case 2: // move type-in
+       typeIn = opt;
+      case 3: // input box
+       g_signal_connect(opt->handle, "key-press-event", G_CALLBACK (ICSKeyEvent), (gpointer) opt);
+       break;
+      case 5: // game list
+       g_signal_connect(opt->handle, "button-press-event", G_CALLBACK (GameListEvent), (gpointer) 0 );
+      case 4: // game-list filter
+       g_signal_connect(opt->handle, "key-press-event", G_CALLBACK (GameListEvent), (gpointer) nr );
+       break;
+      case 6: // engine output (uses generic textview callback)
+       break;
+    }
 }
 
-//--------------------------- UCI Menu Popup ------------------------------------------
-int UciUp;
-Widget UciShell;
+//----------------------------Generic dialog --------------------------------------------
 
-struct UciControl {
-  char *name;
-  Widget handle;
-  void *ptr;
-};
+// cloned from Engine Settings dialog (and later merged with it)
 
-struct UciControl controlDesc[] = {
-  {N_("maximum nr of CPUs:"), 0, &appData.smpCores},
-  {N_("Polyglot Directory:"), 0, &appData.polyglotDir},
-  {N_("Hash Size (MB):"),     0, &appData.defaultHashSize},
-  {N_("EGTB Path:"),          0, &appData.defaultPathEGTB},
-  {N_("EGTB Cache (MB):"),    0, &appData.defaultCacheSizeEGTB},
-  {N_("Polyglot Book:"),      0, &appData.polyglotBook},
-  {NULL, 0, NULL},
+GtkWidget *shells[NrOfDialogs];
+DialogClass parents[NrOfDialogs];
+WindowPlacement *wp[NrOfDialogs] = { // Beware! Order must correspond to DialogClass enum
+    NULL, &wpComment, &wpTags, NULL, NULL, NULL, NULL, &wpMoveHistory, &wpGameList, &wpEngineOutput, &wpEvalGraph,
+    NULL, NULL, NULL, NULL, /*&wpMain*/ NULL
 };
 
-void UciPopDown()
+int
+DialogExists (DialogClass n)
+{   // accessor for use in back-end
+    return shells[n] != NULL;
+}
+
+void
+RaiseWindow (DialogClass dlg)
 {
-    if (!UciUp) return;
-    previous = NULL;
-    XtPopdown(UciShell);
-    XtDestroyWidget(UciShell);
-    UciUp = False;
-    ModeHighlight();
+#ifdef TODO_GTK
+    static XEvent xev;
+    Window root = RootWindow(xDisplay, DefaultScreen(xDisplay));
+    Atom atom = XInternAtom (xDisplay, "_NET_ACTIVE_WINDOW", False);
+
+    xev.xclient.type = ClientMessage;
+    xev.xclient.serial = 0;
+    xev.xclient.send_event = True;
+    xev.xclient.display = xDisplay;
+    xev.xclient.window = XtWindow(shells[dlg]);
+    xev.xclient.message_type = atom;
+    xev.xclient.format = 32;
+    xev.xclient.data.l[0] = 1;
+    xev.xclient.data.l[1] = CurrentTime;
+
+    XSendEvent (xDisplay,
+          root, False,static gboolean
+MemoEvent(GtkWidget *widget, GdkEvent *event, gpointer gdata)
+
+          SubstructureRedirectMask | SubstructureNotifyMask,
+          &xev);
+
+    XFlush(xDisplay); 
+    XSync(xDisplay, False);
+#endif
 }
 
-void UciCallback(w, client_data, call_data)
-     Widget w;
-     XtPointer client_data, call_data;
+int
+PopDown (DialogClass n)
 {
-    String name;
-    Arg args[16];
-    int oldCores = appData.smpCores, ponder = 0;
+    //Arg args[10];    
+    
+    if (!shellUp[n] || !shells[n]) return 0;    
+#ifdef TODO_GTK
+// Not sure this is still used
+    if(n && wp[n]) { // remember position
+       j = 0;
+       XtSetArg(args[j], XtNx, &windowX); j++;
+       XtSetArg(args[j], XtNy, &windowY); j++;
+       XtSetArg(args[j], XtNheight, &windowH); j++;
+       XtSetArg(args[j], XtNwidth, &windowW); j++;
+       XtGetValues(shells[n], args, j);
+       wp[n]->x = windowX;
+       wp[n]->x = windowY;
+       wp[n]->width  = windowW;
+       wp[n]->height = windowH;
+    }
+#endif
+    
+    gtk_widget_hide(shells[n]);
+    shellUp[n]--; // count rather than clear
 
-    XtSetArg(args[0], XtNlabel, &name);
-    XtGetValues(w, args, 1);
+    if(n == 0 || n >= PromoDlg) {
+        gtk_widget_destroy(shells[n]);
+        shells[n] = NULL;
+    }
 
-    if (strcmp(name, _("OK")) == 0) {
-       int i, j; String name;
-       for(i=0; i<6; i++) {
-           XtSetArg(args[0], XtNstring, &name);
-           XtGetValues(controlDesc[i].handle, args, 1);
-           if(i&1) {
-               if(name)
-                   *(char**) controlDesc[i].ptr = strdup(name);
-           } else {
-               if(sscanf(name, "%d", &j) == 1)
-                   *(int*) controlDesc[i].ptr = j;
-           }
-       }
-       XtSetArg(args[0], XtNstate, &appData.usePolyglotBook);
-       XtGetValues(w1, args, 1);
-       XtSetArg(args[0], XtNstate, &appData.firstHasOwnBookUCI);
-       XtGetValues(w2, args, 1);
-       XtSetArg(args[0], XtNstate, &appData.secondHasOwnBookUCI);
-       XtGetValues(w3, args, 1);
-       XtSetArg(args[0], XtNstate, &ponder);
-       XtGetValues(w4, args, 1);
-
-       // adjust setting in other menu for duplicates
-       // (perhaps duplicates should be removed from general Option Menu?)
-       XtSetArg(args[0], XtNleftBitmap, ponder ? xMarkPixmap : None);
-       XtSetValues(XtNameToWidget(menuBarWidget,
-                                  "menuOptions.Ponder Next Move"), args, 1);
-
-       // make sure changes are sent to first engine by re-initializing it
-       // if it was already started pre-emptively at end of previous game
-       if(gameMode == BeginningOfGame) Reset(True, True); else {
-           // Some changed setting need immediate sending always.
-           PonderNextMoveEvent(ponder);
-           if(oldCores != appData.smpCores)
-               NewSettingEvent(False, &(first.maxCores), "cores", appData.smpCores);
-      }
-      UciPopDown();
-      return;
+    if(marked[n]) {
+       MarkMenuItem(marked[n], False);
+       marked[n] = NULL;
     }
+
+    if(!n) currentCps = NULL; // if an Engine Settings dialog was up, we must be popping it down now
+    currentOption = dialogOptions[TransientDlg]; // just in case a transient dialog was up (to allow its check and combo callbacks to work)
+#ifdef TODO_GTK
+    RaiseWindow(parents[n]); // automatic in GTK?
+    if(parents[n] == BoardWindow) XtSetKeyboardFocus(shellWidget, formWidget); // also automatic???
+#endif
+    return 1;
 }
 
-void UciPopUp()
+/* GTK callback used when OK/cancel clicked in genericpopup for non-modal dialog */
+gboolean GenericPopDown(w, resptype, gdata)
+     GtkWidget *w;
+     GtkResponseType  resptype;
+     gpointer  gdata;
 {
-    Arg args[16];
-    Widget popup, layout, form, b_ok, b_cancel, last = NULL, new, upperLeft;
-    Window root, child;
-    int x, y, i, j;
-    int win_x, win_y;
-    unsigned int mask;
-    char def[MSG_SIZ];
-
-    i = 0;
-    XtSetArg(args[i], XtNresizable, True); i++;
-//    XtSetArg(args[i], XtNwidth, 300); i++;
-    UciShell = popup =
-      XtCreatePopupShell(_("Engine Settings"), transientShellWidgetClass,
-                        shellWidget, args, i);
-
-    layout =
-      XtCreateManagedWidget(layoutName, formWidgetClass, popup,
-                           layoutArgs, XtNumber(layoutArgs));
+    DialogClass dlg = (intptr_t) gdata; /* dialog number dlgnr */
+    GtkWidget *sh = shells[dlg];
 
+    currentOption = dialogOptions[dlg];
 
-    form =
-      XtCreateManagedWidget("form", formWidgetClass, layout,
-                           formArgs, XtNumber(formArgs));
+#ifdef TODO_GTK
+// I guess BrowserDlg will be abandoned, as GTK has a better browser of its own
+    if(shellUp[BrowserDlg] && dlg != BrowserDlg || dialogError) return True; // prevent closing dialog when it has an open file-browse daughter
+#else
+    if(browserUp || dialogError && dlg != FatalDlg) return True; // prevent closing dialog when it has an open file-browse or error-popup daughter
+#endif
+    shells[dlg] = w; // make sure we pop down the right one in case of multiple instances
 
-    j = 0;
-    XtSetArg(args[j], XtNtop, XtChainTop);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-//    XtSetArg(args[j], XtNheight, 20); j++;
-    for(i = 0; controlDesc[i].name != NULL; i++) {
-       j = 3;
-       XtSetArg(args[j], XtNfromVert, last); j++;
-//     XtSetArg(args[j], XtNwidth, 130); j++;
-       XtSetArg(args[j], XtNjustify, XtJustifyLeft); j++;
-       XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-       XtSetArg(args[j], XtNborderWidth, 0); j++;
-       new = XtCreateManagedWidget(controlDesc[i].name, labelWidgetClass, form, args, j);
-       if(i==0) upperLeft = new;
-
-       j = 4;
-       XtSetArg(args[j], XtNborderWidth, 1); 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], XtNwidth, i&1 ? 245 : 50); j++;
-       XtSetArg(args[j], XtNinsertPosition, 9999);  j++;
-       if(i&1) {
-           XtSetArg(args[j], XtNstring, * (char**) controlDesc[i].ptr ?
-                                        * (char**) controlDesc[i].ptr : ""); j++;
-       } else {
-         snprintf(def, MSG_SIZ,  "%d", * (int*) controlDesc[i].ptr);
-           XtSetArg(args[j], XtNstring, def); j++;
-       }
-       XtSetArg(args[j], XtNfromHoriz, upperLeft); j++;
-       controlDesc[i].handle = last =
-           XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
-       XtAddEventHandler(last, ButtonPressMask, False, SetFocus, (XtPointer) popup);
+    /* OK pressed */    
+    if (resptype == GTK_RESPONSE_ACCEPT) {
+        if (GenericReadout(currentOption, -1)) PopDown(dlg);
+        return TRUE;
+    } else
+    /* cancel pressed */
+    {
+       if(dlg == BoardWindow) ExitEvent(0);
+       PopDown(dlg);
     }
+    shells[dlg] = sh; // restore
+    return TRUE;
+}
 
-    j=0;
-    XtSetArg(args[j], XtNfromHoriz, controlDesc[0].handle);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainTop);  j++;
-    XtSetArg(args[j], XtNtop, XtChainTop);  j++;
-    XtSetArg(args[j], XtNleft, XtChainRight);  j++;
-    XtSetArg(args[j], XtNright, XtChainRight);  j++;
-    XtSetArg(args[j], XtNstate, appData.ponderNextMove);  j++;
-    w4 = XtCreateManagedWidget(_("Ponder"), toggleWidgetClass, form, args, j);
-
-    j=0;
-    XtSetArg(args[j], XtNfromVert, last);  j++;
-    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNtop, XtChainBottom);  j++;
-    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
-    XtSetArg(args[j], XtNright, XtChainLeft);  j++;
-    b_ok = XtCreateManagedWidget(_("OK"), commandWidgetClass, form, args, j);
-    XtAddCallback(b_ok, XtNcallback, UciCallback, (XtPointer) 0);
-
-    XtSetArg(args[j], XtNfromHoriz, b_ok);  j++;
-    b_cancel = XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
-    XtAddCallback(b_cancel, XtNcallback, UciPopDown, (XtPointer) 0);
-
-    j = 5;
-    XtSetArg(args[j], XtNfromHoriz, upperLeft);  j++;
-    XtSetArg(args[j], XtNstate, appData.usePolyglotBook);  j++;
-    w1 = XtCreateManagedWidget(_(" use book "), toggleWidgetClass, form, args, j);
-//    XtAddCallback(w1, XtNcallback, UciCallback, (XtPointer) 0);
-
-    j = 5;
-    XtSetArg(args[j], XtNfromHoriz, w1);  j++;
-    XtSetArg(args[j], XtNstate, appData.firstHasOwnBookUCI);  j++;
-    w2 = XtCreateManagedWidget(_("own book 1"), toggleWidgetClass, form, args, j);
-//    XtAddCallback(w2, XtNcallback, UciCallback, (XtPointer) 0);
-
-    j = 5;
-    XtSetArg(args[j], XtNfromHoriz, w2);  j++;
-    XtSetArg(args[j], XtNstate, appData.secondHasOwnBookUCI);  j++;
-    w3 = XtCreateManagedWidget(_("own book 2"), toggleWidgetClass, form, args, j);
-//    XtAddCallback(w3, XtNcallback, UciCallback, (XtPointer) 0);
-
-    XtRealizeWidget(popup);
-    CatchDeleteWindow(popup, "UciPopDown");
-
-    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);
+int AppendText(Option *opt, char *s)
+{    
+    char *v;
+    int len;
+    GtkTextIter end;    
+  
+    GetWidgetTextGTK(opt->handle, &v);
+    len = strlen(v);
+    g_free(v);
+    gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(opt->handle), &end);
+    gtk_text_buffer_insert(opt->handle, &end, s, -1);
+
+    return len;
+}
 
-    XtPopup(popup, XtGrabExclusive);
-    UciUp = True;
+void
+SetColor (char *colorName, Option *box)
+{       // sets the color of a widget
+    GdkColor color;
 
-    previous = NULL;
-    SetFocus(controlDesc[2].handle, popup, (XEvent*) NULL, False);
-//    XtSetKeyboardFocus(popup, controlDesc[1].handle);
+    /* set the colour of the colour button to the colour that will be used */
+    gdk_color_parse( colorName, &color );
+    gtk_widget_modify_bg ( GTK_WIDGET(box->handle), GTK_STATE_NORMAL, &color );
 }
 
-void UciMenuProc(w, event, prms, nprms)
-     Widget w;
-     XEvent *event;
-     String *prms;
-     Cardinal *nprms;
-{
-   UciPopUp();
+#ifdef TODO_GTK
+void
+ColorChanged (Widget w, XtPointer data, XEvent *event, Boolean *b)
+{   // for detecting a typed change in color
+    char buf[10];
+    if ( (XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) && *buf == '\r' )
+       RefreshColor((int)(intptr_t) data, 0);
 }
+#endif
 
-//--------------------------- Engine-specific options menu ----------------------------------
-
-int SettingsUp;
-Widget SettingsShell;
-int values[MAX_OPTIONS];
-ChessProgramState *currentCps;
+static void
+GraphEventProc(GtkWidget *widget, GdkEvent *event, gpointer gdata)
+{   // handle expose and mouse events on Graph widget
+    int w, h;
+    int j, button=10, f=1, sizing=0;
+    Option *opt, *graph = (Option *) gdata;
+    PointerCallback *userHandler = graph->target;
+    GdkEventExpose *eevent = (GdkEventExpose *) event;
+    GdkEventButton *bevent = (GdkEventButton *) event;
+    GdkEventMotion *mevent = (GdkEventMotion *) event;
+    cairo_t *cr;
+
+//    if (!XtIsRealized(widget)) return;
+
+    switch(event->type) {
+       case GDK_EXPOSE: // make handling of expose events generic, just copying from memory buffer (->choice) to display (->textValue)
+           /* Get window size */
+#ifdef TODO_GTK
+           j = 0;
+           XtSetArg(args[j], XtNwidth, &w); j++;
+           XtSetArg(args[j], XtNheight, &h); j++;
+           XtGetValues(widget, args, j);
+
+           if(w < graph->max || w > graph->max + 1 || h != graph->value) { // use width fudge of 1 pixel
+               if(((XExposeEvent*)event)->count >= 0) { // suppress sizing on expose for ordered redraw in response to sizing.
+                   sizing = 1;
+                   graph->max = w; graph->value = h; // note: old values are kept if we we don't exceed width fudge
+               }
+           } else w = graph->max;
+
+           if(sizing && ((XExposeEvent*)event)->count > 0) { graph->max = 0; return; } // don't bother if further exposure is pending during resize
+           if(!graph->textValue || sizing) { // create surfaces of new size for display widget
+               if(graph->textValue) cairo_surface_destroy((cairo_surface_t *)graph->textValue);
+               graph->textValue = (char*) cairo_xlib_surface_create(xDisplay, XtWindow(widget), DefaultVisual(xDisplay, 0), w, h);
+           }
+           if(sizing) { // the memory buffer was already created in GenericPopup(),
+                        // to give drawing routines opportunity to use it before first expose event
+                        // (which are only processed when main gets to the event loop, so after all init!)
+                        // so only change when size is no longer good
+               if(graph->choice) cairo_surface_destroy((cairo_surface_t *) graph->choice);
+               graph->choice = (char**) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
+               break;
+           }
+#endif
+           w = eevent->area.width;
+           if(eevent->area.x + w > graph->max) w--; // cut off fudge pixel
+           cr = gdk_cairo_create(((GtkWidget *) (graph->handle))->window);
+           cairo_set_source_surface(cr, (cairo_surface_t *) graph->choice, 0, 0);
+           cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
+           cairo_rectangle(cr, eevent->area.x, eevent->area.y, w, eevent->area.height);
+           cairo_fill(cr);
+           cairo_destroy(cr);
+       default:
+           return;
+       case GDK_MOTION_NOTIFY:
+           f = 0;
+           w = mevent->x; h = mevent->y;
+           break;
+       case GDK_BUTTON_RELEASE:
+           f = -1; // release indicated by negative button numbers
+       case GDK_BUTTON_PRESS:
+           w = bevent->x; h = bevent->y;
+           button = bevent->button;
+           shiftState = bevent->state & GDK_SHIFT_MASK;
+           controlState = bevent->state & GDK_CONTROL_MASK;
+    }
+    button *= f;
+
+    opt = userHandler(button, w, h);
+#ifdef TODO_GTK
+    if(opt) { // user callback specifies a context menu; pop it up
+       XUngrabPointer(xDisplay, CurrentTime);
+       XtCallActionProc(widget, "XawPositionSimpleMenu", event, &(opt->name), 1);
+       XtPopupSpringLoaded(opt->handle);
+    }
+    XSync(xDisplay, False);
+#endif
+}
 
-void SettingsPopDown()
+void
+GraphExpose (Option *opt, int x, int y, int w, int h)
 {
-    if (!SettingsUp) return;
-    previous = NULL;
-    XtPopdown(SettingsShell);
-    XtDestroyWidget(SettingsShell);
-    SettingsUp = False;
-    ModeHighlight();
+#if 0
+  GdkRectangle r;
+  r.x = x; r.y = y; r.width = w; r.height = h;
+  gdk_window_invalidate_rect(((GtkWidget *)(opt->handle))->window, &r, FALSE);
+#endif
+  GdkEventExpose e;
+  if(!opt->handle) return;
+  e.area.x = x; e.area.y = y; e.area.width = w; e.area.height = h; e.count = -1; e.type = GDK_EXPOSE; // count = -1: kludge to suppress sizing
+  GraphEventProc(opt->handle, (GdkEvent *) &e, (gpointer) opt); // fake expose event
 }
 
-void SpinCallback(w, client_data, call_data)
-     Widget w;
-     XtPointer client_data, call_data;
+void GenericCallback(GtkWidget *widget, gpointer gdata)
 {
-    String name, val;
-    Arg args[16];
-    char buf[MSG_SIZ];
-    int j;
-    int data = (intptr_t) client_data;
+    const gchar *name;
+    char buf[MSG_SIZ];    
+    int data = (intptr_t) gdata;   
+    DialogClass dlg;
+#ifdef TODO_GTK
+    GtkWidget *sh = XtParent(XtParent(XtParent(w))), *oldSh;
+#else
+    GtkWidget *sh, *oldSh;
+#endif
 
-    XtSetArg(args[0], XtNlabel, &name);
-    XtGetValues(w, args, 1);
+    currentOption = dialogOptions[dlg=data>>16]; data &= 0xFFFF;
+#ifndef TODO_GTK
+    sh = shells[dlg]; // make following line a no-op, as we haven't found out what the real shell is yet (breaks multiple popups of same type!)
+#endif
+    oldSh = shells[dlg]; shells[dlg] = sh; // bow to reality
 
-    j = 0;
-    XtSetArg(args[0], XtNstring, &val);
-    XtGetValues(currentCps->option[data].handle, args, 1);
-    sscanf(val, "%d", &j);
-    if (strcmp(name, "+") == 0) {
-       if(++j > currentCps->option[data].max) return;
+    if (data == 30000) { // cancel
+        PopDown(dlg); 
+    } else
+    if (data == 30001) { // save buttons imply OK
+        if(GenericReadout(currentOption, -1)) PopDown(dlg); // calls OK-proc after full readout, but no popdown if it returns false
     } else
-    if (strcmp(name, "-") == 0) {
-       if(--j < currentCps->option[data].min) return;
-    } else return;
-    snprintf(buf, MSG_SIZ,  "%d", j);
-    XtSetArg(args[0], XtNstring, buf);
-    XtSetValues(currentCps->option[data].handle, args, 1);
+
+    if(currentCps) {
+        name = gtk_button_get_label (GTK_BUTTON(widget));         
+       if(currentOption[data].type == SaveButton) GenericReadout(currentOption, -1);
+        snprintf(buf, MSG_SIZ,  "option %s\n", name);
+        SendToProgram(buf, currentCps);
+    } else ((ButtonCallback*) currentOption[data].target)(data);   
+
+    shells[dlg] = oldSh; // in case of multiple instances, restore previous (as this one could be popped down now)
 }
 
-void SettingsCallback(w, client_data, call_data)
-     Widget w;
-     XtPointer client_data, call_data;
+void BrowseGTK(GtkWidget *widget, gpointer gdata)
 {
-    String name, val;
-    Arg args[16];
-    char buf[MSG_SIZ];
-    int i, j;
-    int data = (intptr_t) client_data;
+    GtkWidget *entry;
+    GtkWidget *dialog;
+    GtkFileFilter *gtkfilter;
+    GtkFileFilter *gtkfilter_all;
+    int opt_i = (intptr_t) gdata;
+    GtkFileChooserAction fc_action;
+  
+    gtkfilter     = gtk_file_filter_new();
+    gtkfilter_all = gtk_file_filter_new();
+
+    char fileext[10] = "*";
+
+    /* select file or folder depending on option_type */
+    if (currentOption[opt_i].type == PathName)
+        fc_action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
+    else
+        fc_action = GTK_FILE_CHOOSER_ACTION_OPEN;
+
+    dialog = gtk_file_chooser_dialog_new ("Open File",
+                      NULL,
+                      fc_action,
+                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                      NULL);
+
+    /* one filter to show everything */
+    gtk_file_filter_add_pattern(gtkfilter_all, "*");
+    gtk_file_filter_set_name   (gtkfilter_all, "All Files");
+    gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),gtkfilter_all);
+    
+    /* filter for specific filetypes e.g. pgn or fen */
+    if (currentOption[opt_i].textValue != NULL && (strcmp(currentOption[opt_i].textValue, "") != 0) )    
+      {          
+        strcat(fileext, currentOption[opt_i].textValue);    
+        gtk_file_filter_add_pattern(gtkfilter, fileext);
+        gtk_file_filter_set_name (gtkfilter, currentOption[opt_i].textValue);
+        gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog),gtkfilter);
+        /* activate filter */
+        gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(dialog),gtkfilter);
+      }
+    else
+      gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(dialog),gtkfilter_all);       
 
-    XtSetArg(args[0], XtNlabel, &name);
-    XtGetValues(w, args, 1);
+    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+      {
+        char *filename;
+        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));             
+        entry = currentOption[opt_i].handle;
+        gtk_entry_set_text (GTK_ENTRY (entry), filename);        
+        g_free (filename);
 
-    if (strcmp(name, _("cancel")) == 0) {
-        SettingsPopDown();
-        return;
+      }
+    gtk_widget_destroy (dialog);
+    dialog = NULL;
+}
+
+static char *oneLiner  =
+   "<Key>Return: redraw-display() \n \
+    <Key>Tab: TabProc() \n ";
+static char scrollTranslations[] =
+   "<Btn1Up>(2): WheelProc(0 0 A) \n \
+    <Btn4Down>: WheelProc(-1) \n \
+    <Btn5Down>: WheelProc(1) \n ";
+
+static void
+SqueezeIntoBox (Option *opt, int nr, int width)
+{   // size buttons in bar to fit, clipping button names where necessary
+#ifdef TODO_GTK
+    int i, wtot = 0;
+    Dimension widths[20], oldWidths[20];
+    Arg arg;
+    for(i=1; i<nr; i++) {
+       XtSetArg(arg, XtNwidth, &widths[i]);
+       XtGetValues(opt[i].handle, &arg, 1);
+       wtot +=  oldWidths[i] = widths[i];
     }
-    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;
+    opt->min = wtot;
+    if(width <= 0) return;
+    while(wtot > width) {
+       int wmax=0, imax=0;
+       for(i=1; i<nr; i++) if(widths[i] > wmax) wmax = widths[imax=i];
+       widths[imax]--;
+       wtot--;
     }
-    snprintf(buf, MSG_SIZ,  "option %s\n", name);
-    SendToProgram(buf, currentCps);
+    for(i=1; i<nr; i++) if(widths[i] != oldWidths[i]) {
+       XtSetArg(arg, XtNwidth, widths[i]);
+       XtSetValues(opt[i].handle, &arg, 1);
+    }
+    opt->min = wtot;
+#endif
 }
 
-void ComboSelect(w, addr, index) // callback for all combo items
-     Widget w;
-     caddr_t addr;
-     caddr_t index;
-{
-    Arg args[16];
-    int i = ((intptr_t)addr)>>8;
-    int j = 255 & (intptr_t) addr;
+#ifdef TODO_GTK
+int
+SetPositionAndSize (Arg *args, Widget leftNeigbor, Widget topNeigbor, int b, int w, int h, int chaining)
+{   // sizing and positioning most widgets have in common
+    int j = 0;
+    // first position the widget w.r.t. earlier ones
+    if(chaining & 1) { // same row: position w.r.t. last (on current row) and lastrow
+       XtSetArg(args[j], XtNfromVert, topNeigbor); j++;
+       XtSetArg(args[j], XtNfromHoriz, leftNeigbor); j++;
+    } else // otherwise it goes at left margin (which is default), below the previous element
+       XtSetArg(args[j], XtNfromVert, leftNeigbor),  j++;
+    // arrange chaining ('2'-bit indicates top and bottom chain the same)
+    if((chaining & 14) == 6) XtSetArg(args[j], XtNtop,    XtChainBottom), j++;
+    if((chaining & 14) == 10) XtSetArg(args[j], XtNbottom, XtChainTop ), j++;
+    if(chaining & 4) XtSetArg(args[j], XtNbottom, XtChainBottom ), j++;
+    if(chaining & 8) XtSetArg(args[j], XtNtop,    XtChainTop), j++;
+    if(chaining & 0x10) XtSetArg(args[j], XtNright, XtChainRight), j++;
+    if(chaining & 0x20) XtSetArg(args[j], XtNleft,  XtChainRight), j++;
+    if(chaining & 0x40) XtSetArg(args[j], XtNright, XtChainLeft ), j++;
+    if(chaining & 0x80) XtSetArg(args[j], XtNleft,  XtChainLeft ), j++;
+    // set size (if given)
+    if(w) XtSetArg(args[j], XtNwidth, w), j++;
+    if(h) XtSetArg(args[j], XtNheight, h),  j++;
+    // color
+    if(!appData.monoMode) {
+       if(!b && appData.dialogColor[0]) XtSetArg(args[j], XtNbackground, dialogColor),  j++;
+       if(b == 3 && appData.buttonColor[0]) XtSetArg(args[j], XtNbackground, buttonColor),  j++;
+    }
+    if(b == 3) b = 1;
+    // border
+    XtSetArg(args[j], XtNborderWidth, b);  j++;
+    return j;
+}
+#endif
 
-    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);
+static int
+SameRow (Option *opt)
+{
+    return (opt->min & SAME_ROW && (opt->type == Button || opt->type == SaveButton || opt->type == Label || opt->type == ListBox));
 }
 
-void CreateComboPopup(parent, name, n, mb)
-     Widget parent;
-     String name;
-     int n;
-     char *mb[];
+static void
+Pack (GtkWidget *hbox, GtkWidget *table, GtkWidget *entry, int left, int right, int top)
 {
-    int i=0, j;
-    Widget menu, entry;
-    Arg args[16];
+    if(hbox) gtk_box_pack_start(GTK_BOX (hbox), entry, TRUE, TRUE, 0);
+    else     gtk_table_attach_defaults(GTK_TABLE(table), entry, left, right, top, top+1);
+}
 
-    menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
-                             parent, NULL, 0);
-    j = 0;
-    XtSetArg(args[j], XtNwidth, 100);  j++;
-//    XtSetArg(args[j], XtNright, XtChainRight);  j++;
-    while (mb[i] != NULL) {
-           entry = XtCreateManagedWidget(mb[i], smeBSBObjectClass,
-                                         menu, args, j);
-           XtAddCallback(entry, XtNcallback,
-                         (XtCallbackProc) ComboSelect,
-                         (caddr_t)(intptr_t) (256*n+i));
-       i++;
+int
+GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent, int modal, int topLevel)
+{    
+    GtkWidget *dialog = NULL;
+    gint       w;
+    GtkWidget *label;
+    GtkWidget *box;
+    GtkWidget *checkbutton;
+    GtkWidget *entry;
+    GtkWidget *hbox = NULL;    
+    GtkWidget *button;
+    GtkWidget *table;
+    GtkWidget *spinner;    
+    GtkAdjustment *spinner_adj;
+    GtkWidget *combobox;
+    GtkWidget *textview;
+    GtkTextBuffer *textbuffer;           
+    GdkColor color;     
+    GtkWidget *actionarea;
+    GtkWidget *sw;    
+    GtkWidget *list;    
+    GtkWidget *graph;    
+    GtkWidget *menuButton;    
+    GtkWidget *menuBar;    
+    GtkWidget *menu;    
+
+    int i, j, arraysize, left, top, height=999, width=1, boxStart;    
+    char def[MSG_SIZ], *msg, engineDlg = (currentCps != NULL && dlgNr != BrowserDlg);
+
+    if(dlgNr < PromoDlg && shellUp[dlgNr]) return 0; // already up
+
+    if(dlgNr && dlgNr < PromoDlg && shells[dlgNr]) { // reusable, and used before (but popped down)
+        gtk_widget_show(shells[dlgNr]);
+        shellUp[dlgNr] = True;
+        return 0;
     }
-}
 
-void
-SettingsPopUp(ChessProgramState *cps)
-{
-    Arg args[16];
-    Widget popup, layout, dialog, edit=NULL, form,  last, b_ok, b_cancel, leftMargin = NULL, textField = NULL;
+    dialogOptions[dlgNr] = option; // make available to callback
+    // 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!
+    currentOption = option;
+
+    if(engineDlg) { // 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(n && (currentOption[n-1].type == Button || currentOption[n-1].type == SaveButton)) currentOption[n].min = SAME_ROW; // OK on same line
+        currentOption[n].type = EndMark; currentOption[n].target = NULL; // delimit list by callback-less end mark
+    }    
+
+    parents[dlgNr] = parent;
+#ifdef TODO_GTK
+    shells[BoardWindow] = shellWidget; parents[dlgNr] = parent;
+
+    if(dlgNr == BoardWindow) dialog = shellWidget; else
+    dialog =
+      XtCreatePopupShell(title, !top || !appData.topLevel ? transientShellWidgetClass : topLevelShellWidgetClass,
+                                                           shells[parent], args, i);
+#endif
+    dialog = gtk_dialog_new_with_buttons( title,
+                                      GTK_WINDOW(shells[parent]),
+                                     GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR |
+                                          (modal ? GTK_DIALOG_MODAL : 0),
+                                      GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+                                      GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+                                      NULL );      
+
+    shells[dlgNr] = dialog;
+    box = gtk_dialog_get_content_area( GTK_DIALOG( dialog ) );
+    gtk_box_set_spacing(GTK_BOX(box), 5);    
+
+    arraysize = 0;
+    for (i=0;option[i].type != EndMark;i++) {
+        arraysize++;   
+    }
+
+    table = gtk_table_new(arraysize, 3, FALSE);
+    gtk_table_set_col_spacings(GTK_TABLE(table), 20);
+    left = 0;
+    top = -1;    
+
+    for (i=0;option[i].type != EndMark;i++) {
+       if(option[i].type == -1) continue;
+        top++;
+        if (top >= height) {
+            top = 0;
+            left = left + 3;
+            gtk_table_resize(GTK_TABLE(table), height, left + 3);   
+        }                
+        if(!SameRow(&option[i])) {
+           if(SameRow(&option[i+1])) {
+               // make sure hbox is always available when we have more options on same row
+                hbox = gtk_hbox_new (option[i].type == Button && option[i].textValue, 0);
+                if (strcmp(option[i].name, "") == 0 || option[i].type == Label || option[i].type == Button)
+                    // for Label and Button name is contained inside option
+                    gtk_table_attach_defaults(GTK_TABLE(table), hbox, left, left+3, top, top+1);
+                else
+                    gtk_table_attach_defaults(GTK_TABLE(table), hbox, left+1, left+3, top, top+1);
+           } else hbox = NULL; //and also make sure no hbox exists if only singl option on row
+        }
+        switch(option[i].type) {
+          case Fractional:           
+           snprintf(def, MSG_SIZ,  "%.2f", *(float*)option[i].target);
+           option[i].value = *(float*)option[i].target;
+            goto tBox;
+          case Spin:
+            if(!currentCps) option[i].value = *(int*)option[i].target;
+            snprintf(def, MSG_SIZ,  "%d", option[i].value);
+          case TextBox:
+         case FileName:            
+         case PathName:
+          tBox:
+            label = gtk_label_new(option[i].name);
+            /* Left Justify */
+            gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+            /* width */
+            w = option[i].type == Spin || option[i].type == Fractional ? 70 : option[i].max ? option[i].max : 205;
+           if(option[i].type == FileName || option[i].type == PathName) w -= 55;
+
+            if (option[i].type==TextBox && option[i].value > 80){                
+                textview = gtk_text_view_new();                
+                gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview), option[i].min & T_WRAP ? GTK_WRAP_WORD : GTK_WRAP_NONE);
+#ifdef TODO_GTK
+               if(option[i].min & T_FILL)  { XtSetArg(args[j], XtNautoFill, True);  j++; }
+               if(option[i].min & T_TOP)   { XtSetArg(args[j], XtNtop, XtChainTop); j++;
+#endif
+                /* add textview to scrolled window so we have vertical scroll bar */
+                sw = gtk_scrolled_window_new(NULL, NULL);
+                gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
+                                               option[i].min & T_HSCRL ? GTK_POLICY_ALWAYS : GTK_POLICY_AUTOMATIC,
+                                               option[i].min & T_VSCRL ? GTK_POLICY_ALWAYS : GTK_POLICY_NEVER);
+                gtk_container_add(GTK_CONTAINER(sw), textview);
+                gtk_widget_set_size_request(GTK_WIDGET(sw), w, -1);
+                textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));                
+                gtk_widget_set_size_request(textview, -1, option[i].min);
+                /* check if label is empty */ 
+                if (strcmp(option[i].name,"") != 0) {
+                    gtk_table_attach_defaults(GTK_TABLE(table), label, left, left+1, top, top+1);
+                    Pack(hbox, table, sw, left+1, left+3, top);
+                }
+                else {
+                    /* no label so let textview occupy all columns */
+                    Pack(hbox, table, sw, left, left+3, top);
+                } 
+                if ( *(char**)option[i].target != NULL )
+                    gtk_text_buffer_set_text (textbuffer, *(char**)option[i].target, -1);
+                else
+                    gtk_text_buffer_set_text (textbuffer, "", -1); 
+                option[i].handle = (void*)textbuffer;
+                option[i].textValue = (char*)textview;
+               if(option[i].choice) { // textviews can request a handler for mouse events in the choice field
+                   g_signal_connect(textview, "button-press-event", G_CALLBACK (MemoEvent), (gpointer) &option[i] );
+                   g_signal_connect(textview, "button-release-event", G_CALLBACK (MemoEvent), (gpointer) &option[i] );
+                   g_signal_connect(textview, "motion-notify-event", G_CALLBACK (MemoEvent), (gpointer) &option[i] );
+               }
+                break; 
+            }
+
+            entry = gtk_entry_new();
+
+            if (option[i].type==Spin || option[i].type==Fractional)
+                gtk_entry_set_text (GTK_ENTRY (entry), def);
+            else if (currentCps)
+                gtk_entry_set_text (GTK_ENTRY (entry), option[i].textValue);
+            else if ( *(char**)option[i].target != NULL )
+                gtk_entry_set_text (GTK_ENTRY (entry), *(char**)option[i].target);            
+
+            //gtk_entry_set_width_chars (GTK_ENTRY (entry), 18);
+            gtk_entry_set_max_length (GTK_ENTRY (entry), w);
+
+            // left, right, top, bottom
+            if (strcmp(option[i].name, "") != 0) gtk_table_attach_defaults(GTK_TABLE(table), label, left, left+1, top, top+1);
+            //gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, i, i+1);            
+
+            if (option[i].type == Spin) {                
+                spinner_adj = (GtkAdjustment *) gtk_adjustment_new (option[i].value, option[i].min, option[i].max, 1.0, 0.0, 0.0);
+                spinner = gtk_spin_button_new (spinner_adj, 1.0, 0);
+                gtk_table_attach_defaults(GTK_TABLE(table), spinner, left+1, left+3, top, top+1);
+                option[i].handle = (void*)spinner;
+            }
+            else if (option[i].type == FileName || option[i].type == PathName) {
+                gtk_table_attach_defaults(GTK_TABLE(table), entry, left+1, left+2, top, top+1);
+                button = gtk_button_new_with_label ("Browse");
+                gtk_table_attach_defaults(GTK_TABLE(table), button, left+2, left+3, top, top+1);
+                g_signal_connect (button, "clicked", G_CALLBACK (BrowseGTK), (gpointer)(intptr_t) i);
+                option[i].handle = (void*)entry;                 
+            }
+            else {
+                Pack(hbox, table, entry, left + (strcmp(option[i].name, "") != 0), left+3, top);
+                option[i].handle = (void*)entry;
+            }                                  
+            break;
+          case CheckBox:
+            checkbutton = gtk_check_button_new_with_label(option[i].name);            
+            if(!currentCps) option[i].value = *(Boolean*)option[i].target;
+            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), option[i].value);
+            gtk_table_attach_defaults(GTK_TABLE(table), checkbutton, left, left+3, top, top+1);                            
+            option[i].handle = (void *)checkbutton;            
+            break; 
+         case Label:            
+            option[i].handle = (void *) (label = gtk_label_new(option[i].name));
+            /* Left Justify */
+            gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+           if(option[i].min & BORDER) {
+               GtkWidget *frame = gtk_frame_new(NULL);
+                gtk_container_add(GTK_CONTAINER(frame), label);
+               label = frame;
+           }
+            Pack(hbox, table, label, left, left+3, top);
+           if(option[i].target) { // allow user to specify event handler for button presses
+               gtk_widget_add_events(GTK_WIDGET(label), GDK_BUTTON_PRESS_MASK);
+               g_signal_connect(label, "button-press-event", G_CALLBACK(MemoEvent), (gpointer) &option[i]);
+           }
+           break;
+          case SaveButton:
+          case Button:
+            button = gtk_button_new_with_label (option[i].name);
+
+            /* set button color on view board dialog */
+            if(option[i].choice && ((char*)option[i].choice)[0] == '#' && !currentCps) {
+                gdk_color_parse( *(char**) option[i-1].target, &color );
+                gtk_widget_modify_bg ( GTK_WIDGET(button), GTK_STATE_NORMAL, &color );
+           }
+
+            /* set button color on new variant dialog */
+            if(option[i].textValue) {
+                gdk_color_parse( option[i].textValue, &color );
+                gtk_widget_modify_bg ( GTK_WIDGET(button), GTK_STATE_NORMAL, &color );
+                gtk_widget_set_sensitive(button, appData.noChessProgram || option[i].value < 0
+                                        || strstr(first.variants, VariantName(option[i].value)));                 
+            }
+            
+            Pack(hbox, table, button, left, left+1, top);
+            g_signal_connect (button, "clicked", G_CALLBACK (GenericCallback), (gpointer)(intptr_t) i + (dlgNr<<16));           
+            option[i].handle = (void*)button;            
+            break;  
+         case ComboBox:
+            label = gtk_label_new(option[i].name);
+            /* Left Justify */
+            gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+            gtk_table_attach_defaults(GTK_TABLE(table), label, left, left+1, top, top+1);
+
+            combobox = gtk_combo_box_new_text();            
+
+            for(j=0;;j++) {
+               if (  ((char **) option[i].textValue)[j] == NULL) break;
+               gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), ((char **) option[i].choice)[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, ((char**)(option[i].textValue))[j])) break;
+                }
+                /* If choice is NULL set to first */
+                if (option[i].choice[j] == NULL)
+                   option[i].value = 0;
+                else 
+                   option[i].value = j;
+            }
+
+            //option[i].value = j + (option[i].choice[j] == NULL);            
+            gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), option[i].value); 
+            
+            Pack(hbox, table, combobox, left+1, left+3, top);
+            g_signal_connect(G_OBJECT(combobox), "changed", G_CALLBACK(ComboSelect), (gpointer) (intptr_t) (i + 256*dlgNr));
+
+            option[i].handle = (void*)combobox;
+            values[i] = option[i].value;            
+            break;
+         case ListBox:
+            {
+                GtkCellRenderer *renderer;
+                GtkTreeViewColumn *column;
+                GtkListStore *store;
+
+                option[i].handle = (void *) (list = gtk_tree_view_new());
+                gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
+                renderer = gtk_cell_renderer_text_new();
+                column = gtk_tree_view_column_new_with_attributes("List Items", renderer, "text", 0, NULL);
+                gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
+                store = gtk_list_store_new(1, G_TYPE_STRING); // 1 column of text
+                gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store));
+                g_object_unref(store);
+                LoadListBox(&option[i], "?", -1, -1);
+               HighlightListBoxItem(&option[i], 0);
+
+                /* add listbox to scrolled window so we have vertical scroll bar */
+                sw = gtk_scrolled_window_new(NULL, NULL);
+                gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+                gtk_container_add(GTK_CONTAINER(sw), list);
+                gtk_widget_set_size_request(GTK_WIDGET(sw), option[i].max ? option[i].max : -1, option[i].value ? option[i].value : -1);
+                /* never has label, so let listbox occupy all columns */
+                Pack(hbox, table, sw, left, left+3, top);
+            }
+           break;
+         case Graph:
+           option[i].handle = (void*) (graph = gtk_drawing_area_new());
+            gtk_widget_set_size_request(graph, option[i].max, option[i].value);
+//         gtk_drawing_area_size(graph, option[i].max, option[i].value);
+            gtk_table_attach_defaults(GTK_TABLE(table), graph, left, left+3, top, top+1);
+            g_signal_connect (graph, "expose-event", G_CALLBACK (GraphEventProc), (gpointer) &option[i]);
+           gtk_widget_add_events(GTK_WIDGET(graph), GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
+            g_signal_connect (graph, "button-press-event", G_CALLBACK (GraphEventProc), (gpointer) &option[i]);
+            g_signal_connect (graph, "button-release-event", G_CALLBACK (GraphEventProc), (gpointer) &option[i]);
+            g_signal_connect (graph, "motion-notify-event", G_CALLBACK (GraphEventProc), (gpointer) &option[i]);
+
+#ifdef TODO_GTK
+           XtAddEventHandler(last, ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask, False,
+                     (XtEventHandler) GraphEventProc, &option[i]); // mandatory user-supplied expose handler
+           if(option[i].min & SAME_ROW) last = forelast, forelast = lastrow;
+#endif
+           option[i].choice = (char**) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, option[i].max, option[i].value); // image buffer
+           break;
+#ifdef TODO_GTK
+         case Graph:
+           j = SetPositionAndSize(args, last, lastrow, 0 /* border */,
+                                  option[i].max /* w */, option[i].value /* h */, option[i].min /* chain */);
+           option[i].handle = (void*)
+               (last = XtCreateManagedWidget("graph", widgetClass, form, args, j));
+           XtAddEventHandler(last, ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask, False,
+                     (XtEventHandler) GraphEventProc, &option[i]); // mandatory user-supplied expose handler
+           if(option[i].min & SAME_ROW) last = forelast, forelast = lastrow;
+           option[i].choice = (char**) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, option[i].max, option[i].value); // image buffer
+           break;
+         case PopUp: // note: used only after Graph, so 'last' refers to the Graph widget
+           option[i].handle = (void*) CreateComboPopup(last, option + i, i + 256*dlgNr, TRUE, option[i].value);
+           break;
+         case BoxBegin:
+           if(option[i].min & SAME_ROW) forelast = lastrow;
+           j = SetPositionAndSize(args, last, lastrow, 0 /* border */,
+                                  0 /* w */, 0 /* h */, option[i].min /* chain */);
+           XtSetArg(args[j], XtNorientation, XtorientHorizontal);  j++;
+           XtSetArg(args[j], XtNvSpace, 0);                        j++;
+           option[box=i].handle = (void*)
+               (last = XtCreateWidget("box", boxWidgetClass, form, args, j));
+           oldForm = form; form = last; oldLastRow = lastrow; oldForeLast = forelast;
+           lastrow = NULL; last = NULL;
+           break;
+#endif
+         case DropDown:
+           msg = _(option[i].name); // write name on the menu button
+//         XtSetArg(args[j], XtNmenuName, XtNewString(option[i].name));  j++;
+//         XtSetArg(args[j], XtNlabel, msg);  j++;
+           option[i].handle = (void*)
+               (menuButton = gtk_menu_item_new_with_label(msg));
+           gtk_widget_show(menuButton);
+           option[i].textValue = (char*) (menu = CreateMenuPopup(option + i, i + 256*dlgNr, -1));
+           gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuButton), menu);
+           gtk_menu_bar_append (GTK_MENU_BAR (menuBar), menuButton);
+
+           break;
+         case BarBegin:
+           menuBar = gtk_menu_bar_new ();
+           gtk_widget_show (menuBar);
+         case BoxBegin:
+           boxStart = i;
+           break;
+         case BarEnd:
+            gtk_table_attach_defaults(GTK_TABLE(table), menuBar, left, left+1, top, top+1);
+         case BoxEnd:
+//         XtManageChildren(&form, 1);
+//         SqueezeIntoBox(&option[boxStart], i-boxStart, option[boxStart].max);
+           if(option[i].target) ((ButtonCallback*)option[i].target)(boxStart); // callback that can make sizing decisions
+           break;
+         case Break:
+            if(option[i].min & SAME_ROW) top = height; // force next option to start in a new column
+            break; 
+       default:
+           printf("GenericPopUp: unexpected case in switch. i=%d type=%d name=%s.\n", i, option[i].type, option[i].name);
+           break;
+       }        
+    }
+
+    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+                        table, TRUE, TRUE, 0);    
+
+    /* Show dialog */
+    gtk_widget_show_all( dialog );    
+
+    /* hide OK/cancel buttons */
+    if((option[i].min & 2)) {
+        actionarea = gtk_dialog_get_action_area(GTK_DIALOG(dialog));
+        gtk_widget_hide(actionarea);
+    }
+
+    g_signal_connect (dialog, "response",
+                      G_CALLBACK (GenericPopDown),
+                      (gpointer)(intptr_t) dlgNr);
+    g_signal_connect (dialog, "delete-event",
+                      G_CALLBACK (GenericPopDown),
+                      (gpointer)(intptr_t) dlgNr);
+    shellUp[dlgNr]++;
+
+#ifdef TODO_GTK
+    Arg args[24];
+    Widget popup, layout, dialog=NULL, edit=NULL, form,  last, b_ok, b_cancel, previousPane = NULL, textField = NULL, oldForm, oldLastRow, oldForeLast;
     Window root, child;
-    int x, y, i, j, height, width, h, c;
+    int x, y, i, j, height=999, width=1, h, c, w, shrink=FALSE, stack = 0, box, chain;
     int win_x, win_y, maxWidth, maxTextWidth;
     unsigned int mask;
-    char def[MSG_SIZ];
+    char def[MSG_SIZ], *msg, engineDlg = (currentCps != NULL && dlgNr != BrowserDlg);
     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;
+    Widget texts[100], forelast = NULL, anchor, widest, lastrow = NULL, browse = NULL;
+    Dimension bWidth = 50;
+
+    if(dlgNr < PromoDlg && shellUp[dlgNr]) return 0; // already up
+    if(dlgNr && dlgNr < PromoDlg && shells[dlgNr]) { // reusable, and used before (but popped down)
+       XtPopup(shells[dlgNr], XtGrabNone);
+       shellUp[dlgNr] = True;
+       return 0;
+    }
 
-    if(cps->nrOptions > 50) width = 4; else if(cps->nrOptions>24) width = 2; else width = 1;
-    height = cps->nrOptions / width + 1;
+    dialogOptions[dlgNr] = option; // make available to callback
+    // 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!
+    currentOption = option;
+
+    if(engineDlg) { // 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(n && (currentOption[n-1].type == Button || currentOption[n-1].type == SaveButton)) currentOption[n].min = SAME_ROW; // 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++;
-    SettingsShell = popup =
-      XtCreatePopupShell(_("Settings Menu"), transientShellWidgetClass,
-                        shellWidget, args, i);
+    shells[BoardWindow] = shellWidget; parents[dlgNr] = parent;
+
+    if(dlgNr == BoardWindow) popup = shellWidget; else
+    popup = shells[dlgNr] =
+      XtCreatePopupShell(title, !top || !appData.topLevel ? transientShellWidgetClass : topLevelShellWidgetClass,
+                                                           shells[parent], args, i);
 
     layout =
       XtCreateManagedWidget(layoutName, formWidgetClass, popup,
                            layoutArgs, XtNumber(layoutArgs));
+    if(!appData.monoMode && appData.dialogColor[0]) XtSetArg(args[0], XtNbackground, dialogColor);
+    XtSetValues(layout, args, 1);
+
   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++;
+    XtSetArg(args[j], stack ? XtNfromVert : XtNfromHoriz, previousPane);  j++;
+    if(!appData.monoMode && appData.dialogColor[0]) XtSetArg(args[j], XtNbackground, dialogColor),  j++;
     XtSetValues(form, args, j);
-    leftMargin = form;
+    lastrow = forelast = NULL;
+    previousPane = form;
 
-    last = widest = NULL; anchor = forelast;
-    for(h=0; h<height; h++) {
-       forelast = last;
+    last = widest = NULL; anchor = lastrow;
+    for(h=0; h<height || c == width-1; h++) {
        i = h + c*height;
-        if(i >= cps->nrOptions) break;
-       switch(cps->option[i].type) {
+       if(option[i].type == EndMark) break;
+       if(option[i].type == -1) continue;
+       lastrow = forelast;
+       forelast = last;
+       switch(option[i].type) {
+         case Fractional:
+           snprintf(def, MSG_SIZ,  "%.2f", *(float*)option[i].target);
+           option[i].value = *(float*)option[i].target;
+           goto tBox;
          case Spin:
-           snprintf(def, MSG_SIZ,  "%d", cps->option[i].value);
+           if(!engineDlg) option[i].value = *(int*)option[i].target;
+           snprintf(def, MSG_SIZ,  "%d", 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++;
+         case FileName:
+         case PathName:
+          tBox:
+           if(option[i].name[0]) { // prefixed by label with option name
+               j = SetPositionAndSize(args, last, lastrow, 0 /* border */,
+                                      0 /* w */, textHeight /* h */, 0xC0 /* chain to left edge */);
+               XtSetArg(args[j], XtNjustify, XtJustifyLeft);  j++;
+               XtSetArg(args[j], XtNlabel, _(option[i].name));  j++;
+               texts[h] = dialog = XtCreateManagedWidget(option[i].name, labelWidgetClass, form, args, j);
+           } else texts[h] = dialog = NULL; // kludge to position from left margin
+           w = option[i].type == Spin || option[i].type == Fractional ? 70 : option[i].max ? option[i].max : 205;
+           if(option[i].type == FileName || option[i].type == PathName) w -= 55;
+           j = SetPositionAndSize(args, dialog, last, 1 /* border */,
+                                  w /* w */, option[i].type == TextBox ? option[i].value : 0 /* h */, 0x91 /* chain full width */);
+           if(option[i].type == TextBox) { // decorations for multi-line text-edits
+               if(option[i].min & T_VSCRL) { XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++; }
+               if(option[i].min & T_HSCRL) { XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollAlways);  j++; }
+               if(option[i].min & T_FILL)  { XtSetArg(args[j], XtNautoFill, True);  j++; }
+               if(option[i].min & T_WRAP)  { XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++; }
+               if(option[i].min & T_TOP)   { XtSetArg(args[j], XtNtop, XtChainTop); j++;
+                   if(!option[i].value) {    XtSetArg(args[j], XtNbottom, XtChainTop); j++;
+                                             XtSetValues(dialog, args+j-2, 2);
+                   }
+               }
+           } else shrink = TRUE;
            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++;
+           XtSetArg(args[j], XtNstring, option[i].type==Spin || option[i].type==Fractional ? def : 
+                               engineDlg ? option[i].textValue : *(char**)option[i].target);  j++;
            edit = last;
-           cps->option[i].handle = (void*)
+           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;
+           XtAddEventHandler(last, ButtonPressMask, False, SetFocus, (XtPointer) popup); // gets focus on mouse click
+           if(option[i].min == 0 || option[i].type != TextBox)
+               XtOverrideTranslations(last, XtParseTranslationTable(oneLiner)); // standard handler for <Enter> and <Tab>
+
+           if(option[i].type == TextBox || option[i].type == Fractional) 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);
+           if(option[i].type == FileName || option[i].type == PathName) {
+               msg = _("browse"); w = 0; // automatically scale to width of text
+               j = textHeight ? textHeight : 0;
+           } else {
+               w = 20; msg = "+"; j = textHeight/2; // spin button
+           }
+           j = SetPositionAndSize(args, last, edit, 3 /* border */,
+                                  w /* w */, j /* h */, 0x31 /* chain to right edge */);
+           edit = XtCreateManagedWidget(msg, commandWidgetClass, form, args, j);
+           XtAddCallback(edit, XtNcallback, SpinCallback, (XtPointer)(intptr_t) i + 256*dlgNr);
+           if(w == 0) browse = edit;
 
-           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++;
+           if(option[i].type != Spin) break;
+
+           j = SetPositionAndSize(args, last, edit, 3 /* border */,
+                                  20 /* w */, textHeight/2 /* h */, 0x31 /* chain to right edge */);
+           XtSetArg(args[j], XtNvertDistance, -1);  j++;
            last = XtCreateManagedWidget("-", commandWidgetClass, form, args, j);
-           XtAddCallback(last, XtNcallback, SpinCallback,
-                         (XtPointer)(intptr_t) i);
+           XtAddCallback(last, XtNcallback, SpinCallback, (XtPointer)(intptr_t) i + 256*dlgNr);
            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++;
+           if(!engineDlg) option[i].value = *(Boolean*)option[i].target; // where checkbox callback uses it
+           j = SetPositionAndSize(args, last, lastrow, 1 /* border */,
+                                  textHeight/2 /* w */, textHeight/2 /* h */, 0xC0 /* chain both to left edge */);
+           XtSetArg(args[j], XtNvertDistance, (textHeight+2)/4 + 3);  j++;
+           XtSetArg(args[j], XtNstate, option[i].value);  j++;
+           lastrow  = last;
+           option[i].handle = (void*)
+               (last = XtCreateManagedWidget(" ", toggleWidgetClass, form, args, j));
+           j = SetPositionAndSize(args, last, lastrow, 0 /* border */,
+                                  option[i].max /* w */, textHeight /* h */, 0xC1 /* chain */);
            XtSetArg(args[j], XtNjustify, XtJustifyLeft);  j++;
-           last = XtCreateManagedWidget(cps->option[i].name, labelWidgetClass, form, args, j);
+           XtSetArg(args[j], XtNlabel, _(option[i].name));  j++;
+           last = XtCreateManagedWidget("label", commandWidgetClass, form, args, j);
+           // make clicking the text toggle checkbox
+           XtAddEventHandler(last, ButtonPressMask, False, CheckCallback, (XtPointer)(intptr_t) i + 256*dlgNr);
+           shrink = TRUE; // following buttons must get text height
+           break;
+         case Label:
+           msg = option[i].name;
+           if(!msg) break;
+           chain = option[i].min;
+           if(chain & SAME_ROW) forelast = lastrow; else shrink = FALSE;
+           j = SetPositionAndSize(args, last, lastrow, (chain & 2) != 0 /* border */,
+                                  option[i].max /* w */, shrink ? textHeight : 0 /* h */, chain | 2 /* chain */);
+#if ENABLE_NLS
+           if(option[i].choice) XtSetArg(args[j], XtNfontSet, *(XFontSet*)option[i].choice), j++;
+#else
+           if(option[i].choice) XtSetArg(args[j], XtNfont, (XFontStruct*)option[i].choice), j++;
+#endif
+           XtSetArg(args[j], XtNresizable, False);  j++;
+           XtSetArg(args[j], XtNjustify, XtJustifyLeft);  j++;
+           XtSetArg(args[j], XtNlabel, _(msg));  j++;
+           option[i].handle = (void*) (last = XtCreateManagedWidget("label", labelWidgetClass, form, args, j));
+           if(option[i].target) // allow user to specify event handler for button presses
+               XtAddEventHandler(last, ButtonPressMask, False, CheckCallback, (XtPointer)(intptr_t) i + 256*dlgNr);
            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));
+           if(option[i].min & SAME_ROW) {
+               chain = 0x31; // 0011.0001 = both left and right side to right edge
+               forelast = lastrow;
+           } else chain = 0, shrink = FALSE;
+           j = SetPositionAndSize(args, last, lastrow, 3 /* border */,
+                                  option[i].max /* w */, shrink ? textHeight : 0 /* h */, option[i].min & 0xE | chain /* chain */);
+           XtSetArg(args[j], XtNlabel, _(option[i].name));  j++;
+           if(option[i].textValue) { // special for buttons of New Variant dialog
+               XtSetArg(args[j], XtNsensitive, appData.noChessProgram || option[i].value < 0
+                                        || strstr(first.variants, VariantName(option[i].value))); j++;
+               XtSetArg(args[j], XtNborderWidth, (gameInfo.variant == option[i].value)+1); j++;
+           }
+           option[i].handle = (void*)
+               (dialog = last = XtCreateManagedWidget(option[i].name, commandWidgetClass, form, args, j));
+           if(option[i].choice && ((char*)option[i].choice)[0] == '#' && !engineDlg) { // for the color picker default-reset
+               SetColor( *(char**) option[i-1].target, &option[i]);
+               XtAddEventHandler(option[i-1].handle, KeyReleaseMask, False, ColorChanged, (XtPointer)(intptr_t) i-1);
+           }
+           XtAddCallback(last, XtNcallback, GenericCallback, (XtPointer)(intptr_t) i + (dlgNr<<16)); // invokes user callback
+           if(option[i].textValue) SetColor( option[i].textValue, &option[i]); // for new-variant buttons
            break;
          case ComboBox:
-           j=0;
-           XtSetArg(args[j], XtNfromVert, last);  j++;
-           XtSetArg(args[j], XtNborderWidth, 0);  j++;
+           j = SetPositionAndSize(args, last, lastrow, 0 /* border */,
+                                  0 /* w */, textHeight /* h */, 0xC0 /* chain both sides to left edge */);
            XtSetArg(args[j], XtNjustify, XtJustifyLeft);  j++;
-           dialog = XtCreateManagedWidget(cps->option[i].name, labelWidgetClass, form, args, j);
+           XtSetArg(args[j], XtNlabel, _(option[i].name));  j++;
+           texts[h] = dialog = XtCreateManagedWidget(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*)
+           if(option[i].min & COMBO_CALLBACK) msg = _(option[i].name); else {
+             if(!engineDlg) SetCurrentComboSelection(option+i);
+             msg=_(((char**)option[i].choice)[option[i].value]);
+           }
+
+           j = SetPositionAndSize(args, dialog, last, (option[i].min & 2) == 0 /* border */,
+                                  option[i].max && !engineDlg ? option[i].max : 100 /* w */,
+                                  textHeight /* h */, 0x91 /* chain */); // same row as its label!
+           XtSetArg(args[j], XtNmenuName, XtNewString(option[i].name));  j++;
+           XtSetArg(args[j], XtNlabel, msg);  j++;
+           shrink = TRUE;
+           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;
+           CreateComboPopup(last, option + i, i + 256*dlgNr, TRUE, -1);
+           values[i] = option[i].value;
+           break;
+         case ListBox:
+           // Listbox goes in viewport, as needed for game list
+           if(option[i].min & SAME_ROW) forelast = lastrow;
+           j = SetPositionAndSize(args, last, lastrow, 1 /* border */,
+                                  option[i].max /* w */, option[i].value /* h */, option[i].min /* chain */);
+           XtSetArg(args[j], XtNresizable, False);  j++;
+           XtSetArg(args[j], XtNallowVert, True); j++; // scoll direction
+           last =
+             XtCreateManagedWidget("viewport", viewportWidgetClass, form, args, j);
+           j = 0; // now list itself
+           XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
+           XtSetArg(args[j], XtNforceColumns, True);  j++;
+           XtSetArg(args[j], XtNverticalList, True);  j++;
+           option[i].handle = (void*)
+               (edit = XtCreateManagedWidget("list", listWidgetClass, last, args, j));
+           XawListChange(option[i].handle, option[i].target, 0, 0, True);
+           XawListHighlight(option[i].handle, 0);
+           scrollTranslations[25] = '0' + i;
+           scrollTranslations[27] = 'A' + dlgNr;
+           XtOverrideTranslations(edit, XtParseTranslationTable(scrollTranslations)); // for mouse-wheel
+           break;
+         case Graph:
+           j = SetPositionAndSize(args, last, lastrow, 0 /* border */,
+                                  option[i].max /* w */, option[i].value /* h */, option[i].min /* chain */);
+           option[i].handle = (void*)
+               (last = XtCreateManagedWidget("graph", widgetClass, form, args, j));
+           XtAddEventHandler(last, ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask, False,
+                     (XtEventHandler) GraphEventProc, &option[i]); // mandatory user-supplied expose handler
+           if(option[i].min & SAME_ROW) last = forelast, forelast = lastrow;
+           option[i].choice = (char**) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, option[i].max, option[i].value); // image buffer
+           break;
+         case PopUp: // note: used only after Graph, so 'last' refers to the Graph widget
+           option[i].handle = (void*) CreateComboPopup(last, option + i, i + 256*dlgNr, TRUE, option[i].value);
+           break;
+         case BoxBegin:
+           if(option[i].min & SAME_ROW) forelast = lastrow;
+           j = SetPositionAndSize(args, last, lastrow, 0 /* border */,
+                                  0 /* w */, 0 /* h */, option[i].min /* chain */);
+           XtSetArg(args[j], XtNorientation, XtorientHorizontal);  j++;
+           XtSetArg(args[j], XtNvSpace, 0);                        j++;
+           option[box=i].handle = (void*)
+               (last = XtCreateWidget("box", boxWidgetClass, form, args, j));
+           oldForm = form; form = last; oldLastRow = lastrow; oldForeLast = forelast;
+           lastrow = NULL; last = NULL;
+           break;
+         case DropDown:
+           j = SetPositionAndSize(args, last, lastrow, 0 /* border */,
+                                  0 /* w */, 0 /* h */, 1 /* chain (always on same row) */);
+           forelast = lastrow;
+           msg = _(option[i].name); // write name on the menu button
+           XtSetArg(args[j], XtNmenuName, XtNewString(option[i].name));  j++;
+           XtSetArg(args[j], XtNlabel, msg);  j++;
+           option[i].handle = (void*)
+               (last = XtCreateManagedWidget(option[i].name, menuButtonWidgetClass, form, args, j));
+           option[i].textValue = (char*) CreateComboPopup(last, option + i, i + 256*dlgNr, FALSE, -1);
+           break;
+         case BoxEnd:
+           XtManageChildren(&form, 1);
+           SqueezeIntoBox(&option[box], i-box, option[box].max);
+           if(option[i].target) ((ButtonCallback*)option[i].target)(box); // callback that can make sizing decisions
+           last = form; lastrow = oldLastRow; form = oldForm; forelast = oldForeLast;
+           break;
+         case Break:
+           width++;
+           height = i+1;
+           stack = !(option[i].min & SAME_ROW);
            break;
        default:
-         if( appData.debugMode )
-           fprintf(debugFP, "SettingsPopUp: unexpected case in switch.\n");
-         break;
+           printf("GenericPopUp: 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++) {
+    if(browse != NULL) {
+       j=0;
+       XtSetArg(args[j], XtNwidth, &bWidth);  j++;
+       XtGetValues(browse, args, j);
+    }
+    for(h=0; h<height || c == width-1; h++) {
        i = h + c*height;
-        if(i >= cps->nrOptions) break;
-       if(cps->option[i].type == Spin || cps->option[i].type == TextBox) {
+       if(option[i].type == EndMark) break;
+       if(option[i].type == Spin || option[i].type == TextBox || option[i].type == ComboBox
+                                 || option[i].type == PathName || option[i].type == FileName) {
            Dimension w;
+           if(!texts[h]) continue;
            j=0;
            XtSetArg(args[j], XtNwidth, &w);  j++;
            XtGetValues(texts[h], args, j);
-           if(cps->option[i].type == Spin) {
+           if(option[i].type == Spin) {
                if(w > maxWidth) maxWidth = w;
                widest = texts[h];
            } else {
@@ -1686,74 +1783,150 @@ SettingsPopUp(ChessProgramState *cps)
     if(maxTextWidth + 110 < maxWidth)
         maxTextWidth = maxWidth - 110;
     else maxWidth = maxTextWidth + 110;
-    for(h=0; h<height; h++) {
+    for(h=0; h<height || c == width-1; h++) {
        i = h + c*height;
-        if(i >= cps->nrOptions) break;
+       if(option[i].type == EndMark) break;
+       if(!texts[h]) continue; // Note: texts[h] can be undefined (giving errors in valgrind), but then both if's below will be false.
        j=0;
-       if(cps->option[i].type == Spin) {
+       if(option[i].type == Spin) {
            XtSetArg(args[j], XtNwidth, maxWidth);  j++;
            XtSetValues(texts[h], args, j);
        } else
-       if(cps->option[i].type == TextBox) {
+       if(option[i].type == TextBox || option[i].type == ComboBox || option[i].type == PathName || option[i].type == FileName) {
            XtSetArg(args[j], XtNwidth, maxTextWidth);  j++;
            XtSetValues(texts[h], args, j);
+           if(bWidth != 50 && (option[i].type == FileName || option[i].type == PathName)) {
+               int tWidth = (option[i].max ? option[i].max : 205) - 5 - bWidth;
+               j = 0;
+               XtSetArg(args[j], XtNwidth, tWidth);  j++;
+               XtSetValues(option[i].handle, 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;
+    if(option[i].min & SAME_ROW) { // even when OK suppressed this EndMark bit can request chaining of last row to bottom
+       for(j=i-1; option[j+1].min & SAME_ROW; j--) {
+           XtSetArg(args[0], XtNtop, XtChainBottom);
+           XtSetArg(args[1], XtNbottom, XtChainBottom);
+           XtSetValues(option[j].handle, args, 2);
+       }
+       if((option[j].type == TextBox || option[j].type == ListBox) && option[j].name[0] == NULLCHAR) {
+           Widget w = option[j].handle;
+           if(option[j].type == ListBox) w = XtParent(w); // for listbox we must chain viewport
+           XtSetArg(args[0], XtNbottom, XtChainBottom);
+           XtSetValues(w, args, 1);
+       }
+       lastrow = forelast;
+    } else shrink = FALSE, lastrow = last, last = widest ? widest : dialog;
+    j = SetPositionAndSize(args, last, anchor ? anchor : lastrow, 3 /* border */,
+                          0 /* w */, shrink ? textHeight : 0 /* h */, 0x37 /* chain: right, bottom and use both neighbors */);
+
+  if(!(option[i].min & NO_OK)) {
+    option[i].handle = b_ok = XtCreateManagedWidget(_("OK"), commandWidgetClass, form, args, j);
+    XtAddCallback(b_ok, XtNcallback, GenericCallback, (XtPointer)(intptr_t) (30001 + (dlgNr<<16)));
+    if(!(option[i].min & NO_CANCEL)) {
+      XtSetArg(args[1], XtNfromHoriz, b_ok); // overwrites!
+      b_cancel = XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
+      XtAddCallback(b_cancel, XtNcallback, GenericCallback, (XtPointer)(intptr_t) (30000 + (dlgNr<<16)));
+    }
+  }
 
+    XtRealizeWidget(popup);
+    if(dlgNr != BoardWindow) { // assign close button, and position w.r.t. pointer, if not main window
+       XSetWMProtocols(xDisplay, XtWindow(popup), &wm_delete_window, 1);
+       snprintf(def, MSG_SIZ, "<Message>WM_PROTOCOLS: GenericPopDown(\"%d\") \n", dlgNr);
+       XtAugmentTranslations(popup, XtParseTranslationTable(def));
+       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, modal ? XtGrabExclusive : XtGrabNone);
+    shellUp[dlgNr]++; // count rather than flag
     previous = NULL;
-    if(textField)SetFocus(textField, popup, (XEvent*) NULL, False);
+    if(textField) SetFocus(textField, popup, (XEvent*) NULL, False);
+    if(dlgNr && wp[dlgNr] && wp[dlgNr]->width > 0) { // if persistent window-info available, reposition
+       j = 0;
+       XtSetArg(args[j], XtNheight, (Dimension) (wp[dlgNr]->height));  j++;
+       XtSetArg(args[j], XtNwidth,  (Dimension) (wp[dlgNr]->width));  j++;
+       XtSetArg(args[j], XtNx, (Position) (wp[dlgNr]->x));  j++;
+       XtSetArg(args[j], XtNy, (Position) (wp[dlgNr]->y));  j++;
+       XtSetValues(popup, args, j);
+    }
+    RaiseWindow(dlgNr);
+#endif
+    return 1; // tells caller he must do initialization (e.g. add specific event handlers)
+}
+
+/* function called when the data to Paste is ready */
+#ifdef TODO_GTK
+static void
+SendTextCB (Widget w, XtPointer client_data, Atom *selection,
+           Atom *type, XtPointer value, unsigned long *len, int *format)
+{
+  char buf[MSG_SIZ], *p = (char*) textOptions[(int)(intptr_t) client_data].choice, *name = (char*) value, *q;
+  if (value==NULL || *len==0) return; /* nothing selected, abort */
+  name[*len]='\0';
+  strncpy(buf, p, MSG_SIZ);
+  q = strstr(p, "$name");
+  snprintf(buf + (q-p), MSG_SIZ -(q-p), "%s%s", name, q+5);
+  SendString(buf);
+  XtFree(value);
 }
+#endif
 
-void FirstSettingsProc(w, event, prms, nprms)
-     Widget w;
-     XEvent *event;
-     String *prms;
-     Cardinal *nprms;
+void
+SendText (int n)
 {
-   SettingsPopUp(&first);
+#ifdef TODO_GTK
+    char *p = (char*) textOptions[n].choice;
+    if(strstr(p, "$name")) {
+       XtGetSelectionValue(menuBarWidget,
+         XA_PRIMARY, XA_STRING,
+         /* (XtSelectionCallbackProc) */ SendTextCB,
+         (XtPointer) (intptr_t) n, /* client_data passed to PastePositionCB */
+         CurrentTime
+       );
+    } else SendString(p);
+#endif
 }
 
-void SecondSettingsProc(w, event, prms, nprms)
-     Widget w;
-     XEvent *event;
-     String *prms;
-     Cardinal *nprms;
+void
+SetInsertPos (Option *opt, int pos)
 {
-   if(WaitForSecond(SettingsMenuIfReady)) return;
-   SettingsPopUp(&second);
+#ifdef TODO_GTK
+    Arg args[16];
+    XtSetArg(args[0], XtNinsertPosition, pos);
+    XtSetValues(opt->handle, args, 1);
+//    SetFocus(opt->handle, shells[InputBoxDlg], NULL, False); // No idea why this does not work, and the following is needed:
+//    XSetInputFocus(xDisplay, XtWindow(opt->handle), RevertToPointerRoot, CurrentTime);
+#endif
 }
 
-//---------------------------- Chat Windows ----------------------------------------------
+#ifdef TODO_GTK
+void
+TypeInProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
+{   // can be used as handler for any text edit in any dialog (from GenericPopUp, that is)
+    int n = prms[0][0] - '0';
+    Widget sh = XtParent(XtParent(XtParent(w))); // popup shell
+
+    if(n<2) { // Enter or Esc typed from primed text widget: treat as if dialog OK or cancel button hit.
+       int dlgNr; // figure out what the dialog number is by comparing shells (because we must pass it :( )
+       for(dlgNr=0; dlgNr<NrOfDialogs; dlgNr++) if(shellUp[dlgNr] && shells[dlgNr] == sh)
+           GenericCallback (w, (XtPointer)(intptr_t) (30000 + n + (dlgNr<<16)), NULL);
+    }
+}
+#endif
 
-void OutputChatMessage(int partner, char *mess)
+void
+HardSetFocus (Option *opt)
 {
-    return; // dummy
+#ifdef TODO_GTK
+    XSetInputFocus(xDisplay, XtWindow(opt->handle), RevertToPointerRoot, CurrentTime);
+#endif
 }
 
+