Add logo widgets in main board window
[xboard.git] / xboard.c
index 035866c..ebd046c 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -256,8 +256,6 @@ void DrawPositionProc P((Widget w, XEvent *event,
 void CommentClick P((Widget w, XEvent * event,
                   String * params, Cardinal * nParams));
 void ICSInputBoxPopUp P((void));
-void FileNamePopUp P((char *label, char *def, char *filter,
-                     FileProc proc, char *openMode));
 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
 void KeyBindingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void QuitWrapper P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
@@ -272,9 +270,7 @@ void DisplayMove P((int moveNumber));
 void ICSInitScript P((void));
 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
 void update_ics_width P(());
-int get_term_width P(());
 int CopyMemoProc P(());
-void SetupDropMenu P((void));
 
 /*
 * XBoard depends on Xt R4 or higher
@@ -293,7 +289,6 @@ GC lightSquareGC, darkSquareGC, lineGC, wdPieceGC, wlPieceGC,
 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
 Option *optList; // contains all widgets of main window
-XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
 #if ENABLE_NLS
 XFontSet fontSet, clockFontSet;
@@ -306,8 +301,6 @@ XFontStruct *coordFontStruct, *countFontStruct;
 XtAppContext appContext;
 char *layoutName;
 
-FileProc fileProc;
-char *fileOpenMode;
 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
 
 Position commentX = -1, commentY = -1;
@@ -432,60 +425,60 @@ XtActionsRec boardActions[] = {
 };
 
 char globalTranslations[] =
-  ":<Key>F9: MenuItem(ResignProc) \n \
-   :Ctrl<Key>n: MenuItem(NewGame) \n \
-   :Meta<Key>V: MenuItem(NewVariant) \n \
-   :Ctrl<Key>o: MenuItem(LoadGame) \n \
+  ":<Key>F9: MenuItem(Actions.Resign) \n \
+   :Ctrl<Key>n: MenuItem(File.NewGame) \n \
+   :Meta<Key>V: MenuItem(File.NewVariant) \n \
+   :Ctrl<Key>o: MenuItem(File.LoadGame) \n \
    :Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
    :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
    :Ctrl<Key>Down: LoadSelectedProc(3) \n \
    :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
-   :Ctrl<Key>s: MenuItem(SaveGame) \n \
-   :Ctrl<Key>c: MenuItem(CopyGame) \n \
-   :Ctrl<Key>v: MenuItem(PasteGame) \n \
-   :Ctrl<Key>O: MenuItem(LoadPosition) \n \
+   :Ctrl<Key>s: MenuItem(File.SaveGame) \n \
+   :Ctrl<Key>c: MenuItem(Edit.CopyGame) \n \
+   :Ctrl<Key>v: MenuItem(Edit.PasteGame) \n \
+   :Ctrl<Key>O: MenuItem(File.LoadPosition) \n \
    :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
    :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
-   :Ctrl<Key>S: MenuItem(SavePosition) \n \
-   :Ctrl<Key>C: MenuItem(CopyPosition) \n \
-   :Ctrl<Key>V: MenuItem(PastePosition) \n \
-   :Ctrl<Key>q: MenuItem(Exit) \n \
-   :Ctrl<Key>w: MenuItem(MachineWhite) \n \
-   :Ctrl<Key>b: MenuItem(MachineBlack) \n \
-   :Ctrl<Key>t: MenuItem(TwoMachines) \n \
-   :Ctrl<Key>a: MenuItem(AnalysisMode) \n \
-   :Ctrl<Key>g: MenuItem(AnalyzeFile) \n \
-   :Ctrl<Key>e: MenuItem(EditGame) \n \
-   :Ctrl<Key>E: MenuItem(EditPosition) \n \
-   :Meta<Key>O: MenuItem(ShowEngineOutput) \n \
-   :Meta<Key>E: MenuItem(ShowEvaluationGraph) \n \
-   :Meta<Key>G: MenuItem(ShowGameList) \n \
-   :Meta<Key>H: MenuItem(ShowMoveHistory) \n \
-   :<Key>Pause: MenuItem(Pause) \n \
-   :<Key>F3: MenuItem(Accept) \n \
-   :<Key>F4: MenuItem(Decline) \n \
-   :<Key>F12: MenuItem(Rematch) \n \
-   :<Key>F5: MenuItem(CallFlag) \n \
-   :<Key>F6: MenuItem(Draw) \n \
-   :<Key>F7: MenuItem(Adjourn) \n \
-   :<Key>F8: MenuItem(Abort) \n \
-   :<Key>F10: MenuItem(StopObserving) \n \
-   :<Key>F11: MenuItem(StopExamining) \n \
+   :Ctrl<Key>S: MenuItem(File.SavePosition) \n \
+   :Ctrl<Key>C: MenuItem(Edit.CopyPosition) \n \
+   :Ctrl<Key>V: MenuItem(Edit.PastePosition) \n \
+   :Ctrl<Key>q: MenuItem(File.Quit) \n \
+   :Ctrl<Key>w: MenuItem(Mode.MachineWhite) \n \
+   :Ctrl<Key>b: MenuItem(Mode.MachineBlack) \n \
+   :Ctrl<Key>t: MenuItem(Mode.TwoMachines) \n \
+   :Ctrl<Key>a: MenuItem(Mode.AnalysisMode) \n \
+   :Ctrl<Key>g: MenuItem(Mode.AnalyzeFile) \n \
+   :Ctrl<Key>e: MenuItem(Mode.EditGame) \n \
+   :Ctrl<Key>E: MenuItem(Mode.EditPosition) \n \
+   :Meta<Key>O: MenuItem(View.EngineOutput) \n \
+   :Meta<Key>E: MenuItem(View.EvaluationGraph) \n \
+   :Meta<Key>G: MenuItem(View.GameList) \n \
+   :Meta<Key>H: MenuItem(View.MoveHistory) \n \
+   :<Key>Pause: MenuItem(Mode.Pause) \n \
+   :<Key>F3: MenuItem(Action.Accept) \n \
+   :<Key>F4: MenuItem(Action.Decline) \n \
+   :<Key>F12: MenuItem(Action.Rematch) \n \
+   :<Key>F5: MenuItem(Action.CallFlag) \n \
+   :<Key>F6: MenuItem(Action.Draw) \n \
+   :<Key>F7: MenuItem(Action.Adjourn) \n \
+   :<Key>F8: MenuItem(Action.Abort) \n \
+   :<Key>F10: MenuItem(Action.StopObserving) \n \
+   :<Key>F11: MenuItem(Action.StopExamining) \n \
    :Ctrl<Key>d: MenuItem(DebugProc) \n \
    :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
-   :Meta<Key>End: MenuItem(ToEnd) \n \
-   :Meta<Key>Right: MenuItem(Forward) \n \
-   :Meta<Key>Home: MenuItem(ToStart) \n \
-   :Meta<Key>Left: MenuItem(Backward) \n \
-   :<Key>Left: MenuItem(Backward) \n \
-   :<Key>Right: MenuItem(Forward) \n \
-   :<Key>Home: MenuItem(Revert) \n \
-   :<Key>End: MenuItem(TruncateGame) \n \
-   :Ctrl<Key>m: MenuItem(MoveNow) \n \
-   :Ctrl<Key>x: MenuItem(RetractMove) \n \
-   :Meta<Key>J: MenuItem(Adjudications) \n \
-   :Meta<Key>U: MenuItem(CommonEngine) \n \
-   :Meta<Key>T: MenuItem(TimeControl) \n \
+   :Meta<Key>End: MenuItem(Edit.ForwardtoEnd) \n \
+   :Meta<Key>Right: MenuItem(Edit.Forward) \n \
+   :Meta<Key>Home: MenuItem(Edit.BacktoStart) \n \
+   :Meta<Key>Left: MenuItem(Edit.Backward) \n \
+   :<Key>Left: MenuItem(Edit.Backward) \n \
+   :<Key>Right: MenuItem(Edit.Forward) \n \
+   :<Key>Home: MenuItem(Edit.Revert) \n \
+   :<Key>End: MenuItem(Edit.TruncateGame) \n \
+   :Ctrl<Key>m: MenuItem(Engine.MoveNow) \n \
+   :Ctrl<Key>x: MenuItem(Engine.RetractMove) \n \
+   :Meta<Key>J: MenuItem(Options.Adjudications) \n \
+   :Meta<Key>U: MenuItem(Options.CommonEngine) \n \
+   :Meta<Key>T: MenuItem(Options.TimeControl) \n \
    :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
 #ifndef OPTIONSDIALOG
     "\
@@ -496,8 +489,8 @@ char globalTranslations[] =
    :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
 #endif
    "\
-   :<Key>F1: MenuItem(Manual) \n \
-   :<Key>F2: MenuItem(FlipView) \n \
+   :<Key>F1: MenuItem(Help.ManXBoard) \n \
+   :<Key>F2: MenuItem(View.FlipView) \n \
    :<KeyDown>Return: TempBackwardProc() \n \
    :<KeyUp>Return: TempForwardProc() \n";
 
@@ -840,23 +833,20 @@ int frameX, frameY;
 void
 GetActualPlacement (Widget wg, WindowPlacement *wp)
 {
-  Arg args[16];
-  Dimension w, h;
-  Position x, y;
   XWindowAttributes winAt;
   Window win, dummy;
-  int i, rx, ry;
+  int rx, ry;
 
   if(!wg) return;
 
-    win = XtWindow(wg);
-    XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
-    XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
-    wp->x = rx - winAt.x;
-    wp->y = ry - winAt.y;
-    wp->height = winAt.height;
-    wp->width = winAt.width;
-    frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
+  win = XtWindow(wg);
+  XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
+  XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
+  wp->x = rx - winAt.x;
+  wp->y = ry - winAt.y;
+  wp->height = winAt.height;
+  wp->width = winAt.width;
+  frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
 }
 
 void
@@ -890,6 +880,17 @@ MainWindowUp ()
 }
 
 void
+SwitchWindow ()
+{
+    extern Option dualOptions[];
+    static Window dual;
+    Window tmp = xBoardWindow;
+    if(!dual) dual = XtWindow(dualOptions[3].handle); // must be first call
+    xBoardWindow = dual; // swap them
+    dual = tmp;
+}
+
+void
 PopUpStartupDialog ()
 {  // start menu not implemented in XBoard
 }
@@ -921,35 +922,30 @@ ConvertToLine (int argc, char **argv)
 void
 InitDrawingSizes (BoardSize boardSize, int flags)
 {   // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
-    Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
-    Arg args[16];
-    XtGeometryResult gres;
+    Dimension boardWidth, boardHeight, w, h;
     int i;
     static Dimension oldWidth, oldHeight;
     static VariantClass oldVariant;
-    static int oldDual = -1, oldMono = -1;
+    static int oldMono = -1, oldTwoBoards = 0;
 
     if(!formWidget) return;
 
+    if(oldTwoBoards && !twoBoards) PopDown(DummyDlg);
+    oldTwoBoards = twoBoards;
+
     if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
 
-  if(boardWidth != oldWidth || boardHeight != oldHeight || oldDual != twoBoards) { // do resizing stuff only if size actually changed
+  if(boardWidth != oldWidth || boardHeight != oldHeight) { // do resizing stuff only if size actually changed
 
-    oldWidth = boardWidth; oldHeight = boardHeight; oldDual = twoBoards;
+    oldWidth = boardWidth; oldHeight = boardHeight;
     CreateGrid();
-    hOffset = boardWidth + 10;
-    for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
-       secondSegments[i] = gridSegments[i];
-       secondSegments[i].x1 += hOffset;
-       secondSegments[i].x2 += hOffset;
-    }
 
     /*
      * Inhibit shell resizing.
      */
-    shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
+    shellArgs[0].value = w = (XtArgVal) boardWidth + marginW ;
     shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
     shellArgs[4].value = shellArgs[2].value = w;
     shellArgs[5].value = shellArgs[3].value = h;
@@ -1069,6 +1065,8 @@ MakeColors ()
     forceMono |= MakeOneColor(appData.blackPieceColor, &blackPieceColor);
     forceMono |= MakeOneColor(appData.highlightSquareColor, &highlightSquareColor);
     forceMono |= MakeOneColor(appData.premoveHighlightColor, &premoveHighlightColor);
+    if (appData.lowTimeWarning)
+       forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
     if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
     if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
 
@@ -1104,17 +1102,69 @@ InitDrawingParams ()
     CreateAnyPieces();
 }
 
+void
+InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
+{   // detervtomine what fonts to use, and create them
+    XrmValue vTo;
+    XrmDatabase xdb;
+
+    if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
+       appData.clockFont = fontTable[CLOCK_FONT][squareSize];
+    if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
+       appData.font = fontTable[MESSAGE_FONT][squareSize];
+    if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
+       appData.coordFont = fontTable[COORD_FONT][squareSize];
+
+#if ENABLE_NLS
+    appData.font = InsertPxlSize(appData.font, fontPxlSize);
+    appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
+    appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
+    fontSet = CreateFontSet(appData.font);
+    clockFontSet = CreateFontSet(appData.clockFont);
+    {
+      /* For the coordFont, use the 0th font of the fontset. */
+      XFontSet coordFontSet = CreateFontSet(appData.coordFont);
+      XFontStruct **font_struct_list;
+      XFontSetExtents *fontSize;
+      char **font_name_list;
+      XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
+      coordFontID = XLoadFont(xDisplay, font_name_list[0]);
+      coordFontStruct = XQueryFont(xDisplay, coordFontID);
+      fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
+      textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
+    }
+#else
+    appData.font = FindFont(appData.font, fontPxlSize);
+    appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
+    appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
+    clockFontID = XLoadFont(xDisplay, appData.clockFont);
+    clockFontStruct = XQueryFont(xDisplay, clockFontID);
+    coordFontID = XLoadFont(xDisplay, appData.coordFont);
+    coordFontStruct = XQueryFont(xDisplay, coordFontID);
+    // textHeight in !NLS mode!
+#endif
+    countFontID = coordFontID;  // [HGM] holdings
+    countFontStruct = coordFontStruct;
+
+    xdb = XtDatabase(xDisplay);
+#if ENABLE_NLS
+    XrmPutLineResource(&xdb, "*international: True");
+    vTo.size = sizeof(XFontSet);
+    vTo.addr = (XtPointer) &fontSet;
+    XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
+#else
+    XrmPutStringResource(&xdb, "*font", appData.font);
+#endif
+}
+
 int
 main (int argc, char **argv)
 {
-    int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
+    int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
     XSetWindowAttributes window_attributes;
     Arg args[16];
-    Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
-    XrmValue vFrom, vTo;
-    XtGeometryResult gres;
+    Dimension boardWidth, boardHeight, w, h;
     char *p;
-    XrmDatabase xdb;
     int forceMono = False;
 
     srandom(time(0)); // [HGM] book: make random truly random
@@ -1136,14 +1186,14 @@ main (int argc, char **argv)
 
 #ifdef ENABLE_NLS
     XtSetLanguageProc(NULL, NULL, NULL);
+    if (appData.debugMode) {
+      fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
+    }
+
     bindtextdomain(PACKAGE, LOCALEDIR);
     textdomain(PACKAGE);
 #endif
 
-    shellWidget =
-      XtAppInitialize(&appContext, "XBoard", shellOptions,
-                     XtNumber(shellOptions),
-                     &argc, argv, xboardResources, NULL, 0);
     appData.boardSize = "";
     InitAppData(ConvertToLine(argc, argv));
     p = getenv("HOME");
@@ -1154,10 +1204,6 @@ main (int argc, char **argv)
     snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
     snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
 
-    XtGetApplicationResources(shellWidget, (XtPointer) &appData,
-                             clientResources, XtNumber(clientResources),
-                             NULL, 0);
-
     { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
        static char buf[MSG_SIZ];
        EscapeExpand(buf, appData.firstInitString);
@@ -1189,12 +1235,6 @@ main (int argc, char **argv)
         setbuf(debugFP, NULL);
     }
 
-#if ENABLE_NLS
-    if (appData.debugMode) {
-      fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
-    }
-#endif
-
     /* [HGM,HR] make sure board size is acceptable */
     if(appData.NrFiles > BOARD_FILES ||
        appData.NrRanks > BOARD_RANKS   )
@@ -1206,13 +1246,25 @@ main (int argc, char **argv)
 #endif
     InitBackEnd1();
 
+       gameInfo.variant = StringToVariant(appData.variant);
+       InitPosition(FALSE);
+
+    shellWidget =
+      XtAppInitialize(&appContext, "XBoard", shellOptions,
+                     XtNumber(shellOptions),
+                     &argc, argv, xboardResources, NULL, 0);
+
+    XtGetApplicationResources(shellWidget, (XtPointer) &appData,
+                             clientResources, XtNumber(clientResources),
+                             NULL, 0);
+
     xDisplay = XtDisplay(shellWidget);
     xScreen = DefaultScreen(xDisplay);
     wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
 
-       gameInfo.variant = StringToVariant(appData.variant);
-       InitPosition(FALSE);
-
+    /*
+     * determine size, based on supplied or remembered -size, or screen size
+     */
     if (isdigit(appData.boardSize[0])) {
         i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
                   &lineGap, &clockFontPxlSize, &coordFontPxlSize,
@@ -1269,12 +1321,6 @@ main (int argc, char **argv)
        tinyLayout = szd->tinyLayout;
        // [HGM] font: use defaults from settings file if available and not overruled
     }
-    if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
-       appData.clockFont = fontTable[CLOCK_FONT][squareSize];
-    if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
-       appData.font = fontTable[MESSAGE_FONT][squareSize];
-    if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
-       appData.coordFont = fontTable[COORD_FONT][squareSize];
 
     /* Now, using squareSize as a hint, find a good XPM/XIM set size */
     if (strlen(appData.pixmapDirectory) > 0) {
@@ -1304,46 +1350,7 @@ XBoard square size (hint): %d\n\
     /*
      * Determine what fonts to use.
      */
-#if ENABLE_NLS
-    appData.font = InsertPxlSize(appData.font, fontPxlSize);
-    appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
-    appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
-    fontSet = CreateFontSet(appData.font);
-    clockFontSet = CreateFontSet(appData.clockFont);
-    {
-      /* For the coordFont, use the 0th font of the fontset. */
-      XFontSet coordFontSet = CreateFontSet(appData.coordFont);
-      XFontStruct **font_struct_list;
-      XFontSetExtents *fontSize;
-      char **font_name_list;
-      XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
-      coordFontID = XLoadFont(xDisplay, font_name_list[0]);
-      coordFontStruct = XQueryFont(xDisplay, coordFontID);
-      fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
-      textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
-    }
-#else
-    appData.font = FindFont(appData.font, fontPxlSize);
-    appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
-    appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
-    clockFontID = XLoadFont(xDisplay, appData.clockFont);
-    clockFontStruct = XQueryFont(xDisplay, clockFontID);
-    coordFontID = XLoadFont(xDisplay, appData.coordFont);
-    coordFontStruct = XQueryFont(xDisplay, coordFontID);
-    // textHeight in !NLS mode!
-#endif
-    countFontID = coordFontID;  // [HGM] holdings
-    countFontStruct = coordFontStruct;
-
-    xdb = XtDatabase(xDisplay);
-#if ENABLE_NLS
-    XrmPutLineResource(&xdb, "*international: True");
-    vTo.size = sizeof(XFontSet);
-    vTo.addr = (XtPointer) &fontSet;
-    XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
-#else
-    XrmPutStringResource(&xdb, "*font", appData.font);
-#endif
+    InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
 
     /*
      * Detect if there are not enough colors available and adapt.
@@ -1360,16 +1367,6 @@ XBoard square size (hint): %d\n\
        appData.monoMode = True;
     }
 
-    if (appData.lowTimeWarning && !appData.monoMode) {
-      vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
-      vFrom.size = strlen(appData.lowTimeWarningColor);
-      XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
-      if (vTo.addr == NULL)
-               appData.monoMode = True;
-      else
-               lowTimeWarningColor = *(Pixel *) vTo.addr;
-    }
-
     if (appData.monoMode && appData.debugMode) {
        fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
                (unsigned long) XWhitePixel(xDisplay, xScreen),
@@ -1397,19 +1394,20 @@ XBoard square size (hint): %d\n\
 #else
                                                &clockFonStruct);
 #endif
-    boardWidget      = optList[22].handle;
-    menuBarWidget    = optList[ 0].handle;
-    dropMenu         = optList[25].handle;
-    titleWidget = optList[optList[10].type != -1 ? 10 : 13].handle;
+    boardWidget      = optList[W_BOARD].handle;
+    menuBarWidget    = optList[W_MENU].handle;
+    dropMenu         = optList[W_DROP].handle;
+    titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
     formWidget  = XtParent(boardWidget);
     XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
     XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
-    XtGetValues(optList[11].handle, args, 2);
+    XtGetValues(optList[W_WHITE].handle, args, 2);
     if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
       XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
       XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
-      XtGetValues(optList[18].handle, args, 2);
+      XtGetValues(optList[W_PAUSE].handle, args, 2);
     }
+    AppendEnginesToMenu(appData.recentEngineList);
 
     xBoardWindow = XtWindow(boardWidget);
 
@@ -1460,6 +1458,13 @@ XBoard square size (hint): %d\n\
     CreateGrid();
     CreateAnyPieces();
 
+    if(appData.logoSize)
+    {   // locate and read user logo
+       char buf[MSG_SIZ];
+       snprintf(buf, MSG_SIZ, "%s/%s.xpm", appData.logoDir, UserName());
+       XpmReadFileToPixmap(xDisplay, xBoardWindow, buf, (Pixmap *) &userLogo, NULL, NULL);
+    }
+
     if (appData.animate || appData.animateDragging)
       CreateAnimVars();
 
@@ -1507,6 +1512,7 @@ XBoard square size (hint): %d\n\
 
     gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
     InitPosition(TRUE);
+    UpdateLogos(TRUE);
 //    XtSetKeyboardFocus(shellWidget, formWidget);
     XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
 
@@ -1742,8 +1748,6 @@ CreateOneGC (XGCValues *gc_values, Pixel foreground, Pixel background)
 static void
 CreateGCs (int redo)
 {
-    XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
-      | GCBackground | GCFunction | GCPlaneMask;
     XGCValues gc_values;
     GC copyInvertedGC;
     Pixel white = XWhitePixel(xDisplay, xScreen);
@@ -2268,66 +2272,30 @@ CreateGrid ()
     }
 }
 
-int nrOfMenuItems = 7;
-Widget menuWidget[150];
-MenuListItem menuItemList[150] = {
-    { "LoadNextGameProc", LoadNextGameProc },
-    { "LoadPrevGameProc", LoadPrevGameProc },
-    { "ReloadGameProc", ReloadGameProc },
-    { "ReloadPositionProc", ReloadPositionProc },
-#ifndef OPTIONSDIALOG
-    { "AlwaysQueenProc", AlwaysQueenProc },
-    { "AnimateDraggingProc", AnimateDraggingProc },
-    { "AnimateMovingProc", AnimateMovingProc },
-    { "AutoflagProc", AutoflagProc },
-    { "AutoflipProc", AutoflipProc },
-    { "BlindfoldProc", BlindfoldProc },
-    { "FlashMovesProc", FlashMovesProc },
-#if HIGHDRAG
-    { "HighlightDraggingProc", HighlightDraggingProc },
-#endif
-    { "HighlightLastMoveProc", HighlightLastMoveProc },
-//    { "IcsAlarmProc", IcsAlarmProc },
-    { "MoveSoundProc", MoveSoundProc },
-    { "PeriodicUpdatesProc", PeriodicUpdatesProc },
-    { "PopupExitMessageProc", PopupExitMessageProc },
-    { "PopupMoveErrorsProc", PopupMoveErrorsProc },
-//    { "PremoveProc", PremoveProc },
-    { "ShowCoordsProc", ShowCoordsProc },
-    { "ShowThinkingProc", ShowThinkingProc },
-    { "HideThinkingProc", HideThinkingProc },
-    { "TestLegalityProc", TestLegalityProc },
-#endif
-    { "AboutGameProc", AboutGameEvent },
-    { "DebugProc", DebugProc },
-    { "NothingProc", NothingProc },
-  {NULL, NothingProc}
-};
-
 void
 MarkMenuItem (char *menuRef, int state)
 {
-    int nr = MenuToNumber(menuRef);
-return;
-    if(nr >= 0) {
+    MenuItem *item = MenuNameToItem(menuRef);
+
+    if(item) {
        Arg args[2];
        XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
-       XtSetValues(menuWidget[nr], args, 1);
+       XtSetValues(item->handle, args, 1);
     }
 }
 
 void
-EnableMenuItem (char *menuRef, int state)
+EnableNamedMenuItem (char *menuRef, int state)
 {
-    int nr = MenuToNumber(menuRef);
-return;
-    if(nr >= 0) XtSetSensitive(menuWidget[nr], state);
+    MenuItem *item = MenuNameToItem(menuRef);
+
+    if(item) XtSetSensitive(item->handle, state);
 }
 
 void
 EnableButtonBar (int state)
 {
-    XtSetSensitive(optList[15].handle, state);
+    XtSetSensitive(optList[W_BUTTON].handle, state);
 }
 
 
@@ -2335,41 +2303,18 @@ void
 SetMenuEnables (Enables *enab)
 {
   while (enab->name != NULL) {
-    EnableMenuItem(enab->name, enab->value);
+    EnableNamedMenuItem(enab->name, enab->value);
     enab++;
   }
 }
 
-int
-Equal(char *p, char *s)
-{   // compare strings skipping spaces in second
-    while(*s) {
-       if(*s == ' ') { s++; continue; }
-       if(*s++ != *p++) return 0;
-    }
-    return !*p;
-}
-
 void
 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
 {   // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
-    int i;
-    char *p;
+    MenuItem *item;
     if(*nprms == 0) return;
-    for(i=0; menuItemList[i].name; i++) {
-       if(Equal(prms[0], menuItemList[i].name)) {
-           (menuItemList[i].proc) ();
-           return;
-       }
-    }
-}
-
-static void
-MenuBarSelect (Widget w, caddr_t addr, caddr_t index)
-{
-    MenuProc *proc = (MenuProc *) addr;
-
-    (proc)();
+    item = MenuNameToItem(prms[0]);
+    if(item) ((MenuProc *) item->proc) ();
 }
 
 static void
@@ -2378,89 +2323,10 @@ MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
     RecentEngineEvent((int) (intptr_t) addr);
 }
 
-// some stuff that must remain in front-end
-static Widget mainBar, currentMenu;
-static int wtot, nr = 0, widths[10];
-
 void
-AppendMenuItem (char *text, char *name, MenuProc *action)
+AppendMenuItem (char *msg, int n)
 {
-    int j;
-    Widget entry;
-    Arg args[16];
-
-    j = 0;
-    XtSetArg(args[j], XtNleftMargin, 20);   j++;
-    XtSetArg(args[j], XtNrightMargin, 20);  j++;
-
-       if (strcmp(text, "----") == 0) {
-         entry = XtCreateManagedWidget(text, smeLineObjectClass,
-                                         currentMenu, args, j);
-       } else {
-          XtSetArg(args[j], XtNlabel, XtNewString(_(text)));
-           entry = XtCreateManagedWidget(name, smeBSBObjectClass,
-                                         currentMenu, args, j+1);
-           XtAddCallback(entry, XtNcallback,
-                         (XtCallbackProc) (strcmp(name, "recent") ? MenuBarSelect : MenuEngineSelect),
-                         (caddr_t) action);
-           menuWidget[nrOfMenuItems] = entry;
-       }
-}
-
-void
-CreateMenuButton (char *name, Menu *mb)
-{   // create menu button on main bar, and shell for pull-down list
-    int i, j;
-    Arg args[16];
-    Dimension w;
-
-       j = 0;
-       XtSetArg(args[j], XtNmenuName, XtNewString(name));  j++;
-       XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name)));  j++;
-       XtSetArg(args[j], XtNborderWidth, 0);                   j++;
-       mb->subMenu = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
-                                      mainBar, args, j);
-    currentMenu = XtCreatePopupShell(name, simpleMenuWidgetClass,
-                             mainBar, NULL, 0);
-       j = 0;
-       XtSetArg(args[j], XtNwidth, &w);                   j++;
-       XtGetValues(mb->subMenu, args, j);
-       wtot += mb->textWidth = widths[nr++] = w;
-}
-
-Widget
-CreateMenuBar (Menu *mb, int boardWidth)
-{
-    int i, j;
-    Arg args[16];
-    char menuName[MSG_SIZ];
-    Dimension w;
-    Menu *ma = mb;
-
-    // create bar itself
-    j = 0;
-    XtSetArg(args[j], XtNorientation, XtorientHorizontal);  j++;
-    XtSetArg(args[j], XtNvSpace, 0);                        j++;
-    XtSetArg(args[j], XtNborderWidth, 0);                   j++;
-    mainBar = XtCreateWidget("menuBar", boxWidgetClass,
-                            formWidget, args, j);
-
-    CreateMainMenus(mb); // put menus in bar according to description in back-end
-
-    // size buttons to make menu bar fit, clipping menu names where necessary
-    while(wtot > boardWidth - 40) {
-       int wmax=0, imax=0;
-       for(i=0; i<nr; i++) if(widths[i] > wmax) wmax = widths[imax=i];
-       widths[imax]--;
-       wtot--;
-    }
-    for(i=0; i<nr; i++) if(widths[i] != ma[i].textWidth) {
-       j = 0;
-       XtSetArg(args[j], XtNwidth, widths[i]);                   j++;
-       XtSetValues(ma[i].subMenu, args, j);
-    }
-
-    return mainBar;
+    CreateMenuItem((Widget) optList[W_ENGIN].textValue, msg, (XtCallbackProc) MenuEngineSelect, n);
 }
 
 void
@@ -2524,6 +2390,14 @@ CutOutSquare (int x, int y, int *x0, int *y0, int  kind)
     return 1;
 }
 
+void
+DrawLogo (void *handle, void *logo)
+{
+    if(!logo || !handle) return;
+    XCopyArea(xDisplay, (Pixmap) logo, XtWindow((Widget) handle), wlPieceGC,
+                               0, 0, appData.logoSize, appData.logoSize/2, 0, 0);
+}
+
 static void
 BlankSquare (int x, int y, int color, ChessSquare piece, Drawable dest, int fac)
 {   // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
@@ -2877,10 +2751,9 @@ DrawSeekDot (int x, int y, int colorNr)
 }
 
 void
-DrawGrid (int second)
+DrawGrid ()
 {
          XDrawSegments(xDisplay, xBoardWindow, lineGC,
-                       second ? secondSegments : // [HGM] dual
                        gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
 }
 
@@ -2939,29 +2812,6 @@ CommentPopDown ()
     PopDown(CommentDlg);
 }
 
-static char *openName;
-FILE *openFP;
-
-void
-DelayedLoad ()
-{
-  (void) (*fileProc)(openFP, 0, openName);
-}
-
-void
-FileNamePopUp (char *label, char *def, char *filter, FileProc proc, char *openMode)
-{
-    fileProc = proc;           /* I can't see a way not */
-    fileOpenMode = openMode;   /*   to use globals here */
-    {   // [HGM] use file-selector dialog stolen from Ghostview
-       int index; // this is not supported yet
-       if(openFP = XsraSelFile(shellWidget, label, NULL, NULL, _("could not open: "),
-                          (def[0] ? def : NULL), filter, openMode, NULL, &openName))
-         // [HGM] delay to give expose event opportunity to redraw board after browser-dialog popdown before lengthy load starts
-         ScheduleDelayedEvent(&DelayedLoad, 50);
-    }
-}
-
 
 /* Disable all user input other than deleting the window */
 static int frozen = 0;
@@ -2971,7 +2821,7 @@ FreezeUI ()
 {
   if (frozen) return;
   /* Grab by a widget that doesn't accept input */
-  XtAddGrab(optList[14].handle, TRUE, FALSE);
+  XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
   frozen = 1;
 }
 
@@ -2980,7 +2830,7 @@ void
 ThawUI ()
 {
   if (!frozen) return;
-  XtRemoveGrab(optList[14].handle);
+  XtRemoveGrab(optList[W_MESSG].handle);
   frozen = 0;
 }
 
@@ -2996,7 +2846,7 @@ ModeHighlight ()
 
     if (pausing != oldPausing) {
        oldPausing = pausing;
-       MarkMenuItem("Pause", pausing);
+       MarkMenuItem("Mode.Pause", pausing);
 
        if (appData.showButtonBar) {
          /* Always toggle, don't set.  Previous code messes up when
@@ -3006,12 +2856,12 @@ ModeHighlight ()
            Pixel oldbg, oldfg;
            XtSetArg(args[0], XtNbackground, &oldbg);
            XtSetArg(args[1], XtNforeground, &oldfg);
-           XtGetValues(optList[18].handle,
+           XtGetValues(optList[W_PAUSE].handle,
                        args, 2);
            XtSetArg(args[0], XtNbackground, oldfg);
            XtSetArg(args[1], XtNforeground, oldbg);
          }
-         XtSetValues(optList[18].handle, args, 2);
+         XtSetValues(optList[W_PAUSE].handle, args, 2);
        }
     }
 
@@ -3024,34 +2874,18 @@ ModeHighlight ()
        MarkMenuItem(wname, True);
     }
     oldmode = gameMode;
-    MarkMenuItem("Machine Match", matchMode && matchGame < appData.matchGames);
+    MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
 
     /* Maybe all the enables should be handled here, not just this one */
-    EnableMenuItem("Training", gameMode == Training || gameMode == PlayFromGameFile);
+    EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
+
+    DisplayLogos(optList[W_WHITE-1].handle, optList[W_BLACK+1].handle);
 }
 
 
 /*
  * Button/menu procedures
  */
-int
-LoadGamePopUp (FILE *f, int gameNumber, char *title)
-{
-    cmailMsgLoaded = FALSE;
-    if (gameNumber == 0) {
-       int error = GameListBuild(f);
-       if (error) {
-           DisplayError(_("Cannot build game list"), error);
-       } else if (!ListEmpty(&gameList) &&
-                  ((ListGame *) gameList.tailPred)->number > 1) {
-           GameListPopUp(f, title);
-           return TRUE;
-       }
-       GameListDestroy();
-       gameNumber = 1;
-    }
-    return LoadGame(f, gameNumber, title, FALSE);
-}
 
 /* this variable is shared between CopyPositionProc and SendPositionSelection */
 char *selected_fen_position=NULL;
@@ -3305,38 +3139,9 @@ ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
 }
 
 void
-DisplayMessage (char *message, char *extMessage)
-{
-  /* display a message in the message widget */
-
-  char buf[MSG_SIZ];
-  Arg arg;
-
-  if (extMessage)
-    {
-      if (*message)
-       {
-         snprintf(buf, sizeof(buf), "%s  %s", message, extMessage);
-         message = buf;
-       }
-      else
-       {
-         message = extMessage;
-       };
-    };
-
-    safeStrCpy(lastMsg, message, MSG_SIZ); // [HGM] make available
-
-  /* need to test if messageWidget already exists, since this function
-     can also be called during the startup, if for example a Xresource
-     is not set up correctly */
-  if(optList && optList[14].handle)
-    {
-      XtSetArg(arg, XtNlabel, message);
-      XtSetValues(optList[14].handle, &arg, 1);
-    };
-
-  return;
+ManProc ()
+{   // called from menu
+    ManInner(NULL, NULL, NULL, NULL);
 }
 
 void
@@ -3528,11 +3333,11 @@ StartClockTimer (long millisec)
 }
 
 void
-DisplayTimerLabel (int optNr, char *color, long timer, int highlight)
+DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
 {
     char buf[MSG_SIZ];
     Arg args[16];
-    Widget w = optList[optNr].handle;
+    Widget w = (Widget) opt->handle;
 
     /* check for low time warning */
     Pixel foregroundOrWarningColor = timerForegroundPixel;
@@ -3543,7 +3348,7 @@ DisplayTimerLabel (int optNr, char *color, long timer, int highlight)
       foregroundOrWarningColor = lowTimeWarningColor;
 
     if (appData.clockMode) {
-      snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
+      snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
       XtSetArg(args[0], XtNlabel, buf);
     } else {
       snprintf(buf, MSG_SIZ, "%s  ", color);
@@ -3945,9 +3750,30 @@ DrawPolygon (Pnt arrow[], int nr)
     if(appData.monoMode) arrow[nr] = arrow[0], XDrawLines(xDisplay, xBoardWindow, darkSquareGC, pts, nr+1, CoordModeOrigin);
 }
 
+static void
+LoadLogo (ChessProgramState *cps, int n, Boolean ics)
+{
+    char buf[MSG_SIZ], *logoName = buf;
+    if(appData.logo[n][0]) {
+       logoName = appData.logo[n];
+    } else if(appData.autoLogo) {
+       if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
+           sprintf(buf, "%s/%s.xpm", appData.logoDir, appData.icsHost);
+       } else if(appData.directory[n] && appData.directory[n][0]) {
+           sprintf(buf, "%s/%s.xpm", appData.logoDir, cps->tidy);
+       }
+    }
+    if(logoName[0])
+       XpmReadFileToPixmap(xDisplay, xBoardWindow, logoName, (Pixmap *) &(cps->programLogo), NULL, NULL);
+}
+
 void
 UpdateLogos (int displ)
 {
-    return; // no logos in XBoard yet
+    if(optList[W_WHITE-1].handle == NULL) return;
+    LoadLogo(&first, 0, 0);
+    LoadLogo(&second, 1, appData.icsActive);
+    if(displ) DisplayLogos(optList[W_WHITE-1].handle, optList[W_BLACK+1].handle);
+    return;
 }