/* \r
* WinBoard.c -- Windows NT front end to XBoard\r
- * $Id$\r
+ * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
*\r
* Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.\r
* Enhancements Copyright 1992-2001 Free Software Foundation, Inc.\r
\r
#include <stdio.h>\r
#include <stdlib.h>\r
+#include <time.h>
#include <malloc.h>\r
#include <sys/stat.h>\r
#include <fcntl.h>\r
#include "wsockerr.h"\r
#include "defaults.h"\r
\r
+#include "wsnap.h"
+
+void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
+
+int myrandom(void);
+void mysrandom(unsigned int seed);
+
typedef struct {\r
ChessSquare piece; \r
POINT pos; /* window coordinates of current pos */\r
char *firstChessProgramNames;\r
char *secondChessProgramNames;\r
\r
-#define ARG_MAX 20000\r
+#define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
#define PALETTESIZE 256\r
\r
static int lastSizing = 0;\r
static int prevStderrPort;\r
\r
+/* [AS] Support for background textures */
+#define BACK_TEXTURE_MODE_DISABLED 0
+#define BACK_TEXTURE_MODE_PLAIN 1
+#define BACK_TEXTURE_MODE_FULL_RANDOM 2
+
+static HBITMAP liteBackTexture = NULL;
+static HBITMAP darkBackTexture = NULL;
+static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
+static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
+static int backTextureSquareSize = 0;
+static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
+
#if __GNUC__ && !defined(_winmajor)\r
#define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */\r
#else\r
#define MF(x) {x, {0, }, {0, }, 0}\r
MyFont fontRec[NUM_SIZES][NUM_FONTS] =\r
{\r
- { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), \r
- MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY),\r
- MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY) },\r
- { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), \r
- MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY),\r
- MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY) },\r
- { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY),\r
- MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY),\r
- MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY) },\r
- { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE),\r
- MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE),\r
- MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE) },\r
- { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM),\r
- MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM),\r
- MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM) },\r
- { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL),\r
- MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL),\r
- MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL) },\r
- { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE),\r
- MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE),\r
- MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE) },\r
- { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING),\r
- MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING),\r
- MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING) },\r
- { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE),\r
- MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE),\r
- MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE) },\r
- { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE),\r
- MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE),\r
- MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE) },\r
- { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM),\r
- MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM),\r
- MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM) },\r
- { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY),\r
- MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY),\r
- MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY) },\r
- { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE),\r
- MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE),\r
- MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE) },\r
- { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG),\r
- MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG),\r
- MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG) },\r
- { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE),\r
- MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE),\r
- MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE) },\r
- { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT),\r
- MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT),\r
- MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT) },\r
- { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL),\r
- MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL),\r
- MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL) },\r
- { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC),\r
- MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC),\r
- MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC) },\r
+ { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
+ { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
};\r
\r
MyFont *font[NUM_SIZES][NUM_FONTS];\r
BOOLEAN analysisDialogUp = FALSE;\r
static int analysisX, analysisY, analysisH, analysisW;\r
\r
+char errorTitle[MSG_SIZ];\r
char errorMessage[2*MSG_SIZ];\r
HWND errorDialog = NULL;\r
BOOLEAN moveErrorMessageUp = FALSE;\r
void ParseIcsTextMenu(char *icsTextMenuString);\r
VOID PopUpMoveDialog(char firstchar);\r
VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);\r
+
+/* [AS] */
+int NewGameFRC();
+int GameListOptions();
+
+HWND moveHistoryDialog = NULL;
+BOOLEAN moveHistoryDialogUp = FALSE;
+
+WindowPlacement wpMoveHistory;
+
+HWND evalGraphDialog = NULL;
+BOOLEAN evalGraphDialogUp = FALSE;
+
+WindowPlacement wpEvalGraph;
+
+HWND engineOutputDialog = NULL;
+BOOLEAN engineOutputDialogUp = FALSE;
+
+WindowPlacement wpEngineOutput;
+
+VOID MoveHistoryPopUp();
+VOID MoveHistoryPopDown();
+VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
+BOOL MoveHistoryIsUp();
+
+VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
+VOID EvalGraphPopUp();
+VOID EvalGraphPopDown();
+BOOL EvalGraphIsUp();
+
+VOID EngineOutputPopUp();
+VOID EngineOutputPopDown();
+BOOL EngineOutputIsUp();
+VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
/*\r
* Setting "frozen" should disable all user input other than deleting\r
LPSTR lpCmdLine, int nCmdShow)\r
{\r
MSG msg;\r
- HANDLE hAccelMain, hAccelNoAlt;\r
+ HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
debugFP = stderr;\r
\r
\r
hAccelMain = LoadAccelerators (hInstance, szAppName);\r
hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");\r
+ hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
/* Acquire and dispatch messages until a WM_QUIT message is received. */\r
\r
0)) /* highest message to examine */\r
{\r
if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&\r
+ !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
+ !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
+ !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
!(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&\r
!(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&\r
!(errorDialog && IsDialogMessage(errorDialog, &msg)) &&\r
!(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&\r
+ !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
!(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {\r
TranslateMessage(&msg); /* Translates virtual key codes */\r
DispatchMessage(&msg); /* Dispatches message to window */\r
}\r
InitAppData(lpCmdLine); /* Get run-time parameters */\r
if (appData.debugMode) {\r
- debugFP = fopen("winboard.debug", "w");\r
+ debugFP = fopen(appData.nameOfDebugFile, "w");
setbuf(debugFP, NULL);\r
}\r
\r
InitBackEnd1();\r
\r
+ InitEngineUCI( installDir, &first );
+ InitEngineUCI( installDir, &second );
+
/* Create a main window for this application instance. */\r
hwnd = CreateWindow(szAppName, szTitle,\r
(WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),\r
InitMenuChecks();\r
buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);\r
\r
+ /* [AS] Load textures if specified */
+ ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
+
+ if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
+ liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
+ liteBackTextureMode = appData.liteBackTextureMode;
+
+ if (liteBackTexture == NULL && appData.debugMode) {
+ fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
+ }
+ }
+
+ if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
+ darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
+ darkBackTextureMode = appData.darkBackTextureMode;
+
+ if (darkBackTexture == NULL && appData.debugMode) {
+ fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
+ }
+ }
+
+ mysrandom( (unsigned) time(NULL) );
+
/* Make a console window if needed */\r
if (appData.icsActive) {\r
ConsoleCreate();\r
}\r
\r
+ /* [AS] Restore layout */
+ if( wpMoveHistory.visible ) {
+ MoveHistoryPopUp();
+ }
+
+ if( wpEvalGraph.visible ) {
+ EvalGraphPopUp();
+ }
+
+ if( wpEngineOutput.visible ) {
+ EngineOutputPopUp();
+ }
+
InitBackEnd2();\r
\r
/* Make the window visible; update its client area; and return "success" */\r
\r
SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
+
+ /* [AS] Disable the FRC stuff if not playing the proper variant */
+ if( gameInfo.variant != VariantFischeRandom ) {
+ EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
+ }
+
if (hwndConsole) {\r
#if AOT_CONSOLE\r
SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
{ "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },\r
{ "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },\r
{ "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },\r
+ { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
{ "boardSize", ArgBoardSize, (LPVOID) &boardSize,\r
TRUE }, /* must come after all fonts */\r
{ "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },\r
{ "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
{ "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
{ "variant", ArgString, (LPVOID) &appData.variant, FALSE },\r
- { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion,\r
- FALSE },\r
- { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,\r
- FALSE },\r
+ { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
+ { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
{ "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },\r
{ "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },\r
{ "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
{ "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
+ /* [AS] New features */
+ { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
+ { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
+ { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
+ { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
+ { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
+ { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
+ { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
+ { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
+ { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
+ { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
+ { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
+ { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
+ { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
+ { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
+ { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
+ { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
+ { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
+ { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
+ { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
+ { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
+ { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
+ { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
+ { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
+ { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
+ { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
+ { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
+ { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
+ { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
+ { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
+ { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
+ { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
+ { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
+ { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
+ { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
+ { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
+ { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
+ { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
+ { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
+ { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
+ { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
+ { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
+ { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
+ { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
+ { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
+ { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
+ { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
+ { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
+ { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
+
+ /* [AS] Layout stuff */
+ { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
+ { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
+ { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
+ { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
+ { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
+
+ { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
+ { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
+ { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
+ { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
+ { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
+
+ { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
+ { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
+ { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
+ { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
+ { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
+
#ifdef ZIPPY\r
{ "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
{ "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },\r
appData.firstProtocolVersion = PROTOVER;\r
appData.secondProtocolVersion = PROTOVER;\r
appData.showButtonBar = TRUE;\r
+
+ /* [AS] New properties (see comments in header file) */
+ appData.firstScoreIsAbsolute = FALSE;
+ appData.secondScoreIsAbsolute = FALSE;
+ appData.saveExtendedInfoInPGN = FALSE;
+ appData.hideThinkingFromHuman = FALSE;
+ appData.liteBackTextureFile = "";
+ appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
+ appData.darkBackTextureFile = "";
+ appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
+ appData.renderPiecesWithFont = "";
+ appData.fontToPieceTable = "";
+ appData.fontBackColorWhite = 0;
+ appData.fontForeColorWhite = 0;
+ appData.fontBackColorBlack = 0;
+ appData.fontForeColorBlack = 0;
+ appData.fontPieceSize = 80;
+ appData.overrideLineGap = 1;
+ appData.adjudicateLossThreshold = 0;
+ appData.delayBeforeQuit = 0;
+ appData.delayAfterQuit = 0;
+ appData.nameOfDebugFile = "winboard.debug";
+ appData.pgnEventHeader = "Computer Chess Game";
+ appData.defaultFrcPosition = -1;
+ appData.gameListTags = GLT_DEFAULT_TAGS;
+ appData.saveOutOfBookInfo = TRUE;
+ appData.showEvalInMoveHistory = TRUE;
+ appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
+ appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
+ appData.highlightMoveWithArrow = FALSE;
+ appData.highlightArrowColor = ParseColorName( "#FFFF80" );
+ appData.useStickyWindows = TRUE;
+ appData.adjudicateDrawMoves = 0;
+ appData.autoDisplayComment = TRUE;
+ appData.autoDisplayTags = TRUE;
+ appData.firstIsUCI = FALSE;
+ appData.secondIsUCI = FALSE;
+ appData.firstHasOwnBookUCI = TRUE;
+ appData.secondHasOwnBookUCI = TRUE;
+ appData.polyglotDir = "";
+ appData.usePolyglotBook = FALSE;
+ appData.polyglotBook = "";
+ appData.defaultHashSize = 64;
+ appData.defaultCacheSizeEGTB = 4;
+ appData.defaultPathEGTB = "c:\\egtb";
+
+ InitWindowPlacement( &wpMoveHistory );
+ InitWindowPlacement( &wpEvalGraph );
+ InitWindowPlacement( &wpEngineOutput );
+
#ifdef ZIPPY\r
appData.zippyTalk = ZIPPY_TALK;\r
appData.zippyPlay = ZIPPY_PLAY;\r
gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
}\r
\r
+ /* [AS] Move history */
+ wpMoveHistory.visible = MoveHistoryIsUp();
+
+ if( moveHistoryDialog ) {
+ GetWindowPlacement(moveHistoryDialog, &wp);
+ wpMoveHistory.x = wp.rcNormalPosition.left;
+ wpMoveHistory.y = wp.rcNormalPosition.top;
+ wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
+ wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
+ }
+
+ /* [AS] Eval graph */
+ wpEvalGraph.visible = EvalGraphIsUp();
+
+ if( evalGraphDialog ) {
+ GetWindowPlacement(evalGraphDialog, &wp);
+ wpEvalGraph.x = wp.rcNormalPosition.left;
+ wpEvalGraph.y = wp.rcNormalPosition.top;
+ wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
+ wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
+ }
+
+ /* [AS] Engine output */
+ wpEngineOutput.visible = EngineOutputIsUp();
+
+ if( engineOutputDialog ) {
+ GetWindowPlacement(engineOutputDialog, &wp);
+ wpEngineOutput.x = wp.rcNormalPosition.left;
+ wpEngineOutput.y = wp.rcNormalPosition.top;
+ wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
+ wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
+ }
+
for (ad = argDescriptors; ad->argName != NULL; ad++) {\r
if (!ad->save) continue;\r
switch (ad->argType) {\r
*\r
\*---------------------------------------------------------------------------*/\r
\r
+/* [AS] Draw square using background texture */
+static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
+{
+ XFORM x;
+
+ if( mode == 0 ) {
+ return; /* Should never happen! */
+ }
+
+ SetGraphicsMode( dst, GM_ADVANCED );
+
+ switch( mode ) {
+ case 1:
+ /* Identity */
+ break;
+ case 2:
+ /* X reflection */
+ x.eM11 = -1.0;
+ x.eM12 = 0;
+ x.eM21 = 0;
+ x.eM22 = 1.0;
+ x.eDx = (FLOAT) dw + dx - 1;
+ x.eDy = 0;
+ dx = 0;
+ SetWorldTransform( dst, &x );
+ break;
+ case 3:
+ /* Y reflection */
+ x.eM11 = 1.0;
+ x.eM12 = 0;
+ x.eM21 = 0;
+ x.eM22 = -1.0;
+ x.eDx = 0;
+ x.eDy = (FLOAT) dh + dy - 1;
+ dy = 0;
+ SetWorldTransform( dst, &x );
+ break;
+ case 4:
+ /* X/Y flip */
+ x.eM11 = 0;
+ x.eM12 = 1.0;
+ x.eM21 = 1.0;
+ x.eM22 = 0;
+ x.eDx = (FLOAT) dx;
+ x.eDy = (FLOAT) dy;
+ dx = 0;
+ dy = 0;
+ SetWorldTransform( dst, &x );
+ break;
+ }
+
+ BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
+
+ x.eM11 = 1.0;
+ x.eM12 = 0;
+ x.eM21 = 0;
+ x.eM22 = 1.0;
+ x.eDx = 0;
+ x.eDy = 0;
+ SetWorldTransform( dst, &x );
+
+ ModifyWorldTransform( dst, 0, MWT_IDENTITY );
+}
+
+/* [AS] */
+enum {
+ PM_WP = 0,
+ PM_WN = 1,
+ PM_WB = 2,
+ PM_WR = 3,
+ PM_WQ = 4,
+ PM_WK = 5,
+ PM_BP = 6,
+ PM_BN = 7,
+ PM_BB = 8,
+ PM_BR = 9,
+ PM_BQ = 10,
+ PM_BK = 11
+};
+
+static HFONT hPieceFont = NULL;
+static HBITMAP hPieceMask[12];
+static HBITMAP hPieceFace[12];
+static int fontBitmapSquareSize = 0;
+static char pieceToFontChar[12] = { 'p', 'n', 'b', 'r', 'q', 'k', 'o', 'm', 'v', 't', 'w', 'l' };
+
+static BOOL SetPieceToFontCharTable( const char * map )
+{
+ BOOL result = FALSE;
+
+ if( map != NULL && strlen(map) == 12 ) {
+ int i;
+
+ for( i=0; i<12; i++ ) {
+ pieceToFontChar[i] = map[i];
+ }
+
+ result = TRUE;
+ }
+
+ return result;
+}
+
+static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
+{
+ HBRUSH hbrush;
+ BYTE r1 = GetRValue( color );
+ BYTE g1 = GetGValue( color );
+ BYTE b1 = GetBValue( color );
+ BYTE r2 = r1 / 2;
+ BYTE g2 = g1 / 2;
+ BYTE b2 = b1 / 2;
+ RECT rc;
+
+ /* Create a uniform background first */
+ hbrush = CreateSolidBrush( color );
+ SetRect( &rc, 0, 0, squareSize, squareSize );
+ FillRect( hdc, &rc, hbrush );
+ DeleteObject( hbrush );
+
+ if( mode == 1 ) {
+ /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
+ int steps = squareSize / 2;
+ int i;
+
+ for( i=0; i<steps; i++ ) {
+ BYTE r = r1 - (r1-r2) * i / steps;
+ BYTE g = g1 - (g1-g2) * i / steps;
+ BYTE b = b1 - (b1-b2) * i / steps;
+
+ hbrush = CreateSolidBrush( RGB(r,g,b) );
+ SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
+ FillRect( hdc, &rc, hbrush );
+ DeleteObject(hbrush);
+ }
+ }
+ else if( mode == 2 ) {
+ /* Diagonal gradient, good more or less for every piece */
+ POINT triangle[3];
+ HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
+ HBRUSH hbrush_old;
+ int steps = squareSize;
+ int i;
+
+ triangle[0].x = squareSize - steps;
+ triangle[0].y = squareSize;
+ triangle[1].x = squareSize;
+ triangle[1].y = squareSize;
+ triangle[2].x = squareSize;
+ triangle[2].y = squareSize - steps;
+
+ for( i=0; i<steps; i++ ) {
+ BYTE r = r1 - (r1-r2) * i / steps;
+ BYTE g = g1 - (g1-g2) * i / steps;
+ BYTE b = b1 - (b1-b2) * i / steps;
+
+ hbrush = CreateSolidBrush( RGB(r,g,b) );
+ hbrush_old = SelectObject( hdc, hbrush );
+ Polygon( hdc, triangle, 3 );
+ SelectObject( hdc, hbrush_old );
+ DeleteObject(hbrush);
+ triangle[0].x++;
+ triangle[2].y++;
+ }
+
+ SelectObject( hdc, hpen );
+ }
+}
+
+/*
+ [AS] The method I use to create the bitmaps it a bit tricky, but it
+ seems to work ok. The main problem here is to find the "inside" of a chess
+ piece: follow the steps as explained below.
+*/
+static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
+{
+ HBITMAP hbm;
+ HBITMAP hbm_old;
+ COLORREF chroma = RGB(0xFF,0x00,0xFF);
+ RECT rc;
+ SIZE sz;
+ POINT pt;
+ int backColor = whitePieceColor;
+ int foreColor = blackPieceColor;
+ int shapeIndex = index < 6 ? index+6 : index;
+
+ if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
+ backColor = appData.fontBackColorWhite;
+ foreColor = appData.fontForeColorWhite;
+ }
+ else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
+ backColor = appData.fontBackColorBlack;
+ foreColor = appData.fontForeColorBlack;
+ }
+
+ /* Mask */
+ hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
+
+ hbm_old = SelectObject( hdc, hbm );
+
+ rc.left = 0;
+ rc.top = 0;
+ rc.right = squareSize;
+ rc.bottom = squareSize;
+
+ /* Step 1: background is now black */
+ FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
+
+ GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
+
+ pt.x = (squareSize - sz.cx) / 2;
+ pt.y = (squareSize - sz.cy) / 2;
+
+ SetBkMode( hdc, TRANSPARENT );
+ SetTextColor( hdc, chroma );
+ /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
+ TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
+
+ SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
+ /* Step 3: the area outside the piece is filled with white */
+ FloodFill( hdc, 0, 0, chroma );
+ SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
+ /*
+ Step 4: this is the tricky part, the area inside the piece is filled with black,
+ but if the start point is not inside the piece we're lost!
+ There should be a better way to do this... if we could create a region or path
+ from the fill operation we would be fine for example.
+ */
+ FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
+
+ SetTextColor( hdc, 0 );
+ /*
+ Step 5: some fonts have "disconnected" areas that are skipped by the fill:
+ draw the piece again in black for safety.
+ */
+ TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
+
+ SelectObject( hdc, hbm_old );
+
+ if( hPieceMask[index] != NULL ) {
+ DeleteObject( hPieceMask[index] );
+ }
+
+ hPieceMask[index] = hbm;
+
+ /* Face */
+ hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
+
+ SelectObject( hdc, hbm );
+
+ {
+ HDC dc1 = CreateCompatibleDC( hdc_window );
+ HDC dc2 = CreateCompatibleDC( hdc_window );
+ HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
+
+ SelectObject( dc1, hPieceMask[index] );
+ SelectObject( dc2, bm2 );
+ FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
+ BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
+
+ /*
+ Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
+ the piece background and deletes (makes transparent) the rest.
+ Thanks to that mask, we are free to paint the background with the greates
+ freedom, as we'll be able to mask off the unwanted parts when finished.
+ We use this, to make gradients and give the pieces a "roundish" look.
+ */
+ SetPieceBackground( hdc, backColor, 2 );
+ BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
+
+ DeleteDC( dc2 );
+ DeleteDC( dc1 );
+ DeleteObject( bm2 );
+ }
+
+ SetTextColor( hdc, foreColor );
+ TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
+
+ SelectObject( hdc, hbm_old );
+
+ if( hPieceFace[index] != NULL ) {
+ DeleteObject( hPieceFace[index] );
+ }
+
+ hPieceFace[index] = hbm;
+}
+
+static int TranslatePieceToFontPiece( int piece )
+{
+ switch( piece ) {
+ case BlackPawn:
+ return PM_BP;
+ case BlackKnight:
+ return PM_BN;
+ case BlackBishop:
+ return PM_BB;
+ case BlackRook:
+ return PM_BR;
+ case BlackQueen:
+ return PM_BQ;
+ case BlackKing:
+ return PM_BK;
+ case WhitePawn:
+ return PM_WP;
+ case WhiteKnight:
+ return PM_WN;
+ case WhiteBishop:
+ return PM_WB;
+ case WhiteRook:
+ return PM_WR;
+ case WhiteQueen:
+ return PM_WQ;
+ case WhiteKing:
+ return PM_WK;
+ }
+
+ return 0;
+}
+
+void CreatePiecesFromFont()
+{
+ LOGFONT lf;
+ HDC hdc_window = NULL;
+ HDC hdc = NULL;
+ HFONT hfont_old;
+ int fontHeight;
+ int i;
+
+ if( fontBitmapSquareSize < 0 ) {
+ /* Something went seriously wrong in the past: do not try to recreate fonts! */
+ return;
+ }
+
+ if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
+ fontBitmapSquareSize = -1;
+ return;
+ }
+
+ if( fontBitmapSquareSize != squareSize ) {
+ hdc_window = GetDC( hwndMain );
+ hdc = CreateCompatibleDC( hdc_window );
+
+ if( hPieceFont != NULL ) {
+ DeleteObject( hPieceFont );
+ }
+ else {
+ for( i=0; i<12; i++ ) {
+ hPieceMask[i] = NULL;
+ hPieceFace[i] = NULL;
+ }
+ }
+
+ fontHeight = 75;
+
+ if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
+ fontHeight = appData.fontPieceSize;
+ }
+
+ fontHeight = (fontHeight * squareSize) / 100;
+
+ lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
+ lf.lfWidth = 0;
+ lf.lfEscapement = 0;
+ lf.lfOrientation = 0;
+ lf.lfWeight = FW_NORMAL;
+ lf.lfItalic = 0;
+ lf.lfUnderline = 0;
+ lf.lfStrikeOut = 0;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = PROOF_QUALITY;
+ lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
+ lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
+
+ hPieceFont = CreateFontIndirect( &lf );
+
+ if( hPieceFont == NULL ) {
+ fontBitmapSquareSize = -2;
+ }
+ else {
+ /* Setup font-to-piece character table */
+ if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) {
+ /* No (or wrong) global settings, try to detect the font */
+ if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
+ /* Alpha */
+ SetPieceToFontCharTable("phbrqkojntwl");
+ }
+ else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
+ /* DiagramTT* family */
+ SetPieceToFontCharTable("PNLRQKpnlrqk");
+ }
+ else {
+ /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
+ SetPieceToFontCharTable("pnbrqkomvtwl");
+ }
+ }
+
+ /* Create bitmaps */
+ hfont_old = SelectObject( hdc, hPieceFont );
+
+ CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
+ CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
+ CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
+ CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
+ CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
+ CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
+ CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
+ CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
+ CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
+ CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
+ CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
+ CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
+
+ SelectObject( hdc, hfont_old );
+
+ fontBitmapSquareSize = squareSize;
+ }
+ }
+
+ if( hdc != NULL ) {
+ DeleteDC( hdc );
+ }
+
+ if( hdc_window != NULL ) {
+ ReleaseDC( hwndMain, hdc_window );
+ }
+}
+
HBITMAP\r
DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)\r
{\r
whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
+
+ /* [AS] Force rendering of the font-based pieces */
+ if( fontBitmapSquareSize > 0 ) {
+ fontBitmapSquareSize = 0;
+ }
}\r
\r
\r
int\r
BoardWidth(int boardSize)\r
{\r
- return (BOARD_SIZE + 1) * sizeInfo[boardSize].lineGap +\r
+ int lineGap = sizeInfo[boardSize].lineGap;
+
+ if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
+ lineGap = appData.overrideLineGap;
+ }
+
+ return (BOARD_SIZE + 1) * lineGap +
BOARD_SIZE * sizeInfo[boardSize].squareSize;\r
}\r
\r
squareSize = sizeInfo[boardSize].squareSize;\r
lineGap = sizeInfo[boardSize].lineGap;\r
\r
+ if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
+ lineGap = appData.overrideLineGap;
+ }
+
if (tinyLayout != oldTinyLayout) {\r
long style = GetWindowLong(hwndMain, GWL_STYLE);\r
if (tinyLayout) {\r
\r
if (appData.blindfold) return;\r
\r
+ /* [AS] Use font-based pieces if needed */
+ if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
+ /* Create piece bitmaps, or do nothing if piece set is up to date */
+ CreatePiecesFromFont();
+
+ if( fontBitmapSquareSize == squareSize ) {
+ int index = TranslatePieceToFontPiece( piece );
+
+ SelectObject( tmphdc, hPieceMask[ index ] );
+
+ BitBlt( hdc,
+ x, y,
+ squareSize, squareSize,
+ tmphdc,
+ 0, 0,
+ SRCAND );
+
+ SelectObject( tmphdc, hPieceFace[ index ] );
+
+ BitBlt( hdc,
+ x, y,
+ squareSize, squareSize,
+ tmphdc,
+ 0, 0,
+ SRCPAINT );
+
+ return;
+ }
+ }
+
if (appData.monoMode) {\r
SelectObject(tmphdc, PieceBitmap(piece, \r
color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));\r
}\r
}\r
\r
+/* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
+int GetBackTextureMode( int algo )
+{
+ int result = BACK_TEXTURE_MODE_DISABLED;
+
+ switch( algo )
+ {
+ case BACK_TEXTURE_MODE_PLAIN:
+ result = 1; /* Always use identity map */
+ break;
+ case BACK_TEXTURE_MODE_FULL_RANDOM:
+ result = 1 + (myrandom() % 3); /* Pick a transformation at random */
+ break;
+ }
+
+ return result;
+}
+
+/*
+ [AS] Compute and save texture drawing info, otherwise we may not be able
+ to handle redraws cleanly (as random numbers would always be different).
+*/
+VOID RebuildTextureSquareInfo()
+{
+ BITMAP bi;
+ int lite_w = 0;
+ int lite_h = 0;
+ int dark_w = 0;
+ int dark_h = 0;
+ int row;
+ int col;
+
+ ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
+
+ if( liteBackTexture != NULL ) {
+ if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
+ lite_w = bi.bmWidth;
+ lite_h = bi.bmHeight;
+ }
+ }
+
+ if( darkBackTexture != NULL ) {
+ if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
+ dark_w = bi.bmWidth;
+ dark_h = bi.bmHeight;
+ }
+ }
+
+ for( row=0; row<BOARD_SIZE; row++ ) {
+ for( col=0; col<BOARD_SIZE; col++ ) {
+ if( (col + row) & 1 ) {
+ /* Lite square */
+ if( lite_w >= squareSize && lite_h >= squareSize ) {
+ backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_SIZE;
+ backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_SIZE;
+ backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
+ }
+ }
+ else {
+ /* Dark square */
+ if( dark_w >= squareSize && dark_h >= squareSize ) {
+ backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_SIZE;
+ backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_SIZE;
+ backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
+ }
+ }
+ }
+ }
+}
+
+/* [AS] Arrow highlighting support */
+
+static int A_WIDTH = 5; /* Width of arrow body */
+
+#define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
+#define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
+
+static double Sqr( double x )
+{
+ return x*x;
+}
+
+static int Round( double x )
+{
+ return (int) (x + 0.5);
+}
+
+/* Draw an arrow between two points using current settings */
+VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
+{
+ POINT arrow[7];
+ double dx, dy, j, k, x, y;
+
+ if( d_x == s_x ) {
+ int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
+
+ arrow[0].x = s_x + A_WIDTH;
+ arrow[0].y = s_y;
+
+ arrow[1].x = s_x + A_WIDTH;
+ arrow[1].y = d_y - h;
+
+ arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
+ arrow[2].y = d_y - h;
+
+ arrow[3].x = d_x;
+ arrow[3].y = d_y;
+
+ arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
+ arrow[4].y = d_y - h;
+
+ arrow[5].x = s_x - A_WIDTH;
+ arrow[5].y = d_y - h;
+
+ arrow[6].x = s_x - A_WIDTH;
+ arrow[6].y = s_y;
+ }
+ else if( d_y == s_y ) {
+ int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
+
+ arrow[0].x = s_x;
+ arrow[0].y = s_y + A_WIDTH;
+
+ arrow[1].x = d_x - w;
+ arrow[1].y = s_y + A_WIDTH;
+
+ arrow[2].x = d_x - w;
+ arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
+
+ arrow[3].x = d_x;
+ arrow[3].y = d_y;
+
+ arrow[4].x = d_x - w;
+ arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
+
+ arrow[5].x = d_x - w;
+ arrow[5].y = s_y - A_WIDTH;
+
+ arrow[6].x = s_x;
+ arrow[6].y = s_y - A_WIDTH;
+ }
+ else {
+ /* [AS] Needed a lot of paper for this! :-) */
+ dy = (double) (d_y - s_y) / (double) (d_x - s_x);
+ dx = (double) (s_x - d_x) / (double) (s_y - d_y);
+
+ j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
+
+ k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
+
+ x = s_x;
+ y = s_y;
+
+ arrow[0].x = Round(x - j);
+ arrow[0].y = Round(y + j*dx);
+
+ arrow[1].x = Round(x + j);
+ arrow[1].y = Round(y - j*dx);
+
+ if( d_x > s_x ) {
+ x = (double) d_x - k;
+ y = (double) d_y - k*dy;
+ }
+ else {
+ x = (double) d_x + k;
+ y = (double) d_y + k*dy;
+ }
+
+ arrow[2].x = Round(x + j);
+ arrow[2].y = Round(y - j*dx);
+
+ arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
+ arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
+
+ arrow[4].x = d_x;
+ arrow[4].y = d_y;
+
+ arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
+ arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
+
+ arrow[6].x = Round(x - j);
+ arrow[6].y = Round(y + j*dx);
+ }
+
+ Polygon( hdc, arrow, 7 );
+}
+
+/* [AS] Draw an arrow between two squares */
+VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
+{
+ int s_x, s_y, d_x, d_y;
+ HPEN hpen;
+ HPEN holdpen;
+ HBRUSH hbrush;
+ HBRUSH holdbrush;
+ LOGBRUSH stLB;
+
+ if( s_col == d_col && s_row == d_row ) {
+ return;
+ }
+
+ /* Get source and destination points */
+ SquareToPos( s_row, s_col, &s_x, &s_y);
+ SquareToPos( d_row, d_col, &d_x, &d_y);
+
+ if( d_y > s_y ) {
+ d_y += squareSize / 4;
+ }
+ else if( d_y < s_y ) {
+ d_y += 3 * squareSize / 4;
+ }
+ else {
+ d_y += squareSize / 2;
+ }
+
+ if( d_x > s_x ) {
+ d_x += squareSize / 4;
+ }
+ else if( d_x < s_x ) {
+ d_x += 3 * squareSize / 4;
+ }
+ else {
+ d_x += squareSize / 2;
+ }
+
+ s_x += squareSize / 2;
+ s_y += squareSize / 2;
+
+ /* Adjust width */
+ A_WIDTH = squareSize / 14;
+
+ /* Draw */
+ stLB.lbStyle = BS_SOLID;
+ stLB.lbColor = appData.highlightArrowColor;
+ stLB.lbHatch = 0;
+
+ hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
+ holdpen = SelectObject( hdc, hpen );
+ hbrush = CreateBrushIndirect( &stLB );
+ holdbrush = SelectObject( hdc, hbrush );
+
+ DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
+
+ SelectObject( hdc, holdpen );
+ SelectObject( hdc, holdbrush );
+ DeleteObject( hpen );
+ DeleteObject( hbrush );
+}
+
+BOOL HasHighlightInfo()
+{
+ BOOL result = FALSE;
+
+ if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
+ highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
+ {
+ result = TRUE;
+ }
+
+ return result;
+}
+
+BOOL IsDrawArrowEnabled()
+{
+ BOOL result = FALSE;
+
+ if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
+ result = TRUE;
+ }
+
+ return result;
+}
+
+VOID DrawArrowHighlight( HDC hdc )
+{
+ if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
+ DrawArrowBetweenSquares( hdc,
+ highlightInfo.sq[0].x, highlightInfo.sq[0].y,
+ highlightInfo.sq[1].x, highlightInfo.sq[1].y );
+ }
+}
+
+HRGN GetArrowHighlightClipRegion( HDC hdc )
+{
+ HRGN result = NULL;
+
+ if( HasHighlightInfo() ) {
+ int x1, y1, x2, y2;
+ int sx, sy, dx, dy;
+
+ SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
+ SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
+
+ sx = MIN( x1, x2 );
+ sy = MIN( y1, y2 );
+ dx = MAX( x1, x2 ) + squareSize;
+ dy = MAX( y1, y2 ) + squareSize;
+
+ result = CreateRectRgn( sx, sy, dx, dy );
+ }
+
+ return result;
+}
+
+/*
+ Warning: this function modifies the behavior of several other functions.
+
+ Basically, Winboard is optimized to avoid drawing the whole board if not strictly
+ needed. Unfortunately, the decision whether or not to perform a full or partial
+ repaint is scattered all over the place, which is not good for features such as
+ "arrow highlighting" that require a full repaint of the board.
+
+ So, I've tried to patch the code where I thought it made sense (e.g. after or during
+ user interaction, when speed is not so important) but especially to avoid errors
+ in the displayed graphics.
+
+ In such patched places, I always try refer to this function so there is a single
+ place to maintain knowledge.
+
+ To restore the original behavior, just return FALSE unconditionally.
+*/
+BOOL IsFullRepaintPreferrable()
+{
+ BOOL result = FALSE;
+
+ if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
+ /* Arrow may appear on the board */
+ result = TRUE;
+ }
+
+ return result;
+}
+
+/*
+ This function is called by DrawPosition to know whether a full repaint must
+ be forced or not.
+
+ Only DrawPosition may directly call this function, which makes use of
+ some state information. Other function should call DrawPosition specifying
+ the repaint flag, and can use IsFullRepaintPreferrable if needed.
+*/
+BOOL DrawPositionNeedsFullRepaint()
+{
+ BOOL result = FALSE;
+
+ /*
+ Probably a slightly better policy would be to trigger a full repaint
+ when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
+ but animation is fast enough that it's difficult to notice.
+ */
+ if( animInfo.piece == EmptySquare ) {
+ if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
+ result = TRUE;
+ }
+ }
+
+ return result;
+}
+
VOID\r
DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)\r
{\r
int row, column, x, y, square_color, piece_color;\r
ChessSquare piece;\r
HBRUSH oldBrush;\r
+ HDC texture_hdc = NULL;
+
+ /* [AS] Initialize background textures if needed */
+ if( liteBackTexture != NULL || darkBackTexture != NULL ) {
+ if( backTextureSquareSize != squareSize ) {
+ backTextureSquareSize = squareSize;
+ RebuildTextureSquareInfo();
+ }
+
+ texture_hdc = CreateCompatibleDC( hdc );
+ }
\r
for (row = 0; row < BOARD_SIZE; row++) {\r
for (column = 0; column < BOARD_SIZE; column++) {\r
} else {\r
DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);\r
}\r
- } else {\r
+ }
+ else if( backTextureSquareInfo[row][column].mode > 0 ) {
+ /* [AS] Draw the square using a texture bitmap */
+ HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
+
+ DrawTile( x, y,
+ squareSize, squareSize,
+ hdc,
+ texture_hdc,
+ backTextureSquareInfo[row][column].mode,
+ backTextureSquareInfo[row][column].x,
+ backTextureSquareInfo[row][column].y );
+
+ SelectObject( texture_hdc, hbm );
+
+ if (piece != EmptySquare) {
+ DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
+ }
+ }
+ else {
oldBrush = SelectObject(hdc, square_color ?\r
lightSquareBrush : darkSquareBrush);\r
BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);\r
}\r
}\r
}\r
+
+ if( texture_hdc != NULL ) {
+ DeleteDC( texture_hdc );
+ }
}\r
\r
#define MAX_CLIPS 200 /* more than enough */\r
*/\r
Boolean fullrepaint = repaint;\r
\r
+ if( DrawPositionNeedsFullRepaint() ) {
+ fullrepaint = TRUE;
+ }
+
+#if 0
+ if( fullrepaint ) {
+ static int repaint_count = 0;
+ char buf[128];
+
+ repaint_count++;
+ sprintf( buf, "FULL repaint: %d\n", repaint_count );
+ OutputDebugString( buf );
+ }
+#endif
+
if (board == NULL) {\r
if (!lastReqValid) {\r
return;\r
DrawGridOnDC(hdcmem);\r
DrawHighlightsOnDC(hdcmem);\r
DrawBoardOnDC(hdcmem, board, tmphdc);\r
+
+ if( appData.highlightMoveWithArrow ) {
+ DrawArrowHighlight(hdcmem);
+ }
+
DrawCoordsOnDC(hdcmem);\r
\r
/* Put the dragged piece back into place and draw it */\r
POINT pt;\r
static int recursive = 0;\r
HMENU hmenu;\r
+ BOOLEAN needsRedraw = FALSE;
BOOLEAN saveAnimate;\r
+ BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
static BOOLEAN sameAgain = FALSE;\r
\r
if (recursive) {\r
}\r
if (!appData.highlightLastMove) {\r
ClearHighlights();\r
- DrawPosition(FALSE, NULL);\r
+ DrawPosition(forceFullRepaint || FALSE, NULL);
}\r
fromX = fromY = -1;\r
dragInfo.start.x = dragInfo.start.y = -1;\r
} else if (fromX == x && fromY == y) {\r
/* Downclick on same square again */\r
ClearHighlights();\r
- DrawPosition(FALSE, NULL);\r
+ DrawPosition(forceFullRepaint || FALSE, NULL);
sameAgain = TRUE; \r
} else if (fromX != -1) {\r
/* Downclick on different square */\r
UserMoveEvent(fromX, fromY, toX, toY, 'q');\r
if (!appData.highlightLastMove) {\r
ClearHighlights();\r
- DrawPosition(FALSE, NULL);\r
+ DrawPosition(forceFullRepaint || FALSE, NULL);
}\r
} else {\r
SetHighlights(fromX, fromY, toX, toY);\r
- DrawPosition(FALSE, NULL);\r
+ DrawPosition(forceFullRepaint || FALSE, NULL);
PromotionPopup(hwnd);\r
}\r
} else { /* not a promotion */\r
UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);\r
if (appData.animate && !appData.highlightLastMove) {\r
ClearHighlights();\r
- DrawPosition(FALSE, NULL);\r
+ DrawPosition(forceFullRepaint || FALSE, NULL);
}\r
}\r
if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
break;\r
}\r
ClearHighlights();\r
- DrawPosition(FALSE, NULL);\r
+ DrawPosition(forceFullRepaint || FALSE, NULL);
}\r
/* First downclick, or restart on a square with same color piece */\r
if (!frozen && OKToStartUserMove(x, y)) {\r
fromX = fromY = -1;\r
dragInfo.start.x = dragInfo.start.y = -1;\r
dragInfo.from = dragInfo.start;\r
+ DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
}\r
break;\r
\r
/* First square clicked: start click-click move */\r
SetHighlights(fromX, fromY, -1, -1);\r
}\r
- DrawPosition(FALSE, NULL);\r
+ DrawPosition(forceFullRepaint || FALSE, NULL);
} else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {\r
/* Errant click; ignore */\r
break;\r
if (appData.alwaysPromoteToQueen) {\r
UserMoveEvent(fromX, fromY, toX, toY, 'q');\r
} else {\r
- DrawPosition(FALSE, NULL);\r
+ DrawPosition(forceFullRepaint || FALSE, NULL);
PromotionPopup(hwnd);\r
}\r
} else {\r
}\r
if (appData.animate || appData.animateDragging ||\r
appData.highlightDragging || gotPremove) {\r
- DrawPosition(FALSE, NULL);\r
+ DrawPosition(forceFullRepaint || FALSE, NULL);
}\r
}\r
dragInfo.start.x = dragInfo.start.y = -1; \r
case WM_MOUSEMOVE:\r
if ((appData.animateDragging || appData.highlightDragging)\r
&& (wParam & MK_LBUTTON)\r
- && dragInfo.from.x >= 0) {\r
+ && dragInfo.from.x >= 0)
+ {
+ BOOL full_repaint = FALSE;
+
if (appData.animateDragging) {\r
dragInfo.pos = pt;\r
}\r
if (appData.highlightDragging) {\r
SetHighlights(fromX, fromY, x, y);\r
+ if( IsDrawArrowEnabled() && (x < 0 || x > 7 || y < 0 || y > y) ) {
+ full_repaint = TRUE;
}\r
- DrawPosition(FALSE, NULL);\r
+ }
+
+ DrawPosition( full_repaint, NULL);
+
dragInfo.lastpos = dragInfo.pos;\r
}\r
break;\r
FILE *f;\r
UINT number;\r
char fileTitle[MSG_SIZ];\r
+ static SnapData sd;
\r
switch (message) {\r
\r
AnalysisPopDown();\r
break;\r
\r
+ case IDM_NewGameFRC:
+ if( NewGameFRC() == 0 ) {
+ ResetGameEvent();
+ AnalysisPopDown();
+ }
+ break;
+
case IDM_LoadGame:\r
LoadGameDialog(hwnd, "Load Game from File");\r
break;\r
PasteGameFromClipboard();\r
break;\r
\r
+ case IDM_CopyGameListToClipboard:
+ CopyGameListToClipboard();
+ break;
+
+ /* [AS] Autodetect FEN or PGN data */
+ case IDM_PasteAny:
+ PasteGameOrFENFromClipboard();
+ break;
+
+ /* [AS] Move history */
+ case IDM_ShowMoveHistory:
+ if( MoveHistoryIsUp() ) {
+ MoveHistoryPopDown();
+ }
+ else {
+ MoveHistoryPopUp();
+ }
+ break;
+
+ /* [AS] Eval graph */
+ case IDM_ShowEvalGraph:
+ if( EvalGraphIsUp() ) {
+ EvalGraphPopDown();
+ }
+ else {
+ EvalGraphPopUp();
+ }
+ break;
+
+ /* [AS] Engine output */
+ case IDM_ShowEngineOutput:
+ if( EngineOutputIsUp() ) {
+ EngineOutputPopDown();
+ }
+ else {
+ EngineOutputPopUp();
+ }
+ break;
+
+ /* [AS] User adjudication */
+ case IDM_UserAdjudication_White:
+ UserAdjudicationEvent( +1 );
+ break;
+
+ case IDM_UserAdjudication_Black:
+ UserAdjudicationEvent( -1 );
+ break;
+
+ case IDM_UserAdjudication_Draw:
+ UserAdjudicationEvent( 0 );
+ break;
+
+ /* [AS] Game list options dialog */
+ case IDM_GameListOptions:
+ GameListOptions();
+ break;
+
case IDM_CopyPosition:\r
CopyFENToClipboard();\r
break;\r
\r
case IDM_GeneralOptions:\r
GeneralOptionsPopup(hwnd);\r
+ DrawPosition(TRUE, NULL);
break;\r
\r
case IDM_BoardOptions:\r
BoardOptionsPopup(hwnd);\r
break;\r
\r
+ case IDM_EnginePlayOptions:
+ EnginePlayOptionsPopup(hwnd);
+ break;
+
+ case IDM_OptionsUCI:
+ UciOptionsPopup(hwnd);
+ break;
+
case IDM_IcsOptions:\r
IcsOptionsPopup(hwnd);\r
break;\r
char dir[MSG_SIZ];\r
GetCurrentDirectory(MSG_SIZ, dir);\r
SetCurrentDirectory(installDir);\r
- debugFP = fopen("WinBoard.debug", "w");\r
+ debugFP = fopen(appData.nameOfDebugFile, "w");
SetCurrentDirectory(dir);\r
setbuf(debugFP, NULL);\r
} else {\r
InputEvent(hwnd, message, wParam, lParam);\r
break;\r
\r
+ /* [AS] Also move "attached" child windows */
+ case WM_WINDOWPOSCHANGING:
+ if( hwnd == hwndMain && appData.useStickyWindows ) {
+ LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
+
+ if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
+ /* Window is moving */
+ RECT rcMain;
+
+ GetWindowRect( hwnd, &rcMain );
+
+ ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
+ ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
+ ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
+ }
+ }
+ break;
+
+ /* [AS] Snapping */
case WM_ENTERSIZEMOVE:\r
if (hwnd == hwndMain) {\r
doingSizing = TRUE;\r
lastSizing = 0;\r
}\r
+ return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
break;\r
\r
case WM_SIZING:\r
}\r
break;\r
\r
+ case WM_MOVING:
+ return OnMoving( &sd, hwnd, wParam, lParam );
+
case WM_EXITSIZEMOVE:\r
if (hwnd == hwndMain) {\r
RECT client;\r
ResizeBoard(client.right, client.bottom, lastSizing);\r
lastSizing = 0;\r
}\r
+ return OnExitSizeMove( &sd, hwnd, wParam, lParam );
break;\r
\r
case WM_DESTROY: /* message: window being destroyed */\r
*\r
\*---------------------------------------------------------------------------*/\r
\r
+/*\r
+ * Decent random number generator, at least not as bad as Windows\r
+ * standard rand, which returns a value in the range 0 to 0x7fff.\r
+ */\r
+unsigned int randstate;\r
+\r
+int\r
+myrandom(void)\r
+{\r
+ randstate = randstate * 1664525 + 1013904223;\r
+ return (int) randstate & 0x7fffffff;\r
+}\r
+\r
+void\r
+mysrandom(unsigned int seed)\r
+{\r
+ randstate = seed;\r
+}\r
+\r
+\r
/* \r
* returns TRUE if user selects a different color, FALSE otherwise \r
*/\r
EndDeferWindowPos(cl.hdwp);\r
}\r
\r
-/* Center one window over another */\r
-BOOL CenterWindow (HWND hwndChild, HWND hwndParent)\r
+BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
{\r
RECT rChild, rParent;\r
int wChild, hChild, wParent, hParent;\r
}\r
\r
/* Calculate new Y position, then adjust for screen */\r
+ if( mode == 0 ) {
yNew = rParent.top + ((hParent - hChild) /2);\r
+ }
+ else {
+ yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
+ }
+
if (yNew < 0) {\r
yNew = 0;\r
} else if ((yNew+hChild) > hScreen) {\r
xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);\r
}\r
\r
+/* Center one window over another */
+BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
+{
+ return CenterWindowEx( hwndChild, hwndParent, 0 );
+}
+
/*---------------------------------------------------------------------------*\\r
*\r
* Startup Dialog functions\r
SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);\r
SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);\r
}\r
- if (chessProgram) {\r
- CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);\r
- } else if (appData.icsActive) {\r
+
+ if (appData.icsActive) {
CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);\r
- } else if (appData.noChessProgram) {\r
+ }
+ else if (appData.noChessProgram) {
CheckDlgButton(hDlg, OPT_View, BST_CHECKED);\r
}\r
+ else {
+ CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
+ }
+
SetStartupDialogEnables(hDlg);\r
return TRUE;\r
\r
case WM_INITDIALOG:\r
move[0] = (char) lParam;\r
move[1] = NULLCHAR;\r
- CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+ CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
hInput = GetDlgItem(hDlg, OPT_Move);\r
SetWindowText(hInput, move);\r
SetFocus(hInput);\r
\*---------------------------------------------------------------------------*/\r
\r
/* Nonmodal error box */\r
+LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,\r
+ WPARAM wParam, LPARAM lParam);\r
+\r
+VOID\r
+ErrorPopUp(char *title, char *content)\r
+{\r
+ FARPROC lpProc;\r
+ char *p, *q;\r
+ BOOLEAN modal = hwndMain == NULL;\r
+\r
+ p = content;\r
+ q = errorMessage;\r
+ while (*p) {\r
+ if (*p == '\n') {\r
+ if (modal) {\r
+ *q++ = ' ';\r
+ p++;\r
+ } else {\r
+ *q++ = '\r';\r
+ *q++ = *p++;\r
+ }\r
+ } else {\r
+ *q++ = *p++;\r
+ }\r
+ }\r
+ *q = NULLCHAR;\r
+ strncpy(errorTitle, title, sizeof(errorTitle));\r
+ errorTitle[sizeof(errorTitle) - 1] = '\0';\r
+ \r
+ if (modal) {\r
+ MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);\r
+ } else {\r
+ lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);\r
+ CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),\r
+ hwndMain, (DLGPROC)lpProc);\r
+ FreeProcInstance(lpProc);\r
+ }\r
+}\r
+\r
VOID\r
ErrorPopDown()\r
{\r
switch (message) {\r
case WM_INITDIALOG:\r
GetWindowRect(hDlg, &rChild);\r
+
+ /*
SetWindowPos(hDlg, NULL, rChild.left,\r
rChild.top + boardRect.top - (rChild.bottom - rChild.top), \r
0, 0, SWP_NOZORDER|SWP_NOSIZE);\r
+ */
+
+ /*
+ [AS] It seems that the above code wants to move the dialog up in the "caption
+ area" of the main window, but it uses the dialog height as an hard-coded constant,
+ and it doesn't work when you resize the dialog.
+ For now, just give it a default position.
+ */
+ SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
+
errorDialog = hDlg;\r
+ SetWindowText(hDlg, errorTitle);\r
hwndText = GetDlgItem(hDlg, OPT_ErrorText);\r
SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);\r
return FALSE;\r
LRESULT CALLBACK\r
ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
{\r
+ static SnapData sd;
static HWND hText, hInput, hFocus;\r
InputSource *is = consoleInputSource;\r
RECT rect;\r
mmi->ptMinTrackSize.x = 100;\r
mmi->ptMinTrackSize.y = 100;\r
break;\r
- }\r
+
+ /* [AS] Snapping */
+ case WM_ENTERSIZEMOVE:
+ return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
+
+ case WM_SIZING:
+ return OnSizing( &sd, hDlg, wParam, lParam );
+
+ case WM_MOVING:
+ return OnMoving( &sd, hDlg, wParam, lParam );
+
+ case WM_EXITSIZEMOVE:
+ return OnExitSizeMove( &sd, hDlg, wParam, lParam );
+ }\r
+
return DefWindowProc(hDlg, message, wParam, lParam);\r
}\r
\r
{\r
int ok, err;\r
\r
+ /* [AS] */
+ if( count <= 0 ) {
+ if (appData.debugMode) {
+ fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
+ }
+
+ return ERROR_INVALID_USER_BUFFER;
+ }
+
ResetEvent(ovl->hEvent);\r
ovl->Offset = ovl->OffsetHigh = 0;\r
ok = ReadFile(hFile, buf, count, outCount, ovl);\r
return err;\r
}\r
\r
+/* [AS] If input is line by line and a line exceed the buffer size, force an error */
+void CheckForInputBufferFull( InputSource * is )
+{
+ if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
+ /* Look for end of line */
+ char * p = is->buf;
+
+ while( p < is->next && *p != '\n' ) {
+ p++;
+ }
+
+ if( p >= is->next ) {
+ if (appData.debugMode) {
+ fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
+ }
+
+ is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
+ is->count = (DWORD) -1;
+ is->next = is->buf;
+ }
+ }
+}
\r
DWORD\r
InputThread(LPVOID arg)\r
is->count = 0;\r
} else {\r
is->count = (DWORD) -1;\r
+ /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
+ break;
}\r
}\r
+
+ CheckForInputBufferFull( is );
+
SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
+
+ if( is->count == ((DWORD) -1) ) break; /* [AS] */
+
if (is->count <= 0) break; /* Quit on EOF or error */\r
}\r
+
CloseHandle(ovl.hEvent);\r
CloseHandle(is->hFile);\r
+
+ if (appData.debugMode) {
+ fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
+ }
+
return 0;\r
}\r
\r
is->count = (DWORD) -1;\r
}\r
}\r
+
+ CheckForInputBufferFull( is );
+
SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
+
+ if( is->count == ((DWORD) -1) ) break; /* [AS] */
+
if (is->count < 0) break; /* Quit on error */\r
}\r
CloseHandle(is->hFile);\r
}\r
}\r
SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
+
+ if( is->count == ((DWORD) -1) ) break; /* [AS] */
+
if (is->count <= 0) break; /* Quit on EOF or error */\r
}\r
return 0;\r
p = q;\r
}\r
}\r
+
/* Move any partial line to the start of the buffer */\r
q = is->buf;\r
while (p < is->next) {\r
*q++ = *p++;\r
}\r
is->next = q;\r
+
if (is->error != NO_ERROR || is->count == 0) {\r
/* Notify backend of the error. Note: If there was a partial\r
line at the end, it is not flushed through. */\r
VOID\r
DisplayError(char *str, int error)\r
{\r
- FARPROC lpProc;\r
char buf[MSG_SIZ*2], buf2[MSG_SIZ];\r
int len;\r
- char *p, *q;\r
\r
if (error == 0) {\r
strcpy(buf, str);\r
}\r
}\r
}\r
- p = buf;\r
- q = errorMessage;\r
- while (*p) {\r
- if (*p == '\n') {\r
- if (hwndMain != NULL /*!!?*/) {\r
- *q++ = '\r';\r
- *q++ = *p++;\r
- } else {\r
- *q++ = ' ';\r
- p++;\r
- }\r
- } else {\r
- *q++ = *p++;\r
- }\r
- }\r
- *q = NULLCHAR;\r
\r
- if (hwndMain == NULL) {\r
- MessageBox(NULL, errorMessage, "Error", MB_OK|MB_ICONEXCLAMATION);\r
- } else {\r
- lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);\r
- CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),\r
- hwndMain, (DLGPROC)lpProc);\r
- FreeProcInstance(lpProc);\r
- }\r
+ ErrorPopUp("Error", buf);\r
}\r
\r
\r
ClearHighlights();\r
DrawPosition(FALSE, NULL);\r
if (appData.popupMoveErrors) {\r
- DisplayError(str, 0);\r
+ ErrorPopUp("Error", str);\r
} else {\r
DisplayMessage(str, "");\r
moveErrorMessageUp = TRUE;\r
}\r
\r
\r
+VOID\r
+DisplayNote(char *str)\r
+{\r
+ ErrorPopUp("Note", str);\r
+}\r
+\r
+\r
typedef struct {\r
char *title, *question, *replyPrefix;\r
ProcRef pr;\r
FreeProcInstance(lpProc);\r
}\r
\r
+/* [AS] Pick FRC position */
+LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static int * lpIndexFRC;
+ BOOL index_is_ok;
+ char buf[16];
+
+ switch( message )
+ {
+ case WM_INITDIALOG:
+ lpIndexFRC = (int *) lParam;
+
+ CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
+
+ SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
+ SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
+ SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
+ SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
+
+ break;
+
+ case WM_COMMAND:
+ switch( LOWORD(wParam) ) {
+ case IDOK:
+ *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
+ EndDialog( hDlg, 0 );
+ return TRUE;
+ case IDCANCEL:
+ EndDialog( hDlg, 1 );
+ return TRUE;
+ case IDC_NFG_Edit:
+ if( HIWORD(wParam) == EN_CHANGE ) {
+ GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
+
+ EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
+ }
+ return TRUE;
+ case IDC_NFG_Random:
+ sprintf( buf, "%d", myrandom() % 960 );
+ SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
+ return TRUE;
+ }
+
+ break;
+ }
+
+ return FALSE;
+}
+
+int NewGameFRC()
+{
+ int result;
+ int index = appData.defaultFrcPosition;
+ FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
+
+ result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
+
+ if( result == 0 ) {
+ appData.defaultFrcPosition = index;
+ }
+
+ return result;
+}
+
+/* [AS] Game list options */
+typedef struct {
+ char id;
+ char * name;
+} GLT_Item;
+
+static GLT_Item GLT_ItemInfo[] = {
+ { GLT_EVENT, "Event" },
+ { GLT_SITE, "Site" },
+ { GLT_DATE, "Date" },
+ { GLT_ROUND, "Round" },
+ { GLT_PLAYERS, "Players" },
+ { GLT_RESULT, "Result" },
+ { GLT_WHITE_ELO, "White Rating" },
+ { GLT_BLACK_ELO, "Black Rating" },
+ { GLT_TIME_CONTROL,"Time Control" },
+ { GLT_VARIANT, "Variant" },
+ { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
+ { 0, 0 }
+};
+
+const char * GLT_FindItem( char id )
+{
+ const char * result = 0;
+
+ GLT_Item * list = GLT_ItemInfo;
+
+ while( list->id != 0 ) {
+ if( list->id == id ) {
+ result = list->name;
+ break;
+ }
+
+ list++;
+ }
+
+ return result;
+}
+
+void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
+{
+ const char * name = GLT_FindItem( id );
+
+ if( name != 0 ) {
+ if( index >= 0 ) {
+ SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
+ }
+ else {
+ SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
+ }
+ }
+}
+
+void GLT_TagsToList( HWND hDlg, char * tags )
+{
+ char * pc = tags;
+
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
+
+ while( *pc ) {
+ GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
+ pc++;
+ }
+
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
+
+ pc = GLT_ALL_TAGS;
+
+ while( *pc ) {
+ if( strchr( tags, *pc ) == 0 ) {
+ GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
+ }
+ pc++;
+ }
+
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
+}
+
+char GLT_ListItemToTag( HWND hDlg, int index )
+{
+ char result = '\0';
+ char name[128];
+
+ GLT_Item * list = GLT_ItemInfo;
+
+ if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
+ while( list->id != 0 ) {
+ if( strcmp( list->name, name ) == 0 ) {
+ result = list->id;
+ break;
+ }
+
+ list++;
+ }
+ }
+
+ return result;
+}
+
+void GLT_MoveSelection( HWND hDlg, int delta )
+{
+ int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
+ int idx2 = idx1 + delta;
+ int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
+
+ if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
+ char buf[128];
+
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
+ }
+}
+
+LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static char glt[64];
+ static char * lpUserGLT;
+
+ switch( message )
+ {
+ case WM_INITDIALOG:
+ lpUserGLT = (char *) lParam;
+
+ strcpy( glt, lpUserGLT );
+
+ CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
+
+ /* Initialize list */
+ GLT_TagsToList( hDlg, glt );
+
+ SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
+
+ break;
+
+ case WM_COMMAND:
+ switch( LOWORD(wParam) ) {
+ case IDOK:
+ {
+ char * pc = lpUserGLT;
+ int idx = 0;
+ int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
+ char id;
+
+ do {
+ id = GLT_ListItemToTag( hDlg, idx );
+
+ *pc++ = id;
+ idx++;
+ } while( id != '\0' );
+ }
+ EndDialog( hDlg, 0 );
+ return TRUE;
+ case IDCANCEL:
+ EndDialog( hDlg, 1 );
+ return TRUE;
+
+ case IDC_GLT_Default:
+ strcpy( glt, GLT_DEFAULT_TAGS );
+ GLT_TagsToList( hDlg, glt );
+ return TRUE;
+
+ case IDC_GLT_Restore:
+ strcpy( glt, lpUserGLT );
+ GLT_TagsToList( hDlg, glt );
+ return TRUE;
+
+ case IDC_GLT_Up:
+ GLT_MoveSelection( hDlg, -1 );
+ return TRUE;
+
+ case IDC_GLT_Down:
+ GLT_MoveSelection( hDlg, +1 );
+ return TRUE;
+ }
+
+ break;
+ }
+
+ return FALSE;
+}
+
+int GameListOptions()
+{
+ char glt[64];
+ int result;
+ FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
+
+ strcpy( glt, appData.gameListTags );
+
+ result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
+
+ if( result == 0 ) {
+ /* [AS] Memory leak here! */
+ appData.gameListTags = strdup( glt );
+ }
+
+ return result;
+}
+
\r
VOID\r
DisplayIcsInteractionTitle(char *str)\r
we could arrange for this even though neither WinBoard\r
nor the chess program uses a console for stdio? */\r
/*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/\r
+
+ /* [AS] Special termination modes for misbehaving programs... */
+ if( signal == 9 ) {
+ if ( appData.debugMode) {
+ fprintf( debugFP, "Terminating process %u\n", cp->pid );
+ }
+
+ TerminateProcess( cp->hProcess, 0 );
+ }
+ else if( signal == 10 ) {
+ DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
+
+ if( dw != WAIT_OBJECT_0 ) {
+ if ( appData.debugMode) {
+ fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
+ }
+
+ TerminateProcess( cp->hProcess, 0 );
+ }
+ }
+
CloseHandle(cp->hProcess);\r
break;\r
\r
AddInputSource(ProcRef pr, int lineByLine,\r
InputCallback func, VOIDSTAR closure)\r
{\r
- InputSource *is, *is2;\r
+ InputSource *is, *is2 = NULL;
ChildProc *cp = (ChildProc *) pr;\r
\r
is = (InputSource *) calloc(1, sizeof(InputSource));\r
consoleInputSource = is;\r
} else {\r
is->kind = cp->kind;\r
+ /*
+ [AS] Try to avoid a race condition if the thread is given control too early:
+ we create all threads suspended so that the is->hThread variable can be
+ safely assigned, then let the threads start with ResumeThread.
+ */
switch (cp->kind) {\r
case CPReal:\r
is->hFile = cp->hFrom;\r
cp->hFrom = NULL; /* now owned by InputThread */\r
is->hThread =\r
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,\r
- (LPVOID) is, 0, &is->id);\r
+ (LPVOID) is, CREATE_SUSPENDED, &is->id);
break;\r
\r
case CPComm:\r
cp->hFrom = NULL; /* now owned by InputThread */\r
is->hThread =\r
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,\r
- (LPVOID) is, 0, &is->id);\r
+ (LPVOID) is, CREATE_SUSPENDED, &is->id);
break;\r
\r
case CPSock:\r
is->sock = cp->sock;\r
is->hThread =\r
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
- (LPVOID) is, 0, &is->id);\r
+ (LPVOID) is, CREATE_SUSPENDED, &is->id);
break;\r
\r
case CPRcmd:\r
is2->second = is2;\r
is->hThread =\r
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
- (LPVOID) is, 0, &is->id);\r
+ (LPVOID) is, CREATE_SUSPENDED, &is->id);
is2->hThread =\r
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
- (LPVOID) is2, 0, &is2->id);\r
+ (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
break;\r
}\r
+
+ if( is->hThread != NULL ) {
+ ResumeThread( is->hThread );
}\r
+
+ if( is2 != NULL && is2->hThread != NULL ) {
+ ResumeThread( is2->hThread );
+ }
+ }
+
return (InputSourceRef) is;\r
}\r
\r
FARPROC lpProc;\r
char *p, *q;\r
\r
+ /* [AS] */
+ EngineOutputPopUp();
+ return;
+
if (str == NULL) str = "";\r
p = (char *) malloc(2 * strlen(str) + 2);\r
q = p;\r
}\r
\r
void\r
-HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current)\r
-{\r
- /* Currently not implemented in WinBoard */\r
-}\r
-\r
-\r
+HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
+{\r
+#if 0
+ char buf[256];
+\r
+ sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
+ first, last, current, current >= 0 ? movelist[current] : "n/a" );
+\r
+ OutputDebugString( buf );
+#endif
+
+ MoveHistorySet( movelist, first, last, current, pvInfoList );
+
+ EvalGraphSet( first, last, current, pvInfoList );
+}
+
+void SetProgramStats( FrontEndProgramStats * stats )
+{
+#if 0
+ char buf[1024];
+
+ sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
+ stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
+
+ OutputDebugString( buf );
+#endif
+
+ EngineOutputUpdate( stats );
+}