Fix multi-leg promotions
[xboard.git] / xaw / xboard.c
index 71416d4..1c3ffc7 100644 (file)
@@ -5,7 +5,8 @@
  * Massachusetts.
  *
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free
+ * Software Foundation, Inc.
  *
  * The following terms apply to Digital Equipment Corporation's copyright
  * interest in XBoard:
@@ -148,6 +149,7 @@ extern char *getenv();
 #include <locale.h>
 #endif
 
+#include <X11/keysym.h>
 #include <X11/Intrinsic.h>
 #include <X11/StringDefs.h>
 #include <X11/Shell.h>
@@ -183,13 +185,6 @@ extern char *getenv();
 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
 #include "common.h"
 
-#if HAVE_LIBXPM
-#include <X11/xpm.h>
-#define IMAGE_EXT "xpm"
-#else
-#define IMAGE_EXT "xim"
-#endif
-
 #include "bitmaps/icon_white.bm"
 #include "bitmaps/icon_black.bm"
 #include "bitmaps/checkmark.bm"
@@ -210,6 +205,7 @@ extern char *getenv();
 #include "gettext.h"
 #include "draw.h"
 
+#define SLASH '/'
 
 #ifdef __EMX__
 #ifndef HAVE_USLEEP
@@ -260,9 +256,9 @@ void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms))
 Boolean TempBackwardActive = False;
 void ManInner P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void DisplayMove P((int moveNumber));
-void ICSInitScript P((void));
 void update_ics_width P(());
 int CopyMemoProc P(());
+static int FindLogo P((char *place, char *name, char *buf));
 
 /*
 * XBoard depends on Xt R4 or higher
@@ -318,6 +314,7 @@ WindowPlacement wpEvalGraph;
 WindowPlacement wpEngineOutput;
 WindowPlacement wpGameList;
 WindowPlacement wpTags;
+WindowPlacement wpDualBoard;
 
 
 /* This magic number is the number of intermediate frames used
@@ -387,60 +384,17 @@ XtActionsRec boardActions[] = {
 };
 
 char globalTranslations[] =
-  ":<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>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(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(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(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
     "\
@@ -451,8 +405,6 @@ char globalTranslations[] =
    :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
 #endif
    "\
-   :<Key>F1: MenuItem(Help.ManXBoard) \n \
-   :<Key>F2: MenuItem(View.FlipView) \n \
    :<KeyDown>Return: TempBackwardProc() \n \
    :<KeyUp>Return: TempForwardProc() \n";
 
@@ -463,7 +415,7 @@ char ICSInputTranslations[] =
 
 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
 //             as the widget is destroyed before the up-click can call extend-end
-char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
+char commentTranslations[] = "<Btn3Down>: extend-end(PRIMARY) select-start() CommentClick() \n";
 
 String xboardResources[] = {
     "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
@@ -474,128 +426,6 @@ String xboardResources[] = {
 /* Max possible square size */
 #define MAXSQSIZE 256
 
-static int xpm_avail[MAXSQSIZE];
-
-#ifdef HAVE_DIR_STRUCT
-
-/* Extract piece size from filename */
-static int
-xpm_getsize (char *name, int len, char *ext)
-{
-    char *p, *d;
-    char buf[10];
-
-    if (len < 4)
-      return 0;
-
-    if ((p=strchr(name, '.')) == NULL ||
-       StrCaseCmp(p+1, ext) != 0)
-      return 0;
-
-    p = name + 3;
-    d = buf;
-
-    while (*p && isdigit(*p))
-      *(d++) = *(p++);
-
-    *d = 0;
-    return atoi(buf);
-}
-
-/* Setup xpm_avail */
-static int
-xpm_getavail (char *dirname, char *ext)
-{
-    DIR *dir;
-    struct dirent *ent;
-    int  i;
-
-    for (i=0; i<MAXSQSIZE; ++i)
-      xpm_avail[i] = 0;
-
-    if (appData.debugMode)
-      fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
-
-    dir = opendir(dirname);
-    if (!dir)
-      {
-         fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
-                 programName, dirname);
-         exit(1);
-      }
-
-    while ((ent=readdir(dir)) != NULL) {
-       i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
-       if (i > 0 && i < MAXSQSIZE)
-         xpm_avail[i] = 1;
-    }
-
-    closedir(dir);
-
-    return 0;
-}
-
-void
-xpm_print_avail (FILE *fp, char *ext)
-{
-    int i;
-
-    fprintf(fp, _("Available `%s' sizes:\n"), ext);
-    for (i=1; i<MAXSQSIZE; ++i) {
-       if (xpm_avail[i])
-         printf("%d\n", i);
-    }
-}
-
-/* Return XPM piecesize closest to size */
-int
-xpm_closest_to (char *dirname, int size, char *ext)
-{
-    int i;
-    int sm_diff = MAXSQSIZE;
-    int sm_index = 0;
-    int diff;
-
-    xpm_getavail(dirname, ext);
-
-    if (appData.debugMode)
-      xpm_print_avail(stderr, ext);
-
-    for (i=1; i<MAXSQSIZE; ++i) {
-       if (xpm_avail[i]) {
-           diff = size - i;
-           diff = (diff<0) ? -diff : diff;
-           if (diff < sm_diff) {
-               sm_diff = diff;
-               sm_index = i;
-           }
-       }
-    }
-
-    if (!sm_index) {
-       fprintf(stderr, _("Error: No `%s' files!\n"), ext);
-       exit(1);
-    }
-
-    return sm_index;
-}
-#else  /* !HAVE_DIR_STRUCT */
-/* If we are on a system without a DIR struct, we can't
-   read the directory, so we can't collect a list of
-   filenames, etc., so we can't do any size-fitting. */
-int
-xpm_closest_to (char *dirname, int size, char *ext)
-{
-    fprintf(stderr, _("\
-Warning: No DIR structure found on this system --\n\
-         Unable to autosize for XPM/XIM pieces.\n\
-   Please report this error to %s.\n\
-   Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
-    return size;
-}
-#endif /* HAVE_DIR_STRUCT */
-
-
 /* Arrange to catch delete-window events */
 Atom wm_delete_window;
 void
@@ -669,7 +499,8 @@ ParseFont (char *name, int number)
   if(sscanf(name, "size%d:", &size)) {
     // [HGM] font: font is meant for specific boardSize (likely from settings file);
     //       defer processing it until we know if it matches our board size
-    if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
+    if(strstr(name, "-*-") &&        // only pay attention to things that look like X-fonts
+       size >= 0 && size<MAX_SIZE) { // for now, fixed limit
        fontTable[number][size] = strdup(strchr(name, ':')+1);
        fontValid[number][size] = True;
     }
@@ -707,7 +538,13 @@ CreateFonts ()
 void
 ParseColor (int n, char *name)
 { // in XBoard, just copy the color-name string
-  if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
+  if(colorVariable[n] && *name == '#') *(char**)colorVariable[n] = strdup(name);
+}
+
+char *
+Col2Text (int n)
+{
+    return *(char**)colorVariable[n];
 }
 
 void
@@ -812,6 +649,12 @@ GetActualPlacement (Widget wg, WindowPlacement *wp)
 }
 
 void
+GetPlacement (DialogClass dlg, WindowPlacement *wp)
+{ // wrapper to shield back-end from widget type
+  if(shellUp[dlg]) GetActualPlacement(shells[dlg], wp);
+}
+
+void
 GetWindowCoords ()
 { // wrapper to shield use of window handles from back-end (make addressible by number?)
   // In XBoard this will have to wait until awareness of window parameters is implemented
@@ -979,6 +822,7 @@ PrintArg (ArgType t)
     case ArgString:   p = " STR"; break;
     case ArgBoolean:  p = " TF"; break;
     case ArgSettingsFilename:
+    case ArgBackupSettingsFile:
     case ArgFilename: p = " FILE"; break;
     case ArgX:        p = " Nx"; break;
     case ArgY:        p = " Ny"; break;
@@ -992,11 +836,119 @@ PrintArg (ArgType t)
     case ArgTwo:
     case ArgNone:
     case ArgCommSettings:
+    case ArgMaster:
+    case ArgInstall:
       break;
   }
   return p;
 }
 
+char *
+GenerateGlobalTranslationTable (void)
+{
+  /* go through all menu items and extract the keyboard shortcuts, so that X11 can load them */
+  char *output[2];
+
+  int i,j,n=0;
+  MenuItem *mi;
+
+  output[0] = strdup(""); // build keystrokes with and wo mod keys separately
+  output[1] = strdup(""); // so the more specific can preceed the other
+
+  /* loop over all menu entries */
+  for( i=0; menuBar[i-n].mi || !n++; i++)
+    {
+      mi = menuBar[i+n].mi; // kludge to access 'noMenu' behind sentinel
+      for(j=0; mi[j].proc; j++)
+       {
+         if (mi[j].accel)
+           {
+             int ctrl  = 0;
+             int shift = 0;
+             int alt   = 0;
+
+             char *key,*test, *mods;
+
+             /* check for Ctrl/Alt */
+             if( strstr(mi[j].accel, "<Ctrl>")  ) ctrl  = 1;
+             if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
+             if( strstr(mi[j].accel, "<Alt>")   ) alt   = 1;
+
+             /* remove all <...> */
+             test = strrchr(mi[j].accel, '>');
+             if ( test==NULL )
+               key = strdup(mi[j].accel);
+             else
+               key = strdup(++test); // remove ">"
+
+             /* instead of shift X11 uses the uppercase letter directly*/
+             if (shift && strlen(key)==1 )
+               {
+                 *key  = toupper(*key);
+                 shift = 0;
+               }
+
+             /* handle some special cases which have different names in X11 */
+             if ( strncmp(key, "Page_Down", 9) == 0 )
+               {
+                 free(key);
+                 key=strdup("Next");
+               }
+             else if ( strncmp(key, "Page_Up", 7) == 0 )
+               {
+                 free(key);
+                 key=strdup("Prior");
+               };
+
+             /* create string of mods */
+             if (ctrl)
+               mods = strdup("Ctrl ");
+             else
+               mods = strdup("");
+
+             if(alt)
+               {
+                 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
+                 strncat(mods, "Meta ", 5);
+               };
+
+             if(shift)
+               {
+                 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
+                 strncat(mods, "Shift ", 6);
+               };
+
+             // remove trailing space
+             if( isspace(mods[strlen(mods)-1]) )
+               mods[strlen(mods)-1]='\0';
+
+             /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
+             char *name = malloc(MSG_SIZ);
+             if(n) snprintf(name, MSG_SIZ, "%s", mi[j].ref);
+             else  snprintf(name, MSG_SIZ, "%s.%s", menuBar[i].ref, mi[j].ref);
+
+             char *buffer = malloc(MSG_SIZ);
+             snprintf(buffer, MSG_SIZ, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
+
+             /* add string to the output */
+             output[shift|alt|ctrl] = realloc(output[shift|alt|ctrl], strlen(output[shift|alt|ctrl]) + strlen(buffer)+1);
+             strncat(output[shift|alt|ctrl], buffer, strlen(buffer));
+
+             /* clean up */
+             free(key);
+             free(buffer);
+             free(name);
+             free(mods);
+           }
+       }
+    }
+  output[1] = realloc(output[1], strlen(output[1]) + strlen(output[0])+1);
+  strncat(output[1], output[0], strlen(output[0]));
+  free(output[0]);
+  return output[1];
+}
+
+
 void
 PrintOptions ()
 {
@@ -1026,6 +978,11 @@ PrintOptions ()
   if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
 }
 
+void
+SlaveResize (Option *opt)
+{
+}
+
 int
 main (int argc, char **argv)
 {
@@ -1036,6 +993,9 @@ main (int argc, char **argv)
     char *p;
     int forceMono = False;
 
+    extern Option chatOptions[]; // FIXME: adapt Chat window, removing ICS pane and Hide button
+    chatOptions[6].type = chatOptions[10].type = Skip;
+
     srandom(time(0)); // [HGM] book: make random truly random
 
     setbuf(stdout, NULL);
@@ -1043,7 +1003,7 @@ main (int argc, char **argv)
     debugFP = stderr;
 
     if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
-       printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+      printf("%s version %s\n\n  configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
        exit(0);
     }
 
@@ -1052,6 +1012,23 @@ main (int argc, char **argv)
        exit(0);
     }
 
+    if(argc > 1 && !strcmp(argv[1], "--show-config")) { // [HGM] install: called to print config info
+       typedef struct {char *name, *value; } Config;
+       static Config configList[] = {
+         { "Datadir", DATADIR },
+         { "Sysconfdir", SYSCONFDIR },
+         { NULL }
+       };
+       int i;
+
+       for(i=0; configList[i].name; i++) {
+           if(argc > 2 && strcmp(argv[2], configList[i].name)) continue;
+           if(argc > 2) printf("%s", configList[i].value);
+           else printf("%-12s: %s\n", configList[i].name, configList[i].value);
+       }
+       exit(0);
+    }
+
     programName = strrchr(argv[0], '/');
     if (programName == NULL)
       programName = argv[0];
@@ -1148,6 +1125,8 @@ main (int argc, char **argv)
                    programName, appData.boardSize);
            exit(2);
        }
+       if(BOARD_WIDTH > 8)
+           squareSize = (squareSize*8 + BOARD_WIDTH/2)/BOARD_WIDTH; // scale height
        if (i < 7) {
            /* Find some defaults; use the nearest known size */
            SizeDefaults *szd, *nearest;
@@ -1171,8 +1150,8 @@ main (int argc, char **argv)
     } else {
         SizeDefaults *szd = sizeDefaults;
         if (*appData.boardSize == NULLCHAR) {
-           while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
-                  DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
+           while (DisplayWidth(xDisplay, xScreen)  < (szd->minScreenSize*BOARD_WIDTH  + 4)/8 ||
+                  DisplayHeight(xDisplay, xScreen) < (szd->minScreenSize*BOARD_HEIGHT + 4)/8) {
              szd++;
            }
            if (szd->name == NULL) szd--;
@@ -1255,7 +1234,7 @@ main (int argc, char **argv)
     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;
+    titleWidget = optList[optList[W_TITLE].type != Skip ? W_TITLE : W_SMALL].handle;
     formWidget  = XtParent(boardWidget);
     XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
     XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
@@ -1311,21 +1290,28 @@ main (int argc, char **argv)
 
     CatchDeleteWindow(shellWidget, "QuitProc");
 
-    CreateAnyPieces();
+    CreateAnyPieces(1);
     CreateGrid();
 
     if(appData.logoSize)
     {   // locate and read user logo
-       char buf[MSG_SIZ];
-       snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
+       char buf[MSG_SIZ], name[MSG_SIZ];
+       snprintf(name, MSG_SIZ, "/home/%s", UserName());
+       if(!FindLogo(name, ".logo", buf))
+           FindLogo(appData.logoDir, name + 6, buf);
        ASSIGN(userLogo, buf);
     }
 
     if (appData.animate || appData.animateDragging)
       CreateAnimVars();
 
+
+    char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
+
     XtAugmentTranslations(formWidget,
                          XtParseTranslationTable(globalTranslations));
+    XtAugmentTranslations(formWidget,
+                         XtParseTranslationTable(TranslationsTableMenus));
 
     XtAddEventHandler(formWidget, KeyPressMask, False,
                      (XtEventHandler) MoveTypeInProc, NULL);
@@ -1346,6 +1332,9 @@ main (int argc, char **argv)
       EngineOutputPopUp();
     }
 
+    gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
+    InitPosition(TRUE);
+
     InitBackEnd2();
 
     if (errorExitStatus == -1) {
@@ -1366,8 +1355,6 @@ main (int argc, char **argv)
        }
     }
 
-    gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
-    InitPosition(TRUE);
     UpdateLogos(TRUE);
 //    XtSetKeyboardFocus(shellWidget, formWidget);
     XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
@@ -1377,6 +1364,13 @@ main (int argc, char **argv)
     return 0;
 }
 
+void
+DoEvents ()
+{
+    XtInputMask m;
+    while((m = XtAppPending(appContext))) XtAppProcessEvent(appContext, m);
+}
+
 RETSIGTYPE
 TermSizeSigHandler (int sig)
 {
@@ -1560,7 +1554,7 @@ FindFont (char *pattern, int targetPxlSize)
         safeStrCpy(p, best, strlen(best)+1 );
     }
     if (appData.debugMode) {
-        fprintf(debugFP, _("resolved %s at pixel size %d\n  to %s\n"),
+        fprintf(debugFP, "resolved %s at pixel size %d\n  to %s\n",
                pattern, targetPxlSize, p);
     }
     XFreeFontNames(fonts);
@@ -1715,7 +1709,7 @@ ReSize (WindowPlacement *wp)
        if(sqy < sqx) sqx = sqy;
        if(sqx != squareSize) {
            squareSize = sqx; // adopt new square size
-           CreatePNGPieces(); // make newly scaled pieces
+           CreatePNGPieces(appData.pieceDirectory); // make newly scaled pieces
            InitDrawingSizes(0, 0); // creates grid etc.
        } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
        w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
@@ -1781,7 +1775,7 @@ HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
     MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
 }
 
-static int savedIndex;  /* gross that this is global */
+extern int savedIndex;  /* gross that this is global */
 
 void
 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
@@ -1798,27 +1792,6 @@ CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
        LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
 }
 
-void
-EditCommentPopUp (int index, char *title, char *text)
-{
-    savedIndex = index;
-    if (text == NULL) text = "";
-    NewCommentPopup(title, text, index);
-}
-
-void
-CommentPopUp (char *title, char *text)
-{
-    savedIndex = currentMove; // [HGM] vari
-    NewCommentPopup(title, text, currentMove);
-}
-
-void
-CommentPopDown ()
-{
-    PopDown(CommentDlg);
-}
-
 
 /* Disable all user input other than deleting the window */
 static int frozen = 0;
@@ -1846,7 +1819,7 @@ ModeHighlight ()
 {
     Arg args[16];
     static int oldPausing = FALSE;
-    static GameMode oldmode = (GameMode) -1;
+    static GameMode oldMode = (GameMode) -1;
     char *wname;
 
     if (!boardWidget || !XtIsRealized(boardWidget)) return;
@@ -1872,7 +1845,7 @@ ModeHighlight ()
        }
     }
 
-    wname = ModeToWidgetName(oldmode);
+    wname = ModeToWidgetName(oldMode);
     if (wname != NULL) {
        MarkMenuItem(wname, False);
     }
@@ -1880,8 +1853,9 @@ ModeHighlight ()
     if (wname != NULL) {
        MarkMenuItem(wname, True);
     }
-    oldmode = gameMode;
+    if(oldMode == TwoMachinesPlay) EnableNamedMenuItem("Mode.MachineMatch", True);
     MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
+    oldMode = gameMode;
 
     /* Maybe all the enables should be handled here, not just this one */
     EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
@@ -2024,6 +1998,7 @@ PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
             Atom *type, XtPointer value, unsigned long *len, int *format)
 {
   FILE* f;
+  int flip = appData.flipView;
   if (value == NULL || *len == 0) {
     return; /* nothing had been selected to copy */
   }
@@ -2035,7 +2010,9 @@ PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
   fwrite(value, 1, *len, f);
   fclose(f);
   XtFree(value);
+  if(!appData.autoFlipView) appData.flipView = flipView;
   LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
+  appData.flipView = flip;
 }
 
 /* called when Paste Game button is pressed,
@@ -2152,6 +2129,15 @@ ManProc ()
 }
 
 void
+InfoProc ()
+{
+    char buf[MSG_SIZ];
+    snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
+             INFODIR, INFOFILE);
+    system(buf);
+}
+
+void
 SetWindowTitle (char *text, char *title, char *icon)
 {
     Arg args[16];
@@ -2524,6 +2510,19 @@ FrameDelay (int time)
 
 #endif
 
+static int
+FindLogo (char *place, char *name, char *buf)
+{   // check if file exists in given place
+    FILE *f;
+    if(!place) return 0;
+    snprintf(buf, MSG_SIZ, "%s/%s.png", place, name);
+    if(*place && strcmp(place, ".") && (f = fopen(buf, "r")) ) {
+       fclose(f);
+       return 1;
+    }
+    return 0;
+}
+
 static void
 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
 {
@@ -2533,8 +2532,11 @@ LoadLogo (ChessProgramState *cps, int n, Boolean ics)
     } else if(appData.autoLogo) {
        if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
            sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
-       } else if(appData.directory[n] && appData.directory[n][0]) {
-           sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
+       } else { // engine; cascade
+           if(!FindLogo(appData.logoDir, cps->tidy, buf) &&   // first try user log folder
+              !FindLogo(appData.directory[n], "logo", buf) && // then engine directory
+              !FindLogo("/usr/local/share/games/plugins/logos", cps->tidy, buf) ) // then system folders
+               FindLogo("/usr/share/games/plugins/logos", cps->tidy, buf);
        }
     }
     if(logoName[0])