-/*
- * WinBoard.c -- Windows NT front end to XBoard
- * $Id$
- *
- * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
- * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
- *
- * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
- * which was written and is copyrighted by Wayne Christopher.
- *
- * The following terms apply to Digital Equipment Corporation's copyright
- * interest in XBoard:
- * ------------------------------------------------------------------------
- * All Rights Reserved
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appear in all copies and that
- * both that copyright notice and this permission notice appear in
- * supporting documentation, and that the name of Digital not be
- * used in advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission.
- *
- * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
- * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
- * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- * ------------------------------------------------------------------------
- *
- * The following terms apply to the enhanced version of XBoard distributed
- * by the Free Software Foundation:
- * ------------------------------------------------------------------------
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * ------------------------------------------------------------------------
- */
-
-#include "config.h"
-
-#include <windows.h>
-#include <winuser.h>
-#include <winsock.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <malloc.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <math.h>
-#include <commdlg.h>
-#include <dlgs.h>
-#include <richedit.h>
-#include <mmsystem.h>
-
-#if __GNUC__
-#include <errno.h>
-#include <string.h>
-#endif
-
-#include "common.h"
-#include "winboard.h"
-#include "frontend.h"
-#include "backend.h"
-#include "moves.h"
-#include "wclipbrd.h"
-#include "wgamelist.h"
-#include "wedittags.h"
-#include "woptions.h"
-#include "wsockerr.h"
-#include "defaults.h"
-
-typedef struct {
- ChessSquare piece;
- POINT pos; /* window coordinates of current pos */
- POINT lastpos; /* window coordinates of last pos - used for clipping */
- POINT from; /* board coordinates of the piece's orig pos */
- POINT to; /* board coordinates of the piece's new pos */
-} AnimInfo;
-
-static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
-
-typedef struct {
- POINT start; /* window coordinates of start pos */
- POINT pos; /* window coordinates of current pos */
- POINT lastpos; /* window coordinates of last pos - used for clipping */
- POINT from; /* board coordinates of the piece's orig pos */
-} DragInfo;
-
-static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
-
-typedef struct {
- POINT sq[2]; /* board coordinates of from, to squares */
-} HighlightInfo;
-
-static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
-static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
-
-/* Window class names */
-char szAppName[] = "WinBoard";
-char szConsoleName[] = "WBConsole";
-
-/* Title bar text */
-char szTitle[] = "WinBoard";
-char szConsoleTitle[] = "ICS Interaction";
-
-char *programName;
-char *settingsFileName;
-BOOLEAN saveSettingsOnExit;
-char installDir[MSG_SIZ];
-
-BoardSize boardSize;
-BOOLEAN chessProgram;
-static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
-static int squareSize, lineGap;
-static int winWidth, winHeight;
-static RECT messageRect, whiteRect, blackRect;
-static char messageText[MESSAGE_TEXT_MAX];
-static int clockTimerEvent = 0;
-static int loadGameTimerEvent = 0;
-static int analysisTimerEvent = 0;
-static DelayedEventCallback delayedTimerCallback;
-static int delayedTimerEvent = 0;
-static int buttonCount = 2;
-char *icsTextMenuString;
-char *icsNames;
-char *firstChessProgramNames;
-char *secondChessProgramNames;
-
-#define ARG_MAX 20000
-
-#define PALETTESIZE 256
-
-HINSTANCE hInst; /* current instance */
-HWND hwndMain = NULL; /* root window*/
-HWND hwndConsole = NULL;
-BOOLEAN alwaysOnTop = FALSE;
-RECT boardRect;
-COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
- blackPieceColor, highlightSquareColor, premoveHighlightColor;
-HPALETTE hPal;
-ColorClass currentColorClass;
-
-HWND hCommPort = NULL; /* currently open comm port */
-static HWND hwndPause; /* pause button */
-static HBITMAP pieceBitmap[3][(int) WhiteKing + 1];
-static HBRUSH lightSquareBrush, darkSquareBrush,
- whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
-static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
-static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
-static HPEN gridPen = NULL;
-static HPEN highlightPen = NULL;
-static HPEN premovePen = NULL;
-static NPLOGPALETTE pLogPal;
-static BOOL paletteChanged = FALSE;
-static HICON iconWhite, iconBlack, iconCurrent;
-static int doingSizing = FALSE;
-static int lastSizing = 0;
-static int prevStderrPort;
-
-#if __GNUC__ && !defined(_winmajor)
-#define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
-#else
-#define oldDialog (_winmajor < 4)
-#endif
-
-char *defaultTextAttribs[] =
-{
- COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
- COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
- COLOR_NONE
-};
-
-typedef struct {
- char *name;
- int squareSize;
- int lineGap;
- int smallLayout;
- int tinyLayout;
- int cliWidth, cliHeight;
-} SizeInfo;
-
-SizeInfo sizeInfo[] =
-{
- { "tiny", 21, 0, 1, 1, 0, 0 },
- { "teeny", 25, 1, 1, 1, 0, 0 },
- { "dinky", 29, 1, 1, 1, 0, 0 },
- { "petite", 33, 1, 1, 1, 0, 0 },
- { "slim", 37, 2, 1, 0, 0, 0 },
- { "small", 40, 2, 1, 0, 0, 0 },
- { "mediocre", 45, 2, 1, 0, 0, 0 },
- { "middling", 49, 2, 0, 0, 0, 0 },
- { "average", 54, 2, 0, 0, 0, 0 },
- { "moderate", 58, 3, 0, 0, 0, 0 },
- { "medium", 64, 3, 0, 0, 0, 0 },
- { "bulky", 72, 3, 0, 0, 0, 0 },
- { "large", 80, 3, 0, 0, 0, 0 },
- { "big", 87, 3, 0, 0, 0, 0 },
- { "huge", 95, 3, 0, 0, 0, 0 },
- { "giant", 108, 3, 0, 0, 0, 0 },
- { "colossal", 116, 4, 0, 0, 0, 0 },
- { "titanic", 129, 4, 0, 0, 0, 0 },
- { NULL, 0, 0, 0, 0, 0, 0 }
-};
-
-#define MF(x) {x, {0, }, {0, }, 0}
-MyFont fontRec[NUM_SIZES][NUM_FONTS] =
-{
- { 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(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY),
- MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY),
- MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY) },
- { 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(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE),
- MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE),
- MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE) },
- { 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(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL),
- MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL),
- MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL) },
- { 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(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING),
- MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING),
- MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING) },
- { 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(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE),
- MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE),
- MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE) },
- { 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(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY),
- MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY),
- MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY) },
- { 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(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG),
- MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG),
- MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG) },
- { 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(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT),
- MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT),
- MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT) },
- { 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(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC),
- MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC),
- MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC) },
-};
-
-MyFont *font[NUM_SIZES][NUM_FONTS];
-
-typedef struct {
- char *label;
- int id;
- HWND hwnd;
- WNDPROC wndproc;
-} MyButtonDesc;
-
-#define BUTTON_WIDTH (tinyLayout ? 16 : 32)
-#define N_BUTTONS 5
-
-MyButtonDesc buttonDesc[N_BUTTONS] =
-{
- {"<<", IDM_ToStart, NULL, NULL},
- {"<", IDM_Backward, NULL, NULL},
- {"P", IDM_Pause, NULL, NULL},
- {">", IDM_Forward, NULL, NULL},
- {">>", IDM_ToEnd, NULL, NULL},
-};
-
-int tinyLayout = 0, smallLayout = 0;
-#define MENU_BAR_ITEMS 6
-char *menuBarText[2][MENU_BAR_ITEMS+1] = {
- { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
- { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
-};
-
-
-MySound sounds[(int)NSoundClasses];
-MyTextAttribs textAttribs[(int)NColorClasses];
-
-MyColorizeAttribs colorizeAttribs[] = {
- { (COLORREF)0, 0, "Shout Text" },
- { (COLORREF)0, 0, "SShout/CShout" },
- { (COLORREF)0, 0, "Channel 1 Text" },
- { (COLORREF)0, 0, "Channel Text" },
- { (COLORREF)0, 0, "Kibitz Text" },
- { (COLORREF)0, 0, "Tell Text" },
- { (COLORREF)0, 0, "Challenge Text" },
- { (COLORREF)0, 0, "Request Text" },
- { (COLORREF)0, 0, "Seek Text" },
- { (COLORREF)0, 0, "Normal Text" },
- { (COLORREF)0, 0, "None" }
-};
-
-
-
-static char *commentTitle;
-static char *commentText;
-static int commentIndex;
-static Boolean editComment = FALSE;
-HWND commentDialog = NULL;
-BOOLEAN commentDialogUp = FALSE;
-static int commentX, commentY, commentH, commentW;
-
-static char *analysisTitle;
-static char *analysisText;
-HWND analysisDialog = NULL;
-BOOLEAN analysisDialogUp = FALSE;
-static int analysisX, analysisY, analysisH, analysisW;
-
-char errorTitle[MSG_SIZ];
-char errorMessage[2*MSG_SIZ];
-HWND errorDialog = NULL;
-BOOLEAN moveErrorMessageUp = FALSE;
-BOOLEAN consoleEcho = TRUE;
-CHARFORMAT consoleCF;
-COLORREF consoleBackgroundColor;
-
-char *programVersion;
-
-#define CPReal 1
-#define CPComm 2
-#define CPSock 3
-#define CPRcmd 4
-typedef int CPKind;
-
-typedef struct {
- CPKind kind;
- HANDLE hProcess;
- DWORD pid;
- HANDLE hTo;
- HANDLE hFrom;
- SOCKET sock;
- SOCKET sock2; /* stderr socket for OpenRcmd */
-} ChildProc;
-
-#define INPUT_SOURCE_BUF_SIZE 4096
-
-typedef struct _InputSource {
- CPKind kind;
- HANDLE hFile;
- SOCKET sock;
- int lineByLine;
- HANDLE hThread;
- DWORD id;
- char buf[INPUT_SOURCE_BUF_SIZE];
- char *next;
- DWORD count;
- int error;
- InputCallback func;
- struct _InputSource *second; /* for stderr thread on CPRcmd */
- VOIDSTAR closure;
-} InputSource;
-
-InputSource *consoleInputSource;
-
-DCB dcb;
-
-/* forward */
-VOID ConsoleOutput(char* data, int length, int forceVisible);
-VOID ConsoleCreate();
-LRESULT CALLBACK
- ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
-VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
-VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
-VOID ParseCommSettings(char *arg, DCB *dcb);
-LRESULT CALLBACK
- StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
-VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
-void ParseIcsTextMenu(char *icsTextMenuString);
-VOID PopUpMoveDialog(char firstchar);
-VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
-
-/*
- * Setting "frozen" should disable all user input other than deleting
- * the window. We do this while engines are initializing themselves.
- */
-static int frozen = 0;
-static int oldMenuItemState[MENU_BAR_ITEMS];
-void FreezeUI()
-{
- HMENU hmenu;
- int i;
-
- if (frozen) return;
- frozen = 1;
- hmenu = GetMenu(hwndMain);
- for (i=0; i<MENU_BAR_ITEMS; i++) {
- oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
- }
- DrawMenuBar(hwndMain);
-}
-
-/* Undo a FreezeUI */
-void ThawUI()
-{
- HMENU hmenu;
- int i;
-
- if (!frozen) return;
- frozen = 0;
- hmenu = GetMenu(hwndMain);
- for (i=0; i<MENU_BAR_ITEMS; i++) {
- EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
- }
- DrawMenuBar(hwndMain);
-}
-
-/*---------------------------------------------------------------------------*\
- *
- * WinMain
- *
-\*---------------------------------------------------------------------------*/
-
-int APIENTRY
-WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
- LPSTR lpCmdLine, int nCmdShow)
-{
- MSG msg;
- HANDLE hAccelMain, hAccelNoAlt;
-
- debugFP = stderr;
-
- LoadLibrary("RICHED32.DLL");
- consoleCF.cbSize = sizeof(CHARFORMAT);
-
- if (!InitApplication(hInstance)) {
- return (FALSE);
- }
- if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
- return (FALSE);
- }
-
- hAccelMain = LoadAccelerators (hInstance, szAppName);
- hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
-
- /* Acquire and dispatch messages until a WM_QUIT message is received. */
-
- while (GetMessage(&msg, /* message structure */
- NULL, /* handle of window receiving the message */
- 0, /* lowest message to examine */
- 0)) /* highest message to examine */
- {
- if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
- !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
- !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
- !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
- !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
- !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
- TranslateMessage(&msg); /* Translates virtual key codes */
- DispatchMessage(&msg); /* Dispatches message to window */
- }
- }
-
-
- return (msg.wParam); /* Returns the value from PostQuitMessage */
-}
-
-/*---------------------------------------------------------------------------*\
- *
- * Initialization functions
- *
-\*---------------------------------------------------------------------------*/
-
-BOOL
-InitApplication(HINSTANCE hInstance)
-{
- WNDCLASS wc;
-
- /* Fill in window class structure with parameters that describe the */
- /* main window. */
-
- wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
- wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
- wc.cbClsExtra = 0; /* No per-class extra data. */
- wc.cbWndExtra = 0; /* No per-window extra data. */
- wc.hInstance = hInstance; /* Owner of this class */
- wc.hIcon = LoadIcon(hInstance, "icon_white");
- wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
- wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
- wc.lpszMenuName = szAppName; /* Menu name from .RC */
- wc.lpszClassName = szAppName; /* Name to register as */
-
- /* Register the window class and return success/failure code. */
- if (!RegisterClass(&wc)) return FALSE;
-
- wc.style = CS_HREDRAW | CS_VREDRAW;
- wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = DLGWINDOWEXTRA;
- wc.hInstance = hInstance;
- wc.hIcon = LoadIcon(hInstance, "icon_white");
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = szConsoleName;
-
- if (!RegisterClass(&wc)) return FALSE;
- return TRUE;
-}
-
-
-/* Set by InitInstance, used by EnsureOnScreen */
-int screenHeight, screenWidth;
-
-void
-EnsureOnScreen(int *x, int *y)
-{
- /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
- if (*x > screenWidth - 32) *x = 0;
- if (*y > screenHeight - 32) *y = 0;
-}
-
-BOOL
-InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
-{
- HWND hwnd; /* Main window handle. */
- int ibs;
- WINDOWPLACEMENT wp;
- char *filepart;
-
- hInst = hInstance; /* Store instance handle in our global variable */
-
- if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
- *filepart = NULLCHAR;
- } else {
- GetCurrentDirectory(MSG_SIZ, installDir);
- }
- InitAppData(lpCmdLine); /* Get run-time parameters */
- if (appData.debugMode) {
- debugFP = fopen("winboard.debug", "w");
- setbuf(debugFP, NULL);
- }
-
- InitBackEnd1();
-
- /* Create a main window for this application instance. */
- hwnd = CreateWindow(szAppName, szTitle,
- (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
- CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
- NULL, NULL, hInstance, NULL);
- hwndMain = hwnd;
-
- /* If window could not be created, return "failure" */
- if (!hwnd) {
- return (FALSE);
- }
-
- iconWhite = LoadIcon(hInstance, "icon_white");
- iconBlack = LoadIcon(hInstance, "icon_black");
- iconCurrent = iconWhite;
- InitDrawingColors();
- screenHeight = GetSystemMetrics(SM_CYSCREEN);
- screenWidth = GetSystemMetrics(SM_CXSCREEN);
- for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
- /* Compute window size for each board size, and use the largest
- size that fits on this screen as the default. */
- InitDrawingSizes((BoardSize)ibs, 0);
- if (boardSize == (BoardSize)-1 &&
- winHeight <= screenHeight && winWidth <= screenWidth) {
- boardSize = (BoardSize)ibs;
- }
- }
- InitDrawingSizes(boardSize, 0);
- InitMenuChecks();
- buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
-
- InitBackEnd2();
-
- /* Make the window visible; update its client area; and return "success" */
- EnsureOnScreen(&boardX, &boardY);
- wp.length = sizeof(WINDOWPLACEMENT);
- wp.flags = 0;
- wp.showCmd = nCmdShow;
- wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
- wp.rcNormalPosition.left = boardX;
- wp.rcNormalPosition.right = boardX + winWidth;
- wp.rcNormalPosition.top = boardY;
- wp.rcNormalPosition.bottom = boardY + winHeight;
- SetWindowPlacement(hwndMain, &wp);
-
- SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
- 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
- if (hwndConsole) {
-#if AOT_CONSOLE
- SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
- 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
-#endif
- ShowWindow(hwndConsole, nCmdShow);
- }
- UpdateWindow(hwnd);
-
- return TRUE;
-
-}
-
-
-typedef enum {
- ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
- ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
- ArgSettingsFilename
-} ArgType;
-
-typedef struct {
- char *argName;
- ArgType argType;
- /***
- union {
- String *pString; // ArgString
- int *pInt; // ArgInt
- float *pFloat; // ArgFloat
- Boolean *pBoolean; // ArgBoolean
- COLORREF *pColor; // ArgColor
- ColorClass cc; // ArgAttribs
- String *pFilename; // ArgFilename
- BoardSize *pBoardSize; // ArgBoardSize
- int whichFont; // ArgFont
- DCB *pDCB; // ArgCommSettings
- String *pFilename; // ArgSettingsFilename
- } argLoc;
- ***/
- LPVOID argLoc;
- BOOL save;
-} ArgDescriptor;
-
-int junk;
-ArgDescriptor argDescriptors[] = {
- /* positional arguments */
- { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
- { "", ArgNone, NULL },
- /* keyword arguments */
- { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
- { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
- { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
- { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
- { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
- { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
- { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
- { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
- { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
- { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
- { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
- { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
- { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
- { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
- { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
- { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
- { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
- { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
- FALSE },
- { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
- FALSE },
- { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
- FALSE },
- { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
- { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
- FALSE },
- { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
- { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
- { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
- { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
- { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
- { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
- { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
- { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
- { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
- { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
- { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
- { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
- { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
- { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
- { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
- { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
- { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
- /*!!bitmapDirectory?*/
- { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
- { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
- { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
- { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
- { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
- { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
- { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
- { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
- { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
- { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
- { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
- { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
- { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
- { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
- { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
- { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
- { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
- { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
- { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
- { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
- { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
- { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
- { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
- { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
- { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
- { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
- { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
- { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
- { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
- { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
- { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
- { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
- { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
- { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
- { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
- { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
- { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
- { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
- { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
- { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
- { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
- { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
- { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
- { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
- { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
- { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
- { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
- { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
- { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
- { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
- { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
- { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
- { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
- { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
- { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
- { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
- { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
- { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
- { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
- { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
- { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
- { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
- { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
- { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
- { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
- { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
- { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
- { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
- { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
- { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
- { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
- { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
- { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
- { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
- { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
- { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
- { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
- { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
- { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
- { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
- { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
- { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
- { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
- { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
- { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
- { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
- { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
- { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
- { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
- { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
- { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
- { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
- { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
- { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
- FALSE }, /* only so that old WinBoard.ini files from betas can be read */
- { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
- { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
- { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
- { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
- { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
- { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
- { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
- TRUE }, /* must come after all fonts */
- { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
- { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
- FALSE }, /* historical; kept only so old winboard.ini files will parse */
- { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
- { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
- { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
- { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
- { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
- { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
- { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
- { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
- { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
- { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
- { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
- { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
- { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
- { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
- { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
- { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
- { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
- { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
- { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
- { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
- { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
- { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
- { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
- { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
- { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
- { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
- { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
- { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
-#if 0
- { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
- { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
-#endif
- { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
- { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
- { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
- { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
- { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
- { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
- { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
- { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
- { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
- { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
- { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
- { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
- { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
- { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
- { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
- { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
- { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
- { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
- { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
- { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
- { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
- { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
- { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
- { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
- { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
- { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
- { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
- { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
- { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
- { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
- { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
- { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
- { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
- { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
- { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
- { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
- { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
- { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
- { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
- { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
- { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
- { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
- { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
- { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
- { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
- { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
- { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
- { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
- { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
- { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
- { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
- { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
- { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
- { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
- { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
- { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
- { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
- { "highlightLastMove", ArgBoolean,
- (LPVOID) &appData.highlightLastMove, TRUE },
- { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
- { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
- { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
- { "highlightDragging", ArgBoolean,
- (LPVOID) &appData.highlightDragging, TRUE },
- { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
- { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
- { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
- { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
- { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
- { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
- { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
- { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
- { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
- { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
- { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
- { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
- { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
- { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
- { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
- { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
- { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
- { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
- { "soundShout", ArgFilename,
- (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
- { "soundSShout", ArgFilename,
- (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
- { "soundChannel1", ArgFilename,
- (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
- { "soundChannel", ArgFilename,
- (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
- { "soundKibitz", ArgFilename,
- (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
- { "soundTell", ArgFilename,
- (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
- { "soundChallenge", ArgFilename,
- (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
- { "soundRequest", ArgFilename,
- (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
- { "soundSeek", ArgFilename,
- (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
- { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
- { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
- { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
- { "soundIcsLoss", ArgFilename,
- (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
- { "soundIcsDraw", ArgFilename,
- (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
- { "soundIcsUnfinished", ArgFilename,
- (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
- { "soundIcsAlarm", ArgFilename,
- (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
- { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
- { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
- { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
- { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
- { "reuseChessPrograms", ArgBoolean,
- (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
- { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
- { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
- { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
- { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
- { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
- { "x", ArgInt, (LPVOID) &boardX, TRUE },
- { "y", ArgInt, (LPVOID) &boardY, TRUE },
- { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
- { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
- { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
- { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
- { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
- { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
- { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
- { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
- { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
- { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
- { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
- { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
- { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
- { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
- { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
- { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
- { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
- { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
- { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
- { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
- { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
- { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
- { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
- { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
- { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
- { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
- { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
- { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
- { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
- { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
- TRUE },
- { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
- TRUE },
- { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
- { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
- { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
- { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion,
- FALSE },
- { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,
- FALSE },
- { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
- { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
- { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
- { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
-#ifdef ZIPPY
- { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
- { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
- { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
- { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
- { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
- { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
- { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
- { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
- { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
- { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
- { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
- { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
- { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
- FALSE },
- { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
- { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
- { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
- { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
- { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
- { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
- { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
- FALSE },
- { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
- { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
- { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
- { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
- { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
- { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
- { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
- { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
- { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
- { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
- { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
- { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
- { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
- { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
- { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
- { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
- /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
- { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
-#endif
- { NULL, ArgNone, NULL, FALSE }
-};
-
-
-/* Kludge for indirection files on command line */
-char* lastIndirectionFilename;
-ArgDescriptor argDescriptorIndirection =
-{ "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
-
-
-VOID
-ExitArgError(char *msg, char *badArg)
-{
- char buf[MSG_SIZ];
-
- sprintf(buf, "%s %s", msg, badArg);
- DisplayFatalError(buf, 0, 2);
- exit(2);
-}
-
-/* Command line font name parser. NULL name means do nothing.
- Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
- For backward compatibility, syntax without the colon is also
- accepted, but font names with digits in them won't work in that case.
-*/
-VOID
-ParseFontName(char *name, MyFontParams *mfp)
-{
- char *p, *q;
- if (name == NULL) return;
- p = name;
- q = strchr(p, ':');
- if (q) {
- if (q - p >= sizeof(mfp->faceName))
- ExitArgError("Font name too long:", name);
- memcpy(mfp->faceName, p, q - p);
- mfp->faceName[q - p] = NULLCHAR;
- p = q + 1;
- } else {
- q = mfp->faceName;
- while (*p && !isdigit(*p)) {
- *q++ = *p++;
- if (q - mfp->faceName >= sizeof(mfp->faceName))
- ExitArgError("Font name too long:", name);
- }
- while (q > mfp->faceName && q[-1] == ' ') q--;
- *q = NULLCHAR;
- }
- if (!*p) ExitArgError("Font point size missing:", name);
- mfp->pointSize = (float) atof(p);
- mfp->bold = (strchr(p, 'b') != NULL);
- mfp->italic = (strchr(p, 'i') != NULL);
- mfp->underline = (strchr(p, 'u') != NULL);
- mfp->strikeout = (strchr(p, 's') != NULL);
-}
-
-/* Color name parser.
- X version accepts X color names, but this one
- handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
-COLORREF
-ParseColorName(char *name)
-{
- int red, green, blue, count;
- char buf[MSG_SIZ];
-
- count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
- if (count != 3) {
- count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
- &red, &green, &blue);
- }
- if (count != 3) {
- sprintf(buf, "Can't parse color name %s", name);
- DisplayError(buf, 0);
- return RGB(0, 0, 0);
- }
- return PALETTERGB(red, green, blue);
-}
-
-
-void ParseAttribs(COLORREF *color, int *effects, char* argValue)
-{
- char *e = argValue;
- int eff = 0;
-
- while (*e) {
- if (*e == 'b') eff |= CFE_BOLD;
- else if (*e == 'i') eff |= CFE_ITALIC;
- else if (*e == 'u') eff |= CFE_UNDERLINE;
- else if (*e == 's') eff |= CFE_STRIKEOUT;
- else if (*e == '#' || isdigit(*e)) break;
- e++;
- }
- *effects = eff;
- *color = ParseColorName(e);
-}
-
-
-BoardSize
-ParseBoardSize(char *name)
-{
- BoardSize bs = SizeTiny;
- while (sizeInfo[bs].name != NULL) {
- if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
- bs++;
- }
- ExitArgError("Unrecognized board size value", name);
- return bs; /* not reached */
-}
-
-
-char
-StringGet(void *getClosure)
-{
- char **p = (char **) getClosure;
- return *((*p)++);
-}
-
-char
-FileGet(void *getClosure)
-{
- int c;
- FILE* f = (FILE*) getClosure;
-
- c = getc(f);
- if (c == EOF)
- return NULLCHAR;
- else
- return (char) c;
-}
-
-/* Parse settings file named "name". If file found, return the
- full name in fullname and return TRUE; else return FALSE */
-BOOLEAN
-ParseSettingsFile(char *name, char fullname[MSG_SIZ])
-{
- char *dummy;
- FILE *f;
-
- if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
- f = fopen(fullname, "r");
- if (f != NULL) {
- ParseArgs(FileGet, f);
- fclose(f);
- return TRUE;
- }
- }
- return FALSE;
-}
-
-VOID
-ParseArgs(GetFunc get, void *cl)
-{
- char argName[ARG_MAX];
- char argValue[ARG_MAX];
- ArgDescriptor *ad;
- char start;
- char *q;
- int i, octval;
- char ch;
- int posarg = 0;
-
- ch = get(cl);
- for (;;) {
- while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
- if (ch == NULLCHAR) break;
- if (ch == ';') {
- /* Comment to end of line */
- ch = get(cl);
- while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
- continue;
- } else if (ch == '/' || ch == '-') {
- /* Switch */
- q = argName;
- while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
- ch != '\n' && ch != '\t') {
- *q++ = ch;
- ch = get(cl);
- }
- *q = NULLCHAR;
-
- for (ad = argDescriptors; ad->argName != NULL; ad++)
- if (strcmp(ad->argName, argName + 1) == 0) break;
-
- if (ad->argName == NULL)
- ExitArgError("Unrecognized argument", argName);
-
- } else if (ch == '@') {
- /* Indirection file */
- ad = &argDescriptorIndirection;
- ch = get(cl);
- } else {
- /* Positional argument */
- ad = &argDescriptors[posarg++];
- strcpy(argName, ad->argName);
- }
-
- if (ad->argType == ArgTrue) {
- *(Boolean *) ad->argLoc = TRUE;
- continue;
- }
- if (ad->argType == ArgFalse) {
- *(Boolean *) ad->argLoc = FALSE;
- continue;
- }
-
- while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
- if (ch == NULLCHAR || ch == '\n') {
- ExitArgError("No value provided for argument", argName);
- }
- q = argValue;
- if (ch == '{') {
- // Quoting with { }. No characters have to (or can) be escaped.
- // Thus the string cannot contain a '}' character.
- start = ch;
- ch = get(cl);
- while (start) {
- switch (ch) {
- case NULLCHAR:
- start = NULLCHAR;
- break;
-
- case '}':
- ch = get(cl);
- start = NULLCHAR;
- break;
-
- default:
- *q++ = ch;
- ch = get(cl);
- break;
- }
- }
- } else if (ch == '\'' || ch == '"') {
- // Quoting with ' ' or " ", with \ as escape character.
- // Inconvenient for long strings that may contain Windows filenames.
- start = ch;
- ch = get(cl);
- while (start) {
- switch (ch) {
- case NULLCHAR:
- start = NULLCHAR;
- break;
-
- default:
- not_special:
- *q++ = ch;
- ch = get(cl);
- break;
-
- case '\'':
- case '\"':
- if (ch == start) {
- ch = get(cl);
- start = NULLCHAR;
- break;
- } else {
- goto not_special;
- }
-
- case '\\':
- if (ad->argType == ArgFilename
- || ad->argType == ArgSettingsFilename) {
- goto not_special;
- }
- ch = get(cl);
- switch (ch) {
- case NULLCHAR:
- ExitArgError("Incomplete \\ escape in value for", argName);
- break;
- case 'n':
- *q++ = '\n';
- ch = get(cl);
- break;
- case 'r':
- *q++ = '\r';
- ch = get(cl);
- break;
- case 't':
- *q++ = '\t';
- ch = get(cl);
- break;
- case 'b':
- *q++ = '\b';
- ch = get(cl);
- break;
- case 'f':
- *q++ = '\f';
- ch = get(cl);
- break;
- default:
- octval = 0;
- for (i = 0; i < 3; i++) {
- if (ch >= '0' && ch <= '7') {
- octval = octval*8 + (ch - '0');
- ch = get(cl);
- } else {
- break;
- }
- }
- if (i > 0) {
- *q++ = (char) octval;
- } else {
- *q++ = ch;
- ch = get(cl);
- }
- break;
- }
- break;
- }
- }
- } else {
- while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
- *q++ = ch;
- ch = get(cl);
- }
- }
- *q = NULLCHAR;
-
- switch (ad->argType) {
- case ArgInt:
- *(int *) ad->argLoc = atoi(argValue);
- break;
-
- case ArgFloat:
- *(float *) ad->argLoc = (float) atof(argValue);
- break;
-
- case ArgString:
- case ArgFilename:
- *(char **) ad->argLoc = strdup(argValue);
- break;
-
- case ArgSettingsFilename:
- {
- char fullname[MSG_SIZ];
- if (ParseSettingsFile(argValue, fullname)) {
- if (ad->argLoc != NULL) {
- *(char **) ad->argLoc = strdup(fullname);
- }
- } else {
- if (ad->argLoc != NULL) {
- } else {
- ExitArgError("Failed to open indirection file", argValue);
- }
- }
- }
- break;
-
- case ArgBoolean:
- switch (argValue[0]) {
- case 't':
- case 'T':
- *(Boolean *) ad->argLoc = TRUE;
- break;
- case 'f':
- case 'F':
- *(Boolean *) ad->argLoc = FALSE;
- break;
- default:
- ExitArgError("Unrecognized boolean argument value", argValue);
- break;
- }
- break;
-
- case ArgColor:
- *(COLORREF *)ad->argLoc = ParseColorName(argValue);
- break;
-
- case ArgAttribs: {
- ColorClass cc = (ColorClass)ad->argLoc;
- ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
- }
- break;
-
- case ArgBoardSize:
- *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
- break;
-
- case ArgFont:
- ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
- break;
-
- case ArgCommSettings:
- ParseCommSettings(argValue, &dcb);
- break;
-
- case ArgNone:
- ExitArgError("Unrecognized argument", argValue);
- break;
- }
- }
-}
-
-VOID
-LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
-{
- HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
- lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
- DeleteDC(hdc);
- lf->lfWidth = 0;
- lf->lfEscapement = 0;
- lf->lfOrientation = 0;
- lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
- lf->lfItalic = mfp->italic;
- lf->lfUnderline = mfp->underline;
- lf->lfStrikeOut = mfp->strikeout;
- lf->lfCharSet = DEFAULT_CHARSET;
- lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
- lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
- lf->lfQuality = DEFAULT_QUALITY;
- lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
- strcpy(lf->lfFaceName, mfp->faceName);
-}
-
-VOID
-CreateFontInMF(MyFont *mf)
-{
- LFfromMFP(&mf->lf, &mf->mfp);
- if (mf->hf) DeleteObject(mf->hf);
- mf->hf = CreateFontIndirect(&mf->lf);
-}
-
-VOID
-SetDefaultTextAttribs()
-{
- ColorClass cc;
- for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
- ParseAttribs(&textAttribs[cc].color,
- &textAttribs[cc].effects,
- defaultTextAttribs[cc]);
- }
-}
-
-VOID
-SetDefaultSounds()
-{
- ColorClass cc;
- SoundClass sc;
- for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
- textAttribs[cc].sound.name = strdup("");
- textAttribs[cc].sound.data = NULL;
- }
- for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
- sounds[sc].name = strdup("");
- sounds[sc].data = NULL;
- }
- sounds[(int)SoundBell].name = strdup(SOUND_BELL);
-}
-
-VOID
-LoadAllSounds()
-{
- ColorClass cc;
- SoundClass sc;
- for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
- MyLoadSound(&textAttribs[cc].sound);
- }
- for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
- MyLoadSound(&sounds[sc]);
- }
-}
-
-VOID
-InitAppData(LPSTR lpCmdLine)
-{
- int i, j;
- char buf[ARG_MAX], currDir[MSG_SIZ];
- char *dummy, *p;
-
- programName = szAppName;
-
- /* Initialize to defaults */
- lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
- darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
- whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
- blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
- highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
- premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
- consoleBackgroundColor = ParseColorName(COLOR_BKGD);
- SetDefaultTextAttribs();
- SetDefaultSounds();
- appData.movesPerSession = MOVES_PER_SESSION;
- appData.initString = INIT_STRING;
- appData.secondInitString = INIT_STRING;
- appData.firstComputerString = COMPUTER_STRING;
- appData.secondComputerString = COMPUTER_STRING;
- appData.firstChessProgram = FIRST_CHESS_PROGRAM;
- appData.secondChessProgram = SECOND_CHESS_PROGRAM;
- appData.firstPlaysBlack = FALSE;
- appData.noChessProgram = FALSE;
- chessProgram = FALSE;
- appData.firstHost = FIRST_HOST;
- appData.secondHost = SECOND_HOST;
- appData.firstDirectory = FIRST_DIRECTORY;
- appData.secondDirectory = SECOND_DIRECTORY;
- appData.bitmapDirectory = "";
- appData.remoteShell = REMOTE_SHELL;
- appData.remoteUser = "";
- appData.timeDelay = TIME_DELAY;
- appData.timeControl = TIME_CONTROL;
- appData.timeIncrement = TIME_INCREMENT;
- appData.icsActive = FALSE;
- appData.icsHost = "";
- appData.icsPort = ICS_PORT;
- appData.icsCommPort = ICS_COMM_PORT;
- appData.icsLogon = ICS_LOGON;
- appData.icsHelper = "";
- appData.useTelnet = FALSE;
- appData.telnetProgram = TELNET_PROGRAM;
- appData.gateway = "";
- appData.loadGameFile = "";
- appData.loadGameIndex = 0;
- appData.saveGameFile = "";
- appData.autoSaveGames = FALSE;
- appData.loadPositionFile = "";
- appData.loadPositionIndex = 1;
- appData.savePositionFile = "";
- appData.matchMode = FALSE;
- appData.matchGames = 0;
- appData.monoMode = FALSE;
- appData.debugMode = FALSE;
- appData.clockMode = TRUE;
- boardSize = (BoardSize) -1; /* determine by screen size */
- appData.Iconic = FALSE; /*unused*/
- appData.searchTime = "";
- appData.searchDepth = 0;
- appData.showCoords = FALSE;
- appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
- appData.autoCallFlag = FALSE;
- appData.flipView = FALSE;
- appData.autoFlipView = TRUE;
- appData.cmailGameName = "";
- appData.alwaysPromoteToQueen = FALSE;
- appData.oldSaveStyle = FALSE;
- appData.quietPlay = FALSE;
- appData.showThinking = FALSE;
- appData.ponderNextMove = TRUE;
- appData.periodicUpdates = TRUE;
- appData.popupExitMessage = TRUE;
- appData.popupMoveErrors = FALSE;
- appData.autoObserve = FALSE;
- appData.autoComment = FALSE;
- appData.animate = TRUE;
- appData.animSpeed = 10;
- appData.animateDragging = TRUE;
- appData.highlightLastMove = TRUE;
- appData.getMoveList = TRUE;
- appData.testLegality = TRUE;
- appData.premove = TRUE;
- appData.premoveWhite = FALSE;
- appData.premoveWhiteText = "";
- appData.premoveBlack = FALSE;
- appData.premoveBlackText = "";
- appData.icsAlarm = TRUE;
- appData.icsAlarmTime = 5000;
- appData.autoRaiseBoard = TRUE;
- appData.localLineEditing = TRUE;
- appData.colorize = TRUE;
- appData.reuseFirst = TRUE;
- appData.reuseSecond = TRUE;
- appData.blindfold = FALSE;
- appData.icsEngineAnalyze = FALSE;
- dcb.DCBlength = sizeof(DCB);
- dcb.BaudRate = 9600;
- dcb.fBinary = TRUE;
- dcb.fParity = FALSE;
- dcb.fOutxCtsFlow = FALSE;
- dcb.fOutxDsrFlow = FALSE;
- dcb.fDtrControl = DTR_CONTROL_ENABLE;
- dcb.fDsrSensitivity = FALSE;
- dcb.fTXContinueOnXoff = TRUE;
- dcb.fOutX = FALSE;
- dcb.fInX = FALSE;
- dcb.fNull = FALSE;
- dcb.fRtsControl = RTS_CONTROL_ENABLE;
- dcb.fAbortOnError = FALSE;
- /* Microsoft SDK >= Feb. 2003 (MS VS >= 2002) */
- #if (defined(_MSC_VER) && _MSC_VER <= 1200)
- //dcb.wReserved = 0;
- #else
- dcb.wReserved = 0;
- #endif
- dcb.ByteSize = 7;
- dcb.Parity = SPACEPARITY;
- dcb.StopBits = ONESTOPBIT;
- settingsFileName = SETTINGS_FILE;
- saveSettingsOnExit = TRUE;
- boardX = CW_USEDEFAULT;
- boardY = CW_USEDEFAULT;
- consoleX = CW_USEDEFAULT;
- consoleY = CW_USEDEFAULT;
- consoleW = CW_USEDEFAULT;
- consoleH = CW_USEDEFAULT;
- analysisX = CW_USEDEFAULT;
- analysisY = CW_USEDEFAULT;
- analysisW = CW_USEDEFAULT;
- analysisH = CW_USEDEFAULT;
- commentX = CW_USEDEFAULT;
- commentY = CW_USEDEFAULT;
- commentW = CW_USEDEFAULT;
- commentH = CW_USEDEFAULT;
- editTagsX = CW_USEDEFAULT;
- editTagsY = CW_USEDEFAULT;
- editTagsW = CW_USEDEFAULT;
- editTagsH = CW_USEDEFAULT;
- gameListX = CW_USEDEFAULT;
- gameListY = CW_USEDEFAULT;
- gameListW = CW_USEDEFAULT;
- gameListH = CW_USEDEFAULT;
- icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
- icsNames = ICS_NAMES;
- firstChessProgramNames = FCP_NAMES;
- secondChessProgramNames = SCP_NAMES;
- appData.initialMode = "";
- appData.variant = "normal";
- appData.firstProtocolVersion = PROTOVER;
- appData.secondProtocolVersion = PROTOVER;
- appData.showButtonBar = TRUE;
-#ifdef ZIPPY
- appData.zippyTalk = ZIPPY_TALK;
- appData.zippyPlay = ZIPPY_PLAY;
- appData.zippyLines = ZIPPY_LINES;
- appData.zippyPinhead = ZIPPY_PINHEAD;
- appData.zippyPassword = ZIPPY_PASSWORD;
- appData.zippyPassword2 = ZIPPY_PASSWORD2;
- appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
- appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
- appData.zippyUseI = ZIPPY_USE_I;
- appData.zippyBughouse = ZIPPY_BUGHOUSE;
- appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
- appData.zippyGameEnd = ZIPPY_GAME_END;
- appData.zippyGameStart = ZIPPY_GAME_START;
- appData.zippyAdjourn = ZIPPY_ADJOURN;
- appData.zippyAbort = ZIPPY_ABORT;
- appData.zippyVariants = ZIPPY_VARIANTS;
- appData.zippyMaxGames = ZIPPY_MAX_GAMES;
- appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
-#endif
-
- /* Point font array elements to structures and
- parse default font names */
- for (i=0; i<NUM_FONTS; i++) {
- for (j=0; j<NUM_SIZES; j++) {
- font[j][i] = &fontRec[j][i];
- ParseFontName(font[j][i]->def, &font[j][i]->mfp);
- }
- }
-
- /* Parse default settings file if any */
- if (ParseSettingsFile(settingsFileName, buf)) {
- settingsFileName = strdup(buf);
- }
-
- /* Parse command line */
- ParseArgs(StringGet, &lpCmdLine);
-
- /* Propagate options that affect others */
- if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
- if (appData.icsActive || appData.noChessProgram) {
- chessProgram = FALSE; /* not local chess program mode */
- }
-
- /* Open startup dialog if needed */
- if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
- (appData.icsActive && *appData.icsHost == NULLCHAR) ||
- (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
- *appData.secondChessProgram == NULLCHAR))) {
- FARPROC lpProc;
-
- lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
- DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
- FreeProcInstance(lpProc);
- }
-
- /* Make sure save files land in the right (?) directory */
- if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
- appData.saveGameFile = strdup(buf);
- }
- if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
- appData.savePositionFile = strdup(buf);
- }
-
- /* Finish initialization for fonts and sounds */
- for (i=0; i<NUM_FONTS; i++) {
- for (j=0; j<NUM_SIZES; j++) {
- CreateFontInMF(font[j][i]);
- }
- }
- /* xboard, and older WinBoards, controlled the move sound with the
- appData.ringBellAfterMoves option. In the current WinBoard, we
- always turn the option on (so that the backend will call us),
- then let the user turn the sound off by setting it to silence if
- desired. To accommodate old winboard.ini files saved by old
- versions of WinBoard, we also turn off the sound if the option
- was initially set to false. */
- if (!appData.ringBellAfterMoves) {
- sounds[(int)SoundMove].name = strdup("");
- appData.ringBellAfterMoves = TRUE;
- }
- GetCurrentDirectory(MSG_SIZ, currDir);
- SetCurrentDirectory(installDir);
- LoadAllSounds();
- SetCurrentDirectory(currDir);
-
- p = icsTextMenuString;
- if (p[0] == '@') {
- FILE* f = fopen(p + 1, "r");
- if (f == NULL) {
- DisplayFatalError(p + 1, errno, 2);
- return;
- }
- i = fread(buf, 1, sizeof(buf)-1, f);
- fclose(f);
- buf[i] = NULLCHAR;
- p = buf;
- }
- ParseIcsTextMenu(strdup(p));
-}
-
-
-VOID
-InitMenuChecks()
-{
- HMENU hmenu = GetMenu(hwndMain);
-
- (void) EnableMenuItem(hmenu, IDM_CommPort,
- MF_BYCOMMAND|((appData.icsActive &&
- *appData.icsCommPort != NULLCHAR) ?
- MF_ENABLED : MF_GRAYED));
- (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
- MF_BYCOMMAND|(saveSettingsOnExit ?
- MF_CHECKED : MF_UNCHECKED));
-}
-
-
-VOID
-SaveSettings(char* name)
-{
- FILE *f;
- ArgDescriptor *ad;
- WINDOWPLACEMENT wp;
- char dir[MSG_SIZ];
-
- if (!hwndMain) return;
-
- GetCurrentDirectory(MSG_SIZ, dir);
- SetCurrentDirectory(installDir);
- f = fopen(name, "w");
- SetCurrentDirectory(dir);
- if (f == NULL) {
- DisplayError(name, errno);
- return;
- }
- fprintf(f, ";\n");
- fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
- fprintf(f, ";\n");
- fprintf(f, "; You can edit the values of options that are already set in this file,\n");
- fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
- fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
- fprintf(f, ";\n");
-
- wp.length = sizeof(WINDOWPLACEMENT);
- GetWindowPlacement(hwndMain, &wp);
- boardX = wp.rcNormalPosition.left;
- boardY = wp.rcNormalPosition.top;
-
- if (hwndConsole) {
- GetWindowPlacement(hwndConsole, &wp);
- consoleX = wp.rcNormalPosition.left;
- consoleY = wp.rcNormalPosition.top;
- consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
- consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
- }
-
- if (analysisDialog) {
- GetWindowPlacement(analysisDialog, &wp);
- analysisX = wp.rcNormalPosition.left;
- analysisY = wp.rcNormalPosition.top;
- analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
- analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
- }
-
- if (commentDialog) {
- GetWindowPlacement(commentDialog, &wp);
- commentX = wp.rcNormalPosition.left;
- commentY = wp.rcNormalPosition.top;
- commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
- commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
- }
-
- if (editTagsDialog) {
- GetWindowPlacement(editTagsDialog, &wp);
- editTagsX = wp.rcNormalPosition.left;
- editTagsY = wp.rcNormalPosition.top;
- editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
- editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
- }
-
- if (gameListDialog) {
- GetWindowPlacement(gameListDialog, &wp);
- gameListX = wp.rcNormalPosition.left;
- gameListY = wp.rcNormalPosition.top;
- gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
- gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
- }
-
- for (ad = argDescriptors; ad->argName != NULL; ad++) {
- if (!ad->save) continue;
- switch (ad->argType) {
- case ArgString:
- {
- char *p = *(char **)ad->argLoc;
- if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
- /* Quote multiline values or \-containing values
- with { } if possible */
- fprintf(f, "/%s={%s}\n", ad->argName, p);
- } else {
- /* Else quote with " " */
- fprintf(f, "/%s=\"", ad->argName);
- while (*p) {
- if (*p == '\n') fprintf(f, "\n");
- else if (*p == '\r') fprintf(f, "\\r");
- else if (*p == '\t') fprintf(f, "\\t");
- else if (*p == '\b') fprintf(f, "\\b");
- else if (*p == '\f') fprintf(f, "\\f");
- else if (*p < ' ') fprintf(f, "\\%03o", *p);
- else if (*p == '\"') fprintf(f, "\\\"");
- else if (*p == '\\') fprintf(f, "\\\\");
- else putc(*p, f);
- p++;
- }
- fprintf(f, "\"\n");
- }
- }
- break;
- case ArgInt:
- fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
- break;
- case ArgFloat:
- fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
- break;
- case ArgBoolean:
- fprintf(f, "/%s=%s\n", ad->argName,
- (*(Boolean *)ad->argLoc) ? "true" : "false");
- break;
- case ArgTrue:
- if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
- break;
- case ArgFalse:
- if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
- break;
- case ArgColor:
- {
- COLORREF color = *(COLORREF *)ad->argLoc;
- fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
- color&0xff, (color>>8)&0xff, (color>>16)&0xff);
- }
- break;
- case ArgAttribs:
- {
- MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
- fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
- (ta->effects & CFE_BOLD) ? "b" : "",
- (ta->effects & CFE_ITALIC) ? "i" : "",
- (ta->effects & CFE_UNDERLINE) ? "u" : "",
- (ta->effects & CFE_STRIKEOUT) ? "s" : "",
- (ta->effects) ? " " : "",
- ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
- }
- break;
- case ArgFilename:
- if (strchr(*(char **)ad->argLoc, '\"')) {
- fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
- } else {
- fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
- }
- break;
- case ArgBoardSize:
- fprintf(f, "/%s=%s\n", ad->argName,
- sizeInfo[*(BoardSize *)ad->argLoc].name);
- break;
- case ArgFont:
- {
- int bs;
- for (bs=0; bs<NUM_SIZES; bs++) {
- MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
- fprintf(f, "/size=%s ", sizeInfo[bs].name);
- fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
- ad->argName, mfp->faceName, mfp->pointSize,
- mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
- mfp->bold ? "b" : "",
- mfp->italic ? "i" : "",
- mfp->underline ? "u" : "",
- mfp->strikeout ? "s" : "");
- }
- }
- break;
- case ArgCommSettings:
- PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
- }
- }
- fclose(f);
-}
-
-
-
-/*---------------------------------------------------------------------------*\
- *
- * GDI board drawing routines
- *
-\*---------------------------------------------------------------------------*/
-
-HBITMAP
-DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
-{
- char name[128];
-
- sprintf(name, "%s%d%s", piece, squareSize, suffix);
- if (gameInfo.event &&
- strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
- strcmp(name, "k80s") == 0) {
- strcpy(name, "tim");
- }
- return LoadBitmap(hinst, name);
-}
-
-
-/* Insert a color into the program's logical palette
- structure. This code assumes the given color is
- the result of the RGB or PALETTERGB macro, and it
- knows how those macros work (which is documented).
-*/
-VOID
-InsertInPalette(COLORREF color)
-{
- LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
-
- if (pLogPal->palNumEntries++ >= PALETTESIZE) {
- DisplayFatalError("Too many colors", 0, 1);
- pLogPal->palNumEntries--;
- return;
- }
-
- pe->peFlags = (char) 0;
- pe->peRed = (char) (0xFF & color);
- pe->peGreen = (char) (0xFF & (color >> 8));
- pe->peBlue = (char) (0xFF & (color >> 16));
- return;
-}
-
-
-VOID
-InitDrawingColors()
-{
- if (pLogPal == NULL) {
- /* Allocate enough memory for a logical palette with
- * PALETTESIZE entries and set the size and version fields
- * of the logical palette structure.
- */
- pLogPal = (NPLOGPALETTE)
- LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
- (sizeof(PALETTEENTRY) * (PALETTESIZE))));
- pLogPal->palVersion = 0x300;
- }
- pLogPal->palNumEntries = 0;
-
- InsertInPalette(lightSquareColor);
- InsertInPalette(darkSquareColor);
- InsertInPalette(whitePieceColor);
- InsertInPalette(blackPieceColor);
- InsertInPalette(highlightSquareColor);
- InsertInPalette(premoveHighlightColor);
-
- /* create a logical color palette according the information
- * in the LOGPALETTE structure.
- */
- hPal = CreatePalette((LPLOGPALETTE) pLogPal);
-
- lightSquareBrush = CreateSolidBrush(lightSquareColor);
- darkSquareBrush = CreateSolidBrush(darkSquareColor);
- whitePieceBrush = CreateSolidBrush(whitePieceColor);
- blackPieceBrush = CreateSolidBrush(blackPieceColor);
- iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
-}
-
-
-int
-BoardWidth(int boardSize)
-{
- return (BOARD_SIZE + 1) * sizeInfo[boardSize].lineGap +
- BOARD_SIZE * sizeInfo[boardSize].squareSize;
-}
-
-/* Respond to board resize by dragging edge */
-VOID
-ResizeBoard(int newSizeX, int newSizeY, int flags)
-{
- BoardSize newSize = NUM_SIZES - 1;
- static int recurse = 0;
- if (IsIconic(hwndMain)) return;
- if (recurse > 0) return;
- recurse++;
- while (newSize > 0 &&
- (newSizeX < sizeInfo[newSize].cliWidth ||
- newSizeY < sizeInfo[newSize].cliHeight)) {
- newSize--;
- }
- boardSize = newSize;
- InitDrawingSizes(boardSize, flags);
- recurse--;
-}
-
-
-
-VOID
-InitDrawingSizes(BoardSize boardSize, int flags)
-{
- int i, boardWidth;
- ChessSquare piece;
- static int oldBoardSize = -1, oldTinyLayout = 0;
- HDC hdc;
- SIZE clockSize, messageSize;
- HFONT oldFont;
- char buf[MSG_SIZ];
- char *str;
- HMENU hmenu = GetMenu(hwndMain);
- RECT crect, wrect;
- int offby;
- LOGBRUSH logbrush;
-
- tinyLayout = sizeInfo[boardSize].tinyLayout;
- smallLayout = sizeInfo[boardSize].smallLayout;
- squareSize = sizeInfo[boardSize].squareSize;
- lineGap = sizeInfo[boardSize].lineGap;
-
- if (tinyLayout != oldTinyLayout) {
- long style = GetWindowLong(hwndMain, GWL_STYLE);
- if (tinyLayout) {
- style &= ~WS_SYSMENU;
- InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
- "&Minimize\tCtrl+F4");
- } else {
- style |= WS_SYSMENU;
- RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
- }
- SetWindowLong(hwndMain, GWL_STYLE, style);
-
- for (i=0; menuBarText[tinyLayout][i]; i++) {
- ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
- (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
- }
- DrawMenuBar(hwndMain);
- }
-
- boardWidth = BoardWidth(boardSize);
-
- /* Get text area sizes */
- hdc = GetDC(hwndMain);
- if (appData.clockMode) {
- sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
- } else {
- sprintf(buf, "White");
- }
- oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
- GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
- SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
- str = "We only care about the height here";
- GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
- SelectObject(hdc, oldFont);
- ReleaseDC(hwndMain, hdc);
-
- /* Compute where everything goes */
- whiteRect.left = OUTER_MARGIN;
- whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
- whiteRect.top = OUTER_MARGIN;
- whiteRect.bottom = whiteRect.top + clockSize.cy;
-
- blackRect.left = whiteRect.right + INNER_MARGIN;
- blackRect.right = blackRect.left + boardWidth/2 - 1;
- blackRect.top = whiteRect.top;
- blackRect.bottom = whiteRect.bottom;
-
- messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
- if (appData.showButtonBar) {
- messageRect.right = blackRect.right
- - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
- } else {
- messageRect.right = blackRect.right;
- }
- messageRect.top = whiteRect.bottom + INNER_MARGIN;
- messageRect.bottom = messageRect.top + messageSize.cy;
-
- boardRect.left = whiteRect.left;
- boardRect.right = boardRect.left + boardWidth;
- boardRect.top = messageRect.bottom + INNER_MARGIN;
- boardRect.bottom = boardRect.top + boardWidth;
-
- sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
- sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
- winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
- winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
- GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
- GetWindowRect(hwndMain, &wrect);
- SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
- SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
- /* compensate if menu bar wrapped */
- GetClientRect(hwndMain, &crect);
- offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
- winHeight += offby;
- switch (flags) {
- case WMSZ_TOPLEFT:
- SetWindowPos(hwndMain, NULL,
- wrect.right - winWidth, wrect.bottom - winHeight,
- winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
- break;
-
- case WMSZ_TOPRIGHT:
- case WMSZ_TOP:
- SetWindowPos(hwndMain, NULL,
- wrect.left, wrect.bottom - winHeight,
- winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
- break;
-
- case WMSZ_BOTTOMLEFT:
- case WMSZ_LEFT:
- SetWindowPos(hwndMain, NULL,
- wrect.right - winWidth, wrect.top,
- winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
- break;
-
- case WMSZ_BOTTOMRIGHT:
- case WMSZ_BOTTOM:
- case WMSZ_RIGHT:
- default:
- SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
- SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
- break;
- }
-
- hwndPause = NULL;
- for (i = 0; i < N_BUTTONS; i++) {
- if (buttonDesc[i].hwnd != NULL) {
- DestroyWindow(buttonDesc[i].hwnd);
- buttonDesc[i].hwnd = NULL;
- }
- if (appData.showButtonBar) {
- buttonDesc[i].hwnd =
- CreateWindow("BUTTON", buttonDesc[i].label,
- WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
- boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
- messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
- (HMENU) buttonDesc[i].id,
- (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
- if (tinyLayout) {
- SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
- (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
- MAKELPARAM(FALSE, 0));
- }
- if (buttonDesc[i].id == IDM_Pause)
- hwndPause = buttonDesc[i].hwnd;
- buttonDesc[i].wndproc = (WNDPROC)
- SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
- }
- }
- if (gridPen != NULL) DeleteObject(gridPen);
- if (highlightPen != NULL) DeleteObject(highlightPen);
- if (premovePen != NULL) DeleteObject(premovePen);
- if (lineGap != 0) {
- logbrush.lbStyle = BS_SOLID;
- logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
- gridPen =
- ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
- lineGap, &logbrush, 0, NULL);
- logbrush.lbColor = highlightSquareColor;
- highlightPen =
- ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
- lineGap, &logbrush, 0, NULL);
-
- logbrush.lbColor = premoveHighlightColor;
- premovePen =
- ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
- lineGap, &logbrush, 0, NULL);
-
- for (i = 0; i < BOARD_SIZE + 1; i++) {
- gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
- gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2;
- gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
- boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
- gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
- BOARD_SIZE * (squareSize + lineGap);
- gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x =
- gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left +
- lineGap / 2 + (i * (squareSize + lineGap));
- gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y =
- boardRect.top + BOARD_SIZE * (squareSize + lineGap);
- gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
- }
- }
-
- if (boardSize == oldBoardSize) return;
- oldBoardSize = boardSize;
- oldTinyLayout = tinyLayout;
-
- /* Load piece bitmaps for this board size */
- for (i=0; i<=2; i++) {
- for (piece = WhitePawn;
- (int) piece <= (int) WhiteKing;
- piece = (ChessSquare) ((int) piece + 1)) {
- if (pieceBitmap[i][piece] != NULL)
- DeleteObject(pieceBitmap[i][piece]);
- }
- }
-
- pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
- pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
- pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
- pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
- pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
- pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
- pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
- pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
- pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
- pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
- pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
- pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
- pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
- pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
- pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
- pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
- pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
- pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
-
-}
-
-HBITMAP
-PieceBitmap(ChessSquare p, int kind)
-{
- if ((int) p >= (int) BlackPawn)
- p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
-
- return pieceBitmap[kind][(int) p];
-}
-
-/***************************************************************/
-
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
-/*
-#define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
-#define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
-*/
-
-VOID
-SquareToPos(int row, int column, int * x, int * y)
-{
- if (flipView) {
- *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
- *y = boardRect.top + lineGap + row * (squareSize + lineGap);
- } else {
- *x = boardRect.left + lineGap + column * (squareSize + lineGap);
- *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
- }
-}
-
-VOID
-DrawCoordsOnDC(HDC hdc)
-{
- static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'};
- static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'};
- char str[2] = { NULLCHAR, NULLCHAR };
- int oldMode, oldAlign, x, y, start, i;
- HFONT oldFont;
- HBRUSH oldBrush;
-
- if (!appData.showCoords)
- return;
-
- start = flipView ? 0 : 8;
-
- oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
- oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
- oldAlign = GetTextAlign(hdc);
- oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
-
- y = boardRect.top + lineGap;
- x = boardRect.left + lineGap;
-
- SetTextAlign(hdc, TA_LEFT|TA_TOP);
- for (i = 0; i < 8; i++) {
- str[0] = files[start + i];
- ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
- y += squareSize + lineGap;
- }
-
- SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
- for (i = 0; i < 8; i++) {
- str[0] = ranks[start + i];
- ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
- x += squareSize + lineGap;
- }
-
- SelectObject(hdc, oldBrush);
- SetBkMode(hdc, oldMode);
- SetTextAlign(hdc, oldAlign);
- SelectObject(hdc, oldFont);
-}
-
-VOID
-DrawGridOnDC(HDC hdc)
-{
- HPEN oldPen;
-
- if (lineGap != 0) {
- oldPen = SelectObject(hdc, gridPen);
- PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2);
- SelectObject(hdc, oldPen);
- }
-}
-
-#define HIGHLIGHT_PEN 0
-#define PREMOVE_PEN 1
-
-VOID
-DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
-{
- int x1, y1;
- HPEN oldPen, hPen;
- if (lineGap == 0) return;
- if (flipView) {
- x1 = boardRect.left +
- lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap);
- y1 = boardRect.top +
- lineGap/2 + y * (squareSize + lineGap);
- } else {
- x1 = boardRect.left +
- lineGap/2 + x * (squareSize + lineGap);
- y1 = boardRect.top +
- lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap);
- }
- hPen = pen ? premovePen : highlightPen;
- oldPen = SelectObject(hdc, on ? hPen : gridPen);
- MoveToEx(hdc, x1, y1, NULL);
- LineTo(hdc, x1 + squareSize + lineGap, y1);
- LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
- LineTo(hdc, x1, y1 + squareSize + lineGap);
- LineTo(hdc, x1, y1);
- SelectObject(hdc, oldPen);
-}
-
-VOID
-DrawHighlightsOnDC(HDC hdc)
-{
- int i;
- for (i=0; i<2; i++) {
- if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
- DrawHighlightOnDC(hdc, TRUE,
- highlightInfo.sq[i].x, highlightInfo.sq[i].y,
- HIGHLIGHT_PEN);
- }
- for (i=0; i<2; i++) {
- if (premoveHighlightInfo.sq[i].x >= 0 &&
- premoveHighlightInfo.sq[i].y >= 0) {
- DrawHighlightOnDC(hdc, TRUE,
- premoveHighlightInfo.sq[i].x,
- premoveHighlightInfo.sq[i].y,
- PREMOVE_PEN);
- }
- }
-}
-
-/* Note: sqcolor is used only in monoMode */
-/* Note that this code is largely duplicated in woptions.c,
- function DrawSampleSquare, so that needs to be updated too */
-VOID
-DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
-{
- HBITMAP oldBitmap;
- HBRUSH oldBrush;
-
- if (appData.blindfold) return;
-
- if (appData.monoMode) {
- SelectObject(tmphdc, PieceBitmap(piece,
- color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
- BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
- sqcolor ? SRCCOPY : NOTSRCCOPY);
- } else {
- if (color) {
- oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
- oldBrush = SelectObject(hdc, whitePieceBrush);
- BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
-#if 0
- /* Use black piece color for outline of white pieces */
- /* Not sure this looks really good (though xboard does it).
- Maybe better to have another selectable color, default black */
- SelectObject(hdc, blackPieceBrush); /* could have own brush */
- SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
- BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
-#else
- /* Use black for outline of white pieces */
- SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
- BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
-#endif
- } else {
-#if 0
- /* Use white piece color for details of black pieces */
- /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
- WHITE_PIECE ones aren't always the right shape. */
- /* Not sure this looks really good (though xboard does it).
- Maybe better to have another selectable color, default medium gray? */
- oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
- oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
- BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
- SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
- SelectObject(hdc, blackPieceBrush);
- BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
-#else
- /* Use square color for details of black pieces */
- oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
- oldBrush = SelectObject(hdc, blackPieceBrush);
- BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
-#endif
- }
- SelectObject(hdc, oldBrush);
- SelectObject(tmphdc, oldBitmap);
- }
-}
-
-VOID
-DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
-{
- int row, column, x, y, square_color, piece_color;
- ChessSquare piece;
- HBRUSH oldBrush;
-
- for (row = 0; row < BOARD_SIZE; row++) {
- for (column = 0; column < BOARD_SIZE; column++) {
-
- SquareToPos(row, column, &x, &y);
-
- piece = board[row][column];
-
- square_color = ((column + row) % 2) == 1;
- piece_color = (int) piece < (int) BlackPawn;
-
- if (appData.monoMode) {
- if (piece == EmptySquare) {
- BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
- square_color ? WHITENESS : BLACKNESS);
- } else {
- DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
- }
- } else {
- oldBrush = SelectObject(hdc, square_color ?
- lightSquareBrush : darkSquareBrush);
- BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
- SelectObject(hdc, oldBrush);
- if (piece != EmptySquare)
- DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
- }
- }
- }
-}
-
-#define MAX_CLIPS 200 /* more than enough */
-
-VOID
-HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
-{
- static Board lastReq, lastDrawn;
- static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
- static int lastDrawnFlipView = 0;
- static int lastReqValid = 0, lastDrawnValid = 0;
- int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
- HDC tmphdc;
- HDC hdcmem;
- HBITMAP bufferBitmap;
- HBITMAP oldBitmap;
- RECT Rect;
- HRGN clips[MAX_CLIPS];
- ChessSquare dragged_piece = EmptySquare;
-
- /* I'm undecided on this - this function figures out whether a full
- * repaint is necessary on its own, so there's no real reason to have the
- * caller tell it that. I think this can safely be set to FALSE - but
- * if we trust the callers not to request full repaints unnessesarily, then
- * we could skip some clipping work. In other words, only request a full
- * redraw when the majority of pieces have changed positions (ie. flip,
- * gamestart and similar) --Hawk
- */
- Boolean fullrepaint = repaint;
-
- if (board == NULL) {
- if (!lastReqValid) {
- return;
- }
- board = lastReq;
- } else {
- CopyBoard(lastReq, board);
- lastReqValid = 1;
- }
-
- if (doingSizing) {
- return;
- }
-
- if (IsIconic(hwndMain)) {
- return;
- }
-
- if (hdc == NULL) {
- hdc = GetDC(hwndMain);
- if (!appData.monoMode) {
- SelectPalette(hdc, hPal, FALSE);
- RealizePalette(hdc);
- }
- releaseDC = TRUE;
- } else {
- releaseDC = FALSE;
- }
-
-#if 0
- fprintf(debugFP, "*******************************\n"
- "repaint = %s\n"
- "dragInfo.from (%d,%d)\n"
- "dragInfo.start (%d,%d)\n"
- "dragInfo.pos (%d,%d)\n"
- "dragInfo.lastpos (%d,%d)\n",
- repaint ? "TRUE" : "FALSE",
- dragInfo.from.x, dragInfo.from.y,
- dragInfo.start.x, dragInfo.start.y,
- dragInfo.pos.x, dragInfo.pos.y,
- dragInfo.lastpos.x, dragInfo.lastpos.y);
- fprintf(debugFP, "prev: ");
- for (row = 0; row < 8; row++) {
- for (column = 0; column < 8; column++) {
- fprintf(debugFP, "%d ", lastDrawn[row][column]);
- }
- }
- fprintf(debugFP, "\n");
- fprintf(debugFP, "board: ");
- for (row = 0; row < 8; row++) {
- for (column = 0; column < 8; column++) {
- fprintf(debugFP, "%d ", board[row][column]);
- }
- }
- fprintf(debugFP, "\n");
- fflush(debugFP);
-#endif
-
- /* Create some work-DCs */
- hdcmem = CreateCompatibleDC(hdc);
- tmphdc = CreateCompatibleDC(hdc);
-
- /* Figure out which squares need updating by comparing the
- * newest board with the last drawn board and checking if
- * flipping has changed.
- */
- if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
- for (row = 0; row < 8; row++) {
- for (column = 0; column < 8; column++) {
- if (lastDrawn[row][column] != board[row][column]) {
- SquareToPos(row, column, &x, &y);
- clips[num_clips++] =
- CreateRectRgn(x, y, x + squareSize, y + squareSize);
- }
- }
- }
- for (i=0; i<2; i++) {
- if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
- lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
- if (lastDrawnHighlight.sq[i].x >= 0 &&
- lastDrawnHighlight.sq[i].y >= 0) {
- SquareToPos(lastDrawnHighlight.sq[i].y,
- lastDrawnHighlight.sq[i].x, &x, &y);
- clips[num_clips++] =
- CreateRectRgn(x - lineGap, y - lineGap,
- x + squareSize + lineGap, y + squareSize + lineGap);
- }
- if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
- SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
- clips[num_clips++] =
- CreateRectRgn(x - lineGap, y - lineGap,
- x + squareSize + lineGap, y + squareSize + lineGap);
- }
- }
- }
- for (i=0; i<2; i++) {
- if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
- lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
- if (lastDrawnPremove.sq[i].x >= 0 &&
- lastDrawnPremove.sq[i].y >= 0) {
- SquareToPos(lastDrawnPremove.sq[i].y,
- lastDrawnPremove.sq[i].x, &x, &y);
- clips[num_clips++] =
- CreateRectRgn(x - lineGap, y - lineGap,
- x + squareSize + lineGap, y + squareSize + lineGap);
- }
- if (premoveHighlightInfo.sq[i].x >= 0 &&
- premoveHighlightInfo.sq[i].y >= 0) {
- SquareToPos(premoveHighlightInfo.sq[i].y,
- premoveHighlightInfo.sq[i].x, &x, &y);
- clips[num_clips++] =
- CreateRectRgn(x - lineGap, y - lineGap,
- x + squareSize + lineGap, y + squareSize + lineGap);
- }
- }
- }
- } else {
- fullrepaint = TRUE;
- }
-
- /* Create a buffer bitmap - this is the actual bitmap
- * being written to. When all the work is done, we can
- * copy it to the real DC (the screen). This avoids
- * the problems with flickering.
- */
- GetClientRect(hwndMain, &Rect);
- bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
- Rect.bottom-Rect.top+1);
- oldBitmap = SelectObject(hdcmem, bufferBitmap);
- if (!appData.monoMode) {
- SelectPalette(hdcmem, hPal, FALSE);
- }
-
- /* Create clips for dragging */
- if (!fullrepaint) {
- if (dragInfo.from.x >= 0) {
- SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
- clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
- }
- if (dragInfo.start.x >= 0) {
- SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
- clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
- }
- if (dragInfo.pos.x >= 0) {
- x = dragInfo.pos.x - squareSize / 2;
- y = dragInfo.pos.y - squareSize / 2;
- clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
- }
- if (dragInfo.lastpos.x >= 0) {
- x = dragInfo.lastpos.x - squareSize / 2;
- y = dragInfo.lastpos.y - squareSize / 2;
- clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
- }
- }
-
- /* If dragging is in progress, we temporarely remove the piece */
- if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
- dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
- board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
- }
-
- /* Are we animating a move?
- * If so,
- * - remove the piece from the board (temporarely)
- * - calculate the clipping region
- */
- if (!fullrepaint) {
- if (animInfo.piece != EmptySquare) {
- board[animInfo.from.y][animInfo.from.x] = EmptySquare;
- x = boardRect.left + animInfo.lastpos.x;
- y = boardRect.top + animInfo.lastpos.y;
- x2 = boardRect.left + animInfo.pos.x;
- y2 = boardRect.top + animInfo.pos.y;
- clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
- /* Slight kludge. The real problem is that after AnimateMove is
- done, the position on the screen does not match lastDrawn.
- This currently causes trouble only on e.p. captures in
- atomic, where the piece moves to an empty square and then
- explodes. The old and new positions both had an empty square
- at the destination, but animation has drawn a piece there and
- we have to remember to erase it. */
- lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
- }
- }
-
- /* No clips? Make sure we have fullrepaint set to TRUE */
- if (num_clips == 0)
- fullrepaint = TRUE;
-
- /* Set clipping on the memory DC */
- if (!fullrepaint) {
- SelectClipRgn(hdcmem, clips[0]);
- for (x = 1; x < num_clips; x++) {
- if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
- abort(); // this should never ever happen!
- }
- }
-
- /* Do all the drawing to the memory DC */
- DrawGridOnDC(hdcmem);
- DrawHighlightsOnDC(hdcmem);
- DrawBoardOnDC(hdcmem, board, tmphdc);
- DrawCoordsOnDC(hdcmem);
-
- /* Put the dragged piece back into place and draw it */
- if (dragged_piece != EmptySquare) {
- board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
- x = dragInfo.pos.x - squareSize / 2;
- y = dragInfo.pos.y - squareSize / 2;
- DrawPieceOnDC(hdcmem, dragged_piece,
- ((int) dragged_piece < (int) BlackPawn),
- (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
- }
-
- /* Put the animated piece back into place and draw it */
- if (animInfo.piece != EmptySquare) {
- board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
- x = boardRect.left + animInfo.pos.x;
- y = boardRect.top + animInfo.pos.y;
- DrawPieceOnDC(hdcmem, animInfo.piece,
- ((int) animInfo.piece < (int) BlackPawn),
- (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
- }
-
- /* Release the bufferBitmap by selecting in the old bitmap
- * and delete the memory DC
- */
- SelectObject(hdcmem, oldBitmap);
- DeleteDC(hdcmem);
-
- /* Set clipping on the target DC */
- if (!fullrepaint) {
- SelectClipRgn(hdc, clips[0]);
- for (x = 1; x < num_clips; x++) {
- if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
- abort(); // this should never ever happen!
- }
- }
-
- /* Copy the new bitmap onto the screen in one go.
- * This way we avoid any flickering
- */
- oldBitmap = SelectObject(tmphdc, bufferBitmap);
- BitBlt(hdc, boardRect.left, boardRect.top,
- boardRect.right - boardRect.left,
- boardRect.bottom - boardRect.top,
- tmphdc, boardRect.left, boardRect.top, SRCCOPY);
- SelectObject(tmphdc, oldBitmap);
-
- /* Massive cleanup */
- for (x = 0; x < num_clips; x++)
- DeleteObject(clips[x]);
-
- DeleteDC(tmphdc);
- DeleteObject(bufferBitmap);
-
- if (releaseDC)
- ReleaseDC(hwndMain, hdc);
-
- if (lastDrawnFlipView != flipView) {
- if (flipView)
- CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
- else
- CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
- }
-
- CopyBoard(lastDrawn, board);
- lastDrawnHighlight = highlightInfo;
- lastDrawnPremove = premoveHighlightInfo;
- lastDrawnFlipView = flipView;
- lastDrawnValid = 1;
-}
-
-
-/*---------------------------------------------------------------------------*\
-| CLIENT PAINT PROCEDURE
-| This is the main event-handler for the WM_PAINT message.
-|
-\*---------------------------------------------------------------------------*/
-VOID
-PaintProc(HWND hwnd)
-{
- HDC hdc;
- PAINTSTRUCT ps;
- HFONT oldFont;
-
- if(hdc = BeginPaint(hwnd, &ps)) {
- if (IsIconic(hwnd)) {
- DrawIcon(hdc, 2, 2, iconCurrent);
- } else {
- if (!appData.monoMode) {
- SelectPalette(hdc, hPal, FALSE);
- RealizePalette(hdc);
- }
- HDCDrawPosition(hdc, 1, NULL);
- oldFont =
- SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
- ExtTextOut(hdc, messageRect.left, messageRect.top,
- ETO_CLIPPED|ETO_OPAQUE,
- &messageRect, messageText, strlen(messageText), NULL);
- SelectObject(hdc, oldFont);
- DisplayBothClocks();
- }
- EndPaint(hwnd,&ps);
- }
-
- return;
-}
-
-
-/*
- * If the user selects on a border boundary, return -1; if off the board,
- * return -2. Otherwise map the event coordinate to the square.
- * The offset boardRect.left or boardRect.top must already have been
- * subtracted from x.
- */
-int
-EventToSquare(int x)
-{
- if (x <= 0)
- return -2;
- if (x < lineGap)
- return -1;
- x -= lineGap;
- if ((x % (squareSize + lineGap)) >= squareSize)
- return -1;
- x /= (squareSize + lineGap);
- if (x >= BOARD_SIZE)
- return -2;
- return x;
-}
-
-typedef struct {
- char piece;
- int command;
- char* name;
-} DropEnable;
-
-DropEnable dropEnables[] = {
- { 'P', DP_Pawn, "Pawn" },
- { 'N', DP_Knight, "Knight" },
- { 'B', DP_Bishop, "Bishop" },
- { 'R', DP_Rook, "Rook" },
- { 'Q', DP_Queen, "Queen" },
-};
-
-VOID
-SetupDropMenu(HMENU hmenu)
-{
- int i, count, enable;
- char *p;
- extern char white_holding[], black_holding[];
- char item[MSG_SIZ];
-
- for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
- p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
- dropEnables[i].piece);
- count = 0;
- while (p && *p++ == dropEnables[i].piece) count++;
- sprintf(item, "%s %d", dropEnables[i].name, count);
- enable = count > 0 || !appData.testLegality
- /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
- && !appData.icsActive);
- ModifyMenu(hmenu, dropEnables[i].command,
- MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
- dropEnables[i].command, item);
- }
-}
-
-static int fromX = -1, fromY = -1, toX, toY;
-
-/* Event handler for mouse messages */
-VOID
-MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- int x, y;
- POINT pt;
- static int recursive = 0;
- HMENU hmenu;
- BOOLEAN saveAnimate;
- static BOOLEAN sameAgain = FALSE;
-
- if (recursive) {
- if (message == WM_MBUTTONUP) {
- /* Hideous kludge to fool TrackPopupMenu into paying attention
- to the middle button: we simulate pressing the left button too!
- */
- PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
- PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
- }
- return;
- }
- recursive++;
-
- pt.x = LOWORD(lParam);
- pt.y = HIWORD(lParam);
- x = EventToSquare(pt.x - boardRect.left);
- y = EventToSquare(pt.y - boardRect.top);
- if (!flipView && y >= 0) {
- y = BOARD_SIZE - 1 - y;
- }
- if (flipView && x >= 0) {
- x = BOARD_SIZE - 1 - x;
- }
-
- switch (message) {
- case WM_LBUTTONDOWN:
- ErrorPopDown();
- sameAgain = FALSE;
- if (y == -2) {
- /* Downclick vertically off board; check if on clock */
- if (PtInRect((LPRECT) &whiteRect, pt)) {
- if (gameMode == EditPosition) {
- SetWhiteToPlayEvent();
- } else if (gameMode == IcsPlayingBlack ||
- gameMode == MachinePlaysWhite) {
- CallFlagEvent();
- }
- } else if (PtInRect((LPRECT) &blackRect, pt)) {
- if (gameMode == EditPosition) {
- SetBlackToPlayEvent();
- } else if (gameMode == IcsPlayingWhite ||
- gameMode == MachinePlaysBlack) {
- CallFlagEvent();
- }
- }
- if (!appData.highlightLastMove) {
- ClearHighlights();
- DrawPosition(FALSE, NULL);
- }
- fromX = fromY = -1;
- dragInfo.start.x = dragInfo.start.y = -1;
- dragInfo.from = dragInfo.start;
- break;
- } else if (x < 0 || y < 0) {
- break;
- } else if (fromX == x && fromY == y) {
- /* Downclick on same square again */
- ClearHighlights();
- DrawPosition(FALSE, NULL);
- sameAgain = TRUE;
- } else if (fromX != -1) {
- /* Downclick on different square */
- ChessSquare pdown, pup;
- pdown = boards[currentMove][fromY][fromX];
- pup = boards[currentMove][y][x];
- if (gameMode == EditPosition ||
- !((WhitePawn <= pdown && pdown <= WhiteKing &&
- WhitePawn <= pup && pup <= WhiteKing) ||
- (BlackPawn <= pdown && pdown <= BlackKing &&
- BlackPawn <= pup && pup <= BlackKing))) {
- /* EditPosition, empty square, or different color piece;
- click-click move is possible */
- toX = x;
- toY = y;
- if (IsPromotion(fromX, fromY, toX, toY)) {
- if (appData.alwaysPromoteToQueen) {
- UserMoveEvent(fromX, fromY, toX, toY, 'q');
- if (!appData.highlightLastMove) {
- ClearHighlights();
- DrawPosition(FALSE, NULL);
- }
- } else {
- SetHighlights(fromX, fromY, toX, toY);
- DrawPosition(FALSE, NULL);
- PromotionPopup(hwnd);
- }
- } else { /* not a promotion */
- if (appData.animate || appData.highlightLastMove) {
- SetHighlights(fromX, fromY, toX, toY);
- } else {
- ClearHighlights();
- }
- UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
- if (appData.animate && !appData.highlightLastMove) {
- ClearHighlights();
- DrawPosition(FALSE, NULL);
- }
- }
- if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
- fromX = fromY = -1;
- break;
- }
- ClearHighlights();
- DrawPosition(FALSE, NULL);
- }
- /* First downclick, or restart on a square with same color piece */
- if (!frozen && OKToStartUserMove(x, y)) {
- fromX = x;
- fromY = y;
- dragInfo.lastpos = pt;
- dragInfo.from.x = fromX;
- dragInfo.from.y = fromY;
- dragInfo.start = dragInfo.from;
- SetCapture(hwndMain);
- } else {
- fromX = fromY = -1;
- dragInfo.start.x = dragInfo.start.y = -1;
- dragInfo.from = dragInfo.start;
- }
- break;
-
- case WM_LBUTTONUP:
- ReleaseCapture();
- if (fromX == -1) break;
- if (x == fromX && y == fromY) {
- dragInfo.from.x = dragInfo.from.y = -1;
- /* Upclick on same square */
- if (sameAgain) {
- /* Clicked same square twice: abort click-click move */
- fromX = fromY = -1;
- gotPremove = 0;
- ClearPremoveHighlights();
- } else {
- /* First square clicked: start click-click move */
- SetHighlights(fromX, fromY, -1, -1);
- }
- DrawPosition(FALSE, NULL);
- } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
- /* Errant click; ignore */
- break;
- } else {
- /* Finish drag move */
- dragInfo.from.x = dragInfo.from.y = -1;
- toX = x;
- toY = y;
- saveAnimate = appData.animate; /* sorry, Hawk :) */
- appData.animate = appData.animate && !appData.animateDragging;
- if (IsPromotion(fromX, fromY, toX, toY)) {
- if (appData.alwaysPromoteToQueen) {
- UserMoveEvent(fromX, fromY, toX, toY, 'q');
- } else {
- DrawPosition(FALSE, NULL);
- PromotionPopup(hwnd);
- }
- } else {
- UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
- }
- if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
- appData.animate = saveAnimate;
- fromX = fromY = -1;
- if (appData.highlightDragging && !appData.highlightLastMove) {
- ClearHighlights();
- }
- if (appData.animate || appData.animateDragging ||
- appData.highlightDragging || gotPremove) {
- DrawPosition(FALSE, NULL);
- }
- }
- dragInfo.start.x = dragInfo.start.y = -1;
- dragInfo.pos = dragInfo.lastpos = dragInfo.start;
- break;
-
- case WM_MOUSEMOVE:
- if ((appData.animateDragging || appData.highlightDragging)
- && (wParam & MK_LBUTTON)
- && dragInfo.from.x >= 0) {
- if (appData.animateDragging) {
- dragInfo.pos = pt;
- }
- if (appData.highlightDragging) {
- SetHighlights(fromX, fromY, x, y);
- }
- DrawPosition(FALSE, NULL);
- dragInfo.lastpos = dragInfo.pos;
- }
- break;
- case WM_MOUSEWHEEL:
- /* Mouse Wheel is being rolled forward
- * Play moves forward
- */
- if ((short)HIWORD(wParam) > 0)
- if (forwardMostMove > 0 && currentMove != forwardMostMove)
- ForwardEvent();
- /* Mouse Wheel is being rolled backward
- * Play moves backward
- */
- if ((short)HIWORD(wParam) < 0)
- if (currentMove > 0) BackwardEvent();
- break;
- case WM_MBUTTONDOWN:
- case WM_RBUTTONDOWN:
- ErrorPopDown();
- ReleaseCapture();
- fromX = fromY = -1;
- dragInfo.pos.x = dragInfo.pos.y = -1;
- dragInfo.start.x = dragInfo.start.y = -1;
- dragInfo.from = dragInfo.start;
- dragInfo.lastpos = dragInfo.pos;
- if (appData.highlightDragging) {
- ClearHighlights();
- }
- DrawPosition(TRUE, NULL);
-
- switch (gameMode) {
- case EditPosition:
- case IcsExamining:
- if (x < 0 || y < 0) break;
- fromX = x;
- fromY = y;
- if (message == WM_MBUTTONDOWN) {
- buttonCount = 3; /* even if system didn't think so */
- if (wParam & MK_SHIFT)
- MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
- else
- MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
- } else { /* message == WM_RBUTTONDOWN */
-#if 0
- if (buttonCount == 3) {
- if (wParam & MK_SHIFT)
- MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
- else
- MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
- } else {
- MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
- }
-#else
- /* Just have one menu, on the right button. Windows users don't
- think to try the middle one, and sometimes other software steals
- it, or it doesn't really exist. */
- MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
-#endif
- }
- break;
- case IcsPlayingWhite:
- case IcsPlayingBlack:
- case EditGame:
- case MachinePlaysWhite:
- case MachinePlaysBlack:
- if (appData.testLegality &&
- gameInfo.variant != VariantBughouse &&
- gameInfo.variant != VariantCrazyhouse) break;
- if (x < 0 || y < 0) break;
- fromX = x;
- fromY = y;
- hmenu = LoadMenu(hInst, "DropPieceMenu");
- SetupDropMenu(hmenu);
- MenuPopup(hwnd, pt, hmenu, -1);
- break;
- default:
- break;
- }
- break;
- }
-
- recursive--;
-}
-
-/* Preprocess messages for buttons in main window */
-LRESULT CALLBACK
-ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- int id = GetWindowLong(hwnd, GWL_ID);
- int i, dir;
-
- for (i=0; i<N_BUTTONS; i++) {
- if (buttonDesc[i].id == id) break;
- }
- if (i == N_BUTTONS) return 0;
- switch (message) {
- case WM_KEYDOWN:
- switch (wParam) {
- case VK_LEFT:
- case VK_RIGHT:
- dir = (wParam == VK_LEFT) ? -1 : 1;
- SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
- return TRUE;
- }
- break;
- case WM_CHAR:
- switch (wParam) {
- case '\r':
- SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
- return TRUE;
- case '\t':
- if (appData.icsActive) {
- if (GetKeyState(VK_SHIFT) < 0) {
- /* shifted */
- HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
- if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
- SetFocus(h);
- } else {
- /* unshifted */
- HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
- if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
- SetFocus(h);
- }
- return TRUE;
- }
- break;
- default:
- if (appData.icsActive) {
- HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
- if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
- SetFocus(h);
- SendMessage(h, WM_CHAR, wParam, lParam);
- return TRUE;
- } else if (isalpha((char)wParam) || isdigit((char)wParam)){
- PopUpMoveDialog((char)wParam);
- }
- break;
- }
- break;
- }
- return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
-}
-
-/* Process messages for Promotion dialog box */
-LRESULT CALLBACK
-Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- char promoChar;
-
- switch (message) {
- case WM_INITDIALOG: /* message: initialize dialog box */
- /* Center the dialog over the application window */
- CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
- ShowWindow(GetDlgItem(hDlg, PB_King),
- (!appData.testLegality || gameInfo.variant == VariantSuicide ||
- gameInfo.variant == VariantGiveaway) ?
- SW_SHOW : SW_HIDE);
- return TRUE;
-
- case WM_COMMAND: /* message: received a command */
- switch (LOWORD(wParam)) {
- case IDCANCEL:
- EndDialog(hDlg, TRUE); /* Exit the dialog */
- ClearHighlights();
- DrawPosition(FALSE, NULL);
- return TRUE;
- case PB_King:
- promoChar = 'k';
- break;
- case PB_Queen:
- promoChar = 'q';
- break;
- case PB_Rook:
- promoChar = 'r';
- break;
- case PB_Bishop:
- promoChar = 'b';
- break;
- case PB_Knight:
- promoChar = 'n';
- break;
- default:
- return FALSE;
- }
- EndDialog(hDlg, TRUE); /* Exit the dialog */
- UserMoveEvent(fromX, fromY, toX, toY, promoChar);
- if (!appData.highlightLastMove) {
- ClearHighlights();
- DrawPosition(FALSE, NULL);
- }
- return TRUE;
- }
- return FALSE;
-}
-
-/* Pop up promotion dialog */
-VOID
-PromotionPopup(HWND hwnd)
-{
- FARPROC lpProc;
-
- lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
- DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
- hwnd, (DLGPROC)lpProc);
- FreeProcInstance(lpProc);
-}
-
-/* Toggle ShowThinking */
-VOID
-ToggleShowThinking()
-{
- ShowThinkingEvent(!appData.showThinking);
-}
-
-VOID
-LoadGameDialog(HWND hwnd, char* title)
-{
- UINT number = 0;
- FILE *f;
- char fileTitle[MSG_SIZ];
- f = OpenFileDialog(hwnd, FALSE, "",
- appData.oldSaveStyle ? "gam" : "pgn",
- GAME_FILT,
- title, &number, fileTitle, NULL);
- if (f != NULL) {
- cmailMsgLoaded = FALSE;
- if (number == 0) {
- int error = GameListBuild(f);
- if (error) {
- DisplayError("Cannot build game list", error);
- } else if (!ListEmpty(&gameList) &&
- ((ListGame *) gameList.tailPred)->number > 1) {
- GameListPopUp(f, fileTitle);
- return;
- }
- GameListDestroy();
- number = 1;
- }
- LoadGame(f, number, fileTitle, FALSE);
- }
-}
-
-VOID
-ChangedConsoleFont()
-{
- CHARFORMAT cfmt;
- CHARRANGE tmpsel, sel;
- MyFont *f = font[boardSize][CONSOLE_FONT];
- HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
- HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
- PARAFORMAT paraf;
-
- cfmt.cbSize = sizeof(CHARFORMAT);
- cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
- strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
- /* yHeight is expressed in twips. A twip is 1/20 of a font's point
- * size. This was undocumented in the version of MSVC++ that I had
- * when I wrote the code, but is apparently documented now.
- */
- cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
- cfmt.bCharSet = f->lf.lfCharSet;
- cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
- SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
- SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
- /* Why are the following seemingly needed too? */
- SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
- SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
- SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
- tmpsel.cpMin = 0;
- tmpsel.cpMax = -1; /*999999?*/
- SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
- SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
- /* Trying putting this here too. It still seems to tickle a RichEdit
- * bug: sometimes RichEdit indents the first line of a paragraph too.
- */
- paraf.cbSize = sizeof(paraf);
- paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
- paraf.dxStartIndent = 0;
- paraf.dxOffset = WRAP_INDENT;
- SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
- SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
-}
-
-/*---------------------------------------------------------------------------*\
- *
- * Window Proc for main window
- *
-\*---------------------------------------------------------------------------*/
-
-/* Process messages for main window, etc. */
-LRESULT CALLBACK
-WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- FARPROC lpProc;
- int wmId, wmEvent;
- char *defName;
- FILE *f;
- UINT number;
- char fileTitle[MSG_SIZ];
- char buf[MSG_SIZ];
-
- switch (message) {
-
- case WM_PAINT: /* message: repaint portion of window */
- PaintProc(hwnd);
- break;
-
- case WM_ERASEBKGND:
- if (IsIconic(hwnd)) {
- /* Cheat; change the message */
- return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
- } else {
- return (DefWindowProc(hwnd, message, wParam, lParam));
- }
- break;
-
- case WM_LBUTTONDOWN:
- case WM_MBUTTONDOWN:
- case WM_RBUTTONDOWN:
- case WM_LBUTTONUP:
- case WM_MBUTTONUP:
- case WM_RBUTTONUP:
- case WM_MOUSEMOVE:
- case WM_MOUSEWHEEL:
- MouseEvent(hwnd, message, wParam, lParam);
- break;
-
- case WM_CHAR:
-
- if (appData.icsActive) {
- if (wParam == '\t') {
- if (GetKeyState(VK_SHIFT) < 0) {
- /* shifted */
- HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
- if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
- SetFocus(h);
- } else {
- /* unshifted */
- HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
- if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
- SetFocus(h);
- }
- } else {
- HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
- if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
- SetFocus(h);
- SendMessage(h, message, wParam, lParam);
- }
- } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
- PopUpMoveDialog((char)wParam);
- }
- break;
-
- case WM_PALETTECHANGED:
- if (hwnd != (HWND)wParam && !appData.monoMode) {
- int nnew;
- HDC hdc = GetDC(hwndMain);
- SelectPalette(hdc, hPal, TRUE);
- nnew = RealizePalette(hdc);
- if (nnew > 0) {
- paletteChanged = TRUE;
-#if 0
- UpdateColors(hdc);
-#else
- InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
-#endif
- }
- ReleaseDC(hwnd, hdc);
- }
- break;
-
- case WM_QUERYNEWPALETTE:
- if (!appData.monoMode /*&& paletteChanged*/) {
- int nnew;
- HDC hdc = GetDC(hwndMain);
- paletteChanged = FALSE;
- SelectPalette(hdc, hPal, FALSE);
- nnew = RealizePalette(hdc);
- if (nnew > 0) {
- InvalidateRect(hwnd, &boardRect, FALSE);
- }
- ReleaseDC(hwnd, hdc);
- return TRUE;
- }
- return FALSE;
-
- case WM_COMMAND: /* message: command from application menu */
- wmId = LOWORD(wParam);
- wmEvent = HIWORD(wParam);
-
- switch (wmId) {
- case IDM_NewGame:
- ResetGameEvent();
- AnalysisPopDown();
- break;
-
- case IDM_LoadGame:
- LoadGameDialog(hwnd, "Load Game from File");
- break;
-
- case IDM_LoadNextGame:
- ReloadGame(1);
- break;
-
- case IDM_LoadPrevGame:
- ReloadGame(-1);
- break;
-
- case IDM_ReloadGame:
- ReloadGame(0);
- break;
-
- case IDM_LoadPosition:
- if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
- Reset(FALSE, TRUE);
- }
- number = 1;
- f = OpenFileDialog(hwnd, FALSE, "",
- appData.oldSaveStyle ? "pos" : "fen",
- POSITION_FILT,
- "Load Position from File", &number, fileTitle, NULL);
- if (f != NULL) {
- LoadPosition(f, number, fileTitle);
- }
- break;
-
- case IDM_LoadNextPosition:
- ReloadPosition(1);
- break;
-
- case IDM_LoadPrevPosition:
- ReloadPosition(-1);
- break;
-
- case IDM_ReloadPosition:
- ReloadPosition(0);
- break;
-
- case IDM_SaveGame:
- defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
- f = OpenFileDialog(hwnd, TRUE, defName,
- appData.oldSaveStyle ? "gam" : "pgn",
- GAME_FILT,
- "Save Game to File", NULL, fileTitle, NULL);
- if (f != NULL) {
- SaveGame(f, 0, "");
- }
- break;
-
- case IDM_SavePosition:
- defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
- f = OpenFileDialog(hwnd, TRUE, defName,
- appData.oldSaveStyle ? "pos" : "fen",
- POSITION_FILT,
- "Save Position to File", NULL, fileTitle, NULL);
- if (f != NULL) {
- SavePosition(f, 0, "");
- }
- break;
-
- case IDM_CopyGame:
- CopyGameToClipboard();
- break;
-
- case IDM_PasteGame:
- PasteGameFromClipboard();
- break;
-
- case IDM_CopyPosition:
- CopyFENToClipboard();
- break;
-
- case IDM_PastePosition:
- PasteFENFromClipboard();
- break;
-
- case IDM_MailMove:
- MailMoveEvent();
- break;
-
- case IDM_ReloadCMailMsg:
- Reset(TRUE, TRUE);
- ReloadCmailMsgEvent(FALSE);
- break;
-
- case IDM_Minimize:
- ShowWindow(hwnd, SW_MINIMIZE);
- break;
-
- case IDM_Exit:
- ExitEvent(0);
- break;
-
- case IDM_MachineWhite:
- MachineWhiteEvent();
- /*
- * refresh the tags dialog only if it's visible
- */
- if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
- char *tags;
- tags = PGNTags(&gameInfo);
- TagsPopUp(tags, CmailMsg());
- free(tags);
- }
- break;
-
- case IDM_MachineBlack:
- MachineBlackEvent();
- /*
- * refresh the tags dialog only if it's visible
- */
- if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
- char *tags;
- tags = PGNTags(&gameInfo);
- TagsPopUp(tags, CmailMsg());
- free(tags);
- }
- break;
-
- case IDM_TwoMachines:
- TwoMachinesEvent();
- /*
- * refresh the tags dialog only if it's visible
- */
- if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
- char *tags;
- tags = PGNTags(&gameInfo);
- TagsPopUp(tags, CmailMsg());
- free(tags);
- }
- break;
-
- case IDM_AnalysisMode:
- if (!first.analysisSupport) {
- sprintf(buf, "%s does not support analysis", first.tidy);
- DisplayError(buf, 0);
- } else {
- /* icsEngineAnlyze */
- if (appData.icsActive) {
- if (gameMode != IcsObserving) {
- sprintf(buf, "You are not observing a game");
- DisplayError(buf, 0);
- /* secure check */
- if (appData.icsEngineAnalyze) {
- if (appData.debugMode)
- fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
- ExitAnalyzeMode();
- ModeHighlight();
- break;
- }
- break;
- } else {
- /* if enable, user want disable icsEngineAnalyze */
- if (appData.icsEngineAnalyze) {
- ExitAnalyzeMode();
- ModeHighlight();
- break;
- }
- appData.icsEngineAnalyze = TRUE;
- if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
- }
- }
- if (!appData.showThinking) ToggleShowThinking();
- AnalyzeModeEvent();
- }
- break;
- case IDM_AnalyzeFile:
- if (!first.analysisSupport) {
- char buf[MSG_SIZ];
- sprintf(buf, "%s does not support analysis", first.tidy);
- DisplayError(buf, 0);
- } else {
- if (!appData.showThinking) ToggleShowThinking();
- AnalyzeFileEvent();
- LoadGameDialog(hwnd, "Analyze Game from File");
- AnalysisPeriodicEvent(1);
- }
- break;
-
- case IDM_IcsClient:
- IcsClientEvent();
- break;
-
- case IDM_EditGame:
- EditGameEvent();
- break;
-
- case IDM_EditPosition:
- EditPositionEvent();
- break;
-
- case IDM_Training:
- TrainingEvent();
- break;
-
- case IDM_ShowGameList:
- ShowGameListProc();
- break;
-
- case IDM_EditTags:
- EditTagsProc();
- break;
-
- case IDM_EditComment:
- if (commentDialogUp && editComment) {
- CommentPopDown();
- } else {
- EditCommentEvent();
- }
- break;
-
- case IDM_Pause:
- PauseEvent();
- break;
-
- case IDM_Accept:
- AcceptEvent();
- break;
-
- case IDM_Decline:
- DeclineEvent();
- break;
-
- case IDM_Rematch:
- RematchEvent();
- break;
-
- case IDM_CallFlag:
- CallFlagEvent();
- break;
-
- case IDM_Draw:
- DrawEvent();
- break;
-
- case IDM_Adjourn:
- AdjournEvent();
- break;
-
- case IDM_Abort:
- AbortEvent();
- break;
-
- case IDM_Resign:
- ResignEvent();
- break;
-
- case IDM_StopObserving:
- StopObservingEvent();
- break;
-
- case IDM_StopExamining:
- StopExaminingEvent();
- break;
-
- case IDM_TypeInMove:
- PopUpMoveDialog('\000');
- break;
-
- case IDM_Backward:
- BackwardEvent();
- SetFocus(hwndMain);
- break;
-
- case IDM_Forward:
- ForwardEvent();
- SetFocus(hwndMain);
- break;
-
- case IDM_ToStart:
- ToStartEvent();
- SetFocus(hwndMain);
- break;
-
- case IDM_ToEnd:
- ToEndEvent();
- SetFocus(hwndMain);
- break;
-
- case IDM_Revert:
- RevertEvent();
- break;
-
- case IDM_TruncateGame:
- TruncateGameEvent();
- break;
-
- case IDM_MoveNow:
- MoveNowEvent();
- break;
-
- case IDM_RetractMove:
- RetractMoveEvent();
- break;
-
- case IDM_FlipView:
- flipView = !flipView;
- DrawPosition(FALSE, NULL);
- break;
-
- case IDM_GeneralOptions:
- GeneralOptionsPopup(hwnd);
- break;
-
- case IDM_BoardOptions:
- BoardOptionsPopup(hwnd);
- break;
-
- case IDM_IcsOptions:
- IcsOptionsPopup(hwnd);
- break;
-
- case IDM_Fonts:
- FontsOptionsPopup(hwnd);
- break;
-
- case IDM_Sounds:
- SoundOptionsPopup(hwnd);
- break;
-
- case IDM_CommPort:
- CommPortOptionsPopup(hwnd);
- break;
-
- case IDM_LoadOptions:
- LoadOptionsPopup(hwnd);
- break;
-
- case IDM_SaveOptions:
- SaveOptionsPopup(hwnd);
- break;
-
- case IDM_TimeControl:
- TimeControlOptionsPopup(hwnd);
- break;
-
- case IDM_SaveSettings:
- SaveSettings(settingsFileName);
- break;
-
- case IDM_SaveSettingsOnExit:
- saveSettingsOnExit = !saveSettingsOnExit;
- (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
- MF_BYCOMMAND|(saveSettingsOnExit ?
- MF_CHECKED : MF_UNCHECKED));
- break;
-
- case IDM_Hint:
- HintEvent();
- break;
-
- case IDM_Book:
- BookEvent();
- break;
-
- case IDM_AboutGame:
- AboutGameEvent();
- break;
-
- case IDM_Debug:
- appData.debugMode = !appData.debugMode;
- if (appData.debugMode) {
- char dir[MSG_SIZ];
- GetCurrentDirectory(MSG_SIZ, dir);
- SetCurrentDirectory(installDir);
- debugFP = fopen("WinBoard.debug", "w");
- SetCurrentDirectory(dir);
- setbuf(debugFP, NULL);
- } else {
- fclose(debugFP);
- debugFP = NULL;
- }
- break;
-
- case IDM_HELPCONTENTS:
- if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
- MessageBox (GetFocus(),
- "Unable to activate help",
- szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
- }
- break;
-
- case IDM_HELPSEARCH:
- if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
- MessageBox (GetFocus(),
- "Unable to activate help",
- szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
- }
- break;
-
- case IDM_HELPHELP:
- if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
- MessageBox (GetFocus(),
- "Unable to activate help",
- szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
- }
- break;
-
- case IDM_ABOUT:
- lpProc = MakeProcInstance((FARPROC)About, hInst);
- DialogBox(hInst,
- (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
- "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
- FreeProcInstance(lpProc);
- break;
-
- case IDM_DirectCommand1:
- AskQuestionEvent("Direct Command",
- "Send to chess program:", "", "1");
- break;
- case IDM_DirectCommand2:
- AskQuestionEvent("Direct Command",
- "Send to second chess program:", "", "2");
- break;
-
- case EP_WhitePawn:
- EditPositionMenuEvent(WhitePawn, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_WhiteKnight:
- EditPositionMenuEvent(WhiteKnight, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_WhiteBishop:
- EditPositionMenuEvent(WhiteBishop, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_WhiteRook:
- EditPositionMenuEvent(WhiteRook, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_WhiteQueen:
- EditPositionMenuEvent(WhiteQueen, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_WhiteKing:
- EditPositionMenuEvent(WhiteKing, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_BlackPawn:
- EditPositionMenuEvent(BlackPawn, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_BlackKnight:
- EditPositionMenuEvent(BlackKnight, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_BlackBishop:
- EditPositionMenuEvent(BlackBishop, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_BlackRook:
- EditPositionMenuEvent(BlackRook, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_BlackQueen:
- EditPositionMenuEvent(BlackQueen, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_BlackKing:
- EditPositionMenuEvent(BlackKing, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_EmptySquare:
- EditPositionMenuEvent(EmptySquare, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_ClearBoard:
- EditPositionMenuEvent(ClearBoard, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_White:
- EditPositionMenuEvent(WhitePlay, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case EP_Black:
- EditPositionMenuEvent(BlackPlay, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case DP_Pawn:
- DropMenuEvent(WhitePawn, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case DP_Knight:
- DropMenuEvent(WhiteKnight, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case DP_Bishop:
- DropMenuEvent(WhiteBishop, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case DP_Rook:
- DropMenuEvent(WhiteRook, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- case DP_Queen:
- DropMenuEvent(WhiteQueen, fromX, fromY);
- fromX = fromY = -1;
- break;
-
- default:
- return (DefWindowProc(hwnd, message, wParam, lParam));
- }
- break;
-
- case WM_TIMER:
- switch (wParam) {
- case CLOCK_TIMER_ID:
- KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
- clockTimerEvent = 0;
- DecrementClocks(); /* call into back end */
- break;
- case LOAD_GAME_TIMER_ID:
- KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
- loadGameTimerEvent = 0;
- AutoPlayGameLoop(); /* call into back end */
- break;
- case ANALYSIS_TIMER_ID:
- if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
- || appData.icsEngineAnalyze) && appData.periodicUpdates) {
- AnalysisPeriodicEvent(0);
- } else {
- KillTimer(hwnd, analysisTimerEvent);
- analysisTimerEvent = 0;
- }
- break;
- case DELAYED_TIMER_ID:
- KillTimer(hwnd, delayedTimerEvent);
- delayedTimerEvent = 0;
- delayedTimerCallback();
- break;
- }
- break;
-
- case WM_USER_Input:
- InputEvent(hwnd, message, wParam, lParam);
- break;
-
- case WM_ENTERSIZEMOVE:
- if (hwnd == hwndMain) {
- doingSizing = TRUE;
- lastSizing = 0;
- }
- break;
-
- case WM_SIZING:
- if (hwnd == hwndMain) {
- lastSizing = wParam;
- }
- break;
-
- case WM_EXITSIZEMOVE:
- if (hwnd == hwndMain) {
- RECT client;
- doingSizing = FALSE;
- InvalidateRect(hwnd, &boardRect, FALSE);
- GetClientRect(hwnd, &client);
- ResizeBoard(client.right, client.bottom, lastSizing);
- lastSizing = 0;
- }
- break;
-
- case WM_DESTROY: /* message: window being destroyed */
- PostQuitMessage(0);
- break;
-
- case WM_CLOSE:
- if (hwnd == hwndMain) {
- ExitEvent(0);
- }
- break;
-
- default: /* Passes it on if unprocessed */
- return (DefWindowProc(hwnd, message, wParam, lParam));
- }
- return 0;
-}
-
-/*---------------------------------------------------------------------------*\
- *
- * Misc utility routines
- *
-\*---------------------------------------------------------------------------*/
-
-/*
- * Decent random number generator, at least not as bad as Windows
- * standard rand, which returns a value in the range 0 to 0x7fff.
- */
-unsigned int randstate;
-
-int
-myrandom(void)
-{
- randstate = randstate * 1664525 + 1013904223;
- return (int) randstate & 0x7fffffff;
-}
-
-void
-mysrandom(unsigned int seed)
-{
- randstate = seed;
-}
-
-
-/*
- * returns TRUE if user selects a different color, FALSE otherwise
- */
-
-BOOL
-ChangeColor(HWND hwnd, COLORREF *which)
-{
- static BOOL firstTime = TRUE;
- static DWORD customColors[16];
- CHOOSECOLOR cc;
- COLORREF newcolor;
- int i;
- ColorClass ccl;
-
- if (firstTime) {
- /* Make initial colors in use available as custom colors */
- /* Should we put the compiled-in defaults here instead? */
- i = 0;
- customColors[i++] = lightSquareColor & 0xffffff;
- customColors[i++] = darkSquareColor & 0xffffff;
- customColors[i++] = whitePieceColor & 0xffffff;
- customColors[i++] = blackPieceColor & 0xffffff;
- customColors[i++] = highlightSquareColor & 0xffffff;
- customColors[i++] = premoveHighlightColor & 0xffffff;
-
- for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
- customColors[i++] = textAttribs[ccl].color;
- }
- while (i < 16) customColors[i++] = RGB(255, 255, 255);
- firstTime = FALSE;
- }
-
- cc.lStructSize = sizeof(cc);
- cc.hwndOwner = hwnd;
- cc.hInstance = NULL;
- cc.rgbResult = (DWORD) (*which & 0xffffff);
- cc.lpCustColors = (LPDWORD) customColors;
- cc.Flags = CC_RGBINIT|CC_FULLOPEN;
-
- if (!ChooseColor(&cc)) return FALSE;
-
- newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
- if (newcolor == *which) return FALSE;
- *which = newcolor;
- return TRUE;
-
- /*
- InitDrawingColors();
- InvalidateRect(hwnd, &boardRect, FALSE);
- */
-}
-
-BOOLEAN
-MyLoadSound(MySound *ms)
-{
- BOOL ok = FALSE;
- struct stat st;
- FILE *f;
-
- if (ms->data) free(ms->data);
- ms->data = NULL;
-
- switch (ms->name[0]) {
- case NULLCHAR:
- /* Silence */
- ok = TRUE;
- break;
- case '$':
- /* System sound from Control Panel. Don't preload here. */
- ok = TRUE;
- break;
- case '!':
- if (ms->name[1] == NULLCHAR) {
- /* "!" alone = silence */
- ok = TRUE;
- } else {
- /* Builtin wave resource. Error if not found. */
- HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
- if (h == NULL) break;
- ms->data = (void *)LoadResource(hInst, h);
- if (h == NULL) break;
- ok = TRUE;
- }
- break;
- default:
- /* .wav file. Error if not found. */
- f = fopen(ms->name, "rb");
- if (f == NULL) break;
- if (fstat(fileno(f), &st) < 0) break;
- ms->data = malloc(st.st_size);
- if (fread(ms->data, st.st_size, 1, f) < 1) break;
- fclose(f);
- ok = TRUE;
- break;
- }
- if (!ok) {
- char buf[MSG_SIZ];
- sprintf(buf, "Error loading sound %s", ms->name);
- DisplayError(buf, GetLastError());
- }
- return ok;
-}
-
-BOOLEAN
-MyPlaySound(MySound *ms)
-{
- BOOLEAN ok = FALSE;
- switch (ms->name[0]) {
- case NULLCHAR:
- /* Silence */
- ok = TRUE;
- break;
- case '$':
- /* System sound from Control Panel (deprecated feature).
- "$" alone or an unset sound name gets default beep (still in use). */
- if (ms->name[1]) {
- ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
- }
- if (!ok) ok = MessageBeep(MB_OK);
- break;
- case '!':
- /* Builtin wave resource, or "!" alone for silence */
- if (ms->name[1]) {
- if (ms->data == NULL) return FALSE;
- ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
- } else {
- ok = TRUE;
- }
- break;
- default:
- /* .wav file. Error if not found. */
- if (ms->data == NULL) return FALSE;
- ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
- break;
- }
- /* Don't print an error: this can happen innocently if the sound driver
- is busy; for instance, if another instance of WinBoard is playing
- a sound at about the same time. */
-#if 0
- if (!ok) {
- char buf[MSG_SIZ];
- sprintf(buf, "Error playing sound %s", ms->name);
- DisplayError(buf, GetLastError());
- }
-#endif
- return ok;
-}
-
-
-LRESULT CALLBACK
-OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- BOOL ok;
- OPENFILENAME *ofn;
- static UINT *number; /* gross that this is static */
-
- switch (message) {
- case WM_INITDIALOG: /* message: initialize dialog box */
- /* Center the dialog over the application window */
- ofn = (OPENFILENAME *) lParam;
- if (ofn->Flags & OFN_ENABLETEMPLATE) {
- number = (UINT *) ofn->lCustData;
- SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
- } else {
- number = NULL;
- }
- CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
- return FALSE; /* Allow for further processing */
-
- case WM_COMMAND:
- if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
- *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
- }
- return FALSE; /* Allow for further processing */
- }
- return FALSE;
-}
-
-UINT APIENTRY
-OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
-{
- static UINT *number;
- OPENFILENAME *ofname;
- OFNOTIFY *ofnot;
- switch (uiMsg) {
- case WM_INITDIALOG:
- ofname = (OPENFILENAME *)lParam;
- number = (UINT *)(ofname->lCustData);
- break;
- case WM_NOTIFY:
- ofnot = (OFNOTIFY *)lParam;
- if (ofnot->hdr.code == CDN_FILEOK) {
- *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
- }
- break;
- }
- return 0;
-}
-
-
-FILE *
-OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
- char *nameFilt, char *dlgTitle, UINT *number,
- char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
-{
- OPENFILENAME openFileName;
- char buf1[MSG_SIZ];
- FILE *f;
-
- if (fileName == NULL) fileName = buf1;
- if (defName == NULL) {
- strcpy(fileName, "*.");
- strcat(fileName, defExt);
- } else {
- strcpy(fileName, defName);
- }
- if (fileTitle) strcpy(fileTitle, "");
- if (number) *number = 0;
-
- openFileName.lStructSize = sizeof(OPENFILENAME);
- openFileName.hwndOwner = hwnd;
- openFileName.hInstance = (HANDLE) hInst;
- openFileName.lpstrFilter = nameFilt;
- openFileName.lpstrCustomFilter = (LPSTR) NULL;
- openFileName.nMaxCustFilter = 0L;
- openFileName.nFilterIndex = 1L;
- openFileName.lpstrFile = fileName;
- openFileName.nMaxFile = MSG_SIZ;
- openFileName.lpstrFileTitle = fileTitle;
- openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
- openFileName.lpstrInitialDir = NULL;
- openFileName.lpstrTitle = dlgTitle;
- openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
- | (write ? 0 : OFN_FILEMUSTEXIST)
- | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
- | (oldDialog ? 0 : OFN_EXPLORER);
- openFileName.nFileOffset = 0;
- openFileName.nFileExtension = 0;
- openFileName.lpstrDefExt = defExt;
- openFileName.lCustData = (LONG) number;
- openFileName.lpfnHook = oldDialog ?
- (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
- openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
-
- if (write ? GetSaveFileName(&openFileName) :
- GetOpenFileName(&openFileName)) {
- /* open the file */
- f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
- if (f == NULL) {
- MessageBox(hwnd, "File open failed", NULL,
- MB_OK|MB_ICONEXCLAMATION);
- return NULL;
- }
- } else {
- int err = CommDlgExtendedError();
- if (err != 0) DisplayError("Internal error in file dialog box", err);
- return FALSE;
- }
- return f;
-}
-
-
-
-VOID APIENTRY
-MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
-{
- HMENU hmenuTrackPopup; /* floating pop-up menu */
-
- /*
- * Get the first pop-up menu in the menu template. This is the
- * menu that TrackPopupMenu displays.
- */
- hmenuTrackPopup = GetSubMenu(hmenu, 0);
-
- SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
-
- /*
- * TrackPopup uses screen coordinates, so convert the
- * coordinates of the mouse click to screen coordinates.
- */
- ClientToScreen(hwnd, (LPPOINT) &pt);
-
- /* Draw and track the floating pop-up menu. */
- TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
- pt.x, pt.y, 0, hwnd, NULL);
-
- /* Destroy the menu.*/
- DestroyMenu(hmenu);
-}
-
-typedef struct {
- HWND hDlg, hText;
- int sizeX, sizeY, newSizeX, newSizeY;
- HDWP hdwp;
-} ResizeEditPlusButtonsClosure;
-
-BOOL CALLBACK
-ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
-{
- ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
- RECT rect;
- POINT pt;
-
- if (hChild == cl->hText) return TRUE;
- GetWindowRect(hChild, &rect); /* gives screen coords */
- pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
- pt.y = rect.top + cl->newSizeY - cl->sizeY;
- ScreenToClient(cl->hDlg, &pt);
- cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
- pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
- return TRUE;
-}
-
-/* Resize a dialog that has a (rich) edit field filling most of
- the top, with a row of buttons below */
-VOID
-ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
-{
- RECT rectText;
- int newTextHeight, newTextWidth;
- ResizeEditPlusButtonsClosure cl;
-
- /*if (IsIconic(hDlg)) return;*/
- if (newSizeX == sizeX && newSizeY == sizeY) return;
-
- cl.hdwp = BeginDeferWindowPos(8);
-
- GetWindowRect(hText, &rectText); /* gives screen coords */
- newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
- newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
- if (newTextHeight < 0) {
- newSizeY += -newTextHeight;
- newTextHeight = 0;
- }
- cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
- newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
-
- cl.hDlg = hDlg;
- cl.hText = hText;
- cl.sizeX = sizeX;
- cl.sizeY = sizeY;
- cl.newSizeX = newSizeX;
- cl.newSizeY = newSizeY;
- EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
-
- EndDeferWindowPos(cl.hdwp);
-}
-
-/* Center one window over another */
-BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
-{
- RECT rChild, rParent;
- int wChild, hChild, wParent, hParent;
- int wScreen, hScreen, xNew, yNew;
- HDC hdc;
-
- /* Get the Height and Width of the child window */
- GetWindowRect (hwndChild, &rChild);
- wChild = rChild.right - rChild.left;
- hChild = rChild.bottom - rChild.top;
-
- /* Get the Height and Width of the parent window */
- GetWindowRect (hwndParent, &rParent);
- wParent = rParent.right - rParent.left;
- hParent = rParent.bottom - rParent.top;
-
- /* Get the display limits */
- hdc = GetDC (hwndChild);
- wScreen = GetDeviceCaps (hdc, HORZRES);
- hScreen = GetDeviceCaps (hdc, VERTRES);
- ReleaseDC(hwndChild, hdc);
-
- /* Calculate new X position, then adjust for screen */
- xNew = rParent.left + ((wParent - wChild) /2);
- if (xNew < 0) {
- xNew = 0;
- } else if ((xNew+wChild) > wScreen) {
- xNew = wScreen - wChild;
- }
-
- /* Calculate new Y position, then adjust for screen */
- yNew = rParent.top + ((hParent - hChild) /2);
- if (yNew < 0) {
- yNew = 0;
- } else if ((yNew+hChild) > hScreen) {
- yNew = hScreen - hChild;
- }
-
- /* Set it, and return */
- return SetWindowPos (hwndChild, NULL,
- xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
-}
-
-/*---------------------------------------------------------------------------*\
- *
- * Startup Dialog functions
- *
-\*---------------------------------------------------------------------------*/
-void
-InitComboStrings(HANDLE hwndCombo, char **cd)
-{
- SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
-
- while (*cd != NULL) {
- SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
- cd++;
- }
-}
-
-void
-InitComboStringsFromOption(HANDLE hwndCombo, char *str)
-{
- char buf1[ARG_MAX];
- int len;
-
- if (str[0] == '@') {
- FILE* f = fopen(str + 1, "r");
- if (f == NULL) {
- DisplayFatalError(str + 1, errno, 2);
- return;
- }
- len = fread(buf1, 1, sizeof(buf1)-1, f);
- fclose(f);
- buf1[len] = NULLCHAR;
- str = buf1;
- }
-
- SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
-
- for (;;) {
- char buf[MSG_SIZ];
- char *end = strchr(str, '\n');
- if (end == NULL) return;
- memcpy(buf, str, end - str);
- buf[end - str] = NULLCHAR;
- SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
- str = end + 1;
- }
-}
-
-void
-SetStartupDialogEnables(HWND hDlg)
-{
- EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
- IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
- appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
- EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
- IsDlgButtonChecked(hDlg, OPT_ChessEngine));
- EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
- IsDlgButtonChecked(hDlg, OPT_ChessServer));
- EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
- IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
- EnableWindow(GetDlgItem(hDlg, IDOK),
- IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
- IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
- IsDlgButtonChecked(hDlg, OPT_View));
-}
-
-char *
-QuoteForFilename(char *filename)
-{
- int dquote, space;
- dquote = strchr(filename, '"') != NULL;
- space = strchr(filename, ' ') != NULL;
- if (dquote || space) {
- if (dquote) {
- return "'";
- } else {
- return "\"";
- }
- } else {
- return "";
- }
-}
-
-VOID
-InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
-{
- char buf[MSG_SIZ];
- char *q;
-
- InitComboStringsFromOption(hwndCombo, nthnames);
- q = QuoteForFilename(nthcp);
- sprintf(buf, "%s%s%s", q, nthcp, q);
- if (*nthdir != NULLCHAR) {
- q = QuoteForFilename(nthdir);
- sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
- }
- if (*nthcp == NULLCHAR) {
- SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
- } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
- SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
- SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
- }
-}
-
-LRESULT CALLBACK
-StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- char buf[MSG_SIZ];
- HANDLE hwndCombo;
- char *p;
-
- switch (message) {
- case WM_INITDIALOG:
- /* Center the dialog */
- CenterWindow (hDlg, GetDesktopWindow());
- /* Initialize the dialog items */
- InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
- appData.firstChessProgram, "fd", appData.firstDirectory,
- firstChessProgramNames);
- InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
- appData.secondChessProgram, "sd", appData.secondDirectory,
- secondChessProgramNames);
- hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
- InitComboStringsFromOption(hwndCombo, icsNames);
- sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
- if (*appData.icsHelper != NULLCHAR) {
- char *q = QuoteForFilename(appData.icsHelper);
- sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
- }
- if (*appData.icsHost == NULLCHAR) {
- SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
- /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
- } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
- SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
- SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
- }
- if (chessProgram) {
- CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
- } else if (appData.icsActive) {
- CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
- } else if (appData.noChessProgram) {
- CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
- }
- SetStartupDialogEnables(hDlg);
- return TRUE;
-
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
- strcpy(buf, "/fcp=");
- GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
- p = buf;
- ParseArgs(StringGet, &p);
- strcpy(buf, "/scp=");
- GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
- p = buf;
- ParseArgs(StringGet, &p);
- appData.noChessProgram = FALSE;
- appData.icsActive = FALSE;
- } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
- strcpy(buf, "/ics /icshost=");
- GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
- p = buf;
- ParseArgs(StringGet, &p);
- if (appData.zippyPlay) {
- strcpy(buf, "/fcp=");
- GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
- p = buf;
- ParseArgs(StringGet, &p);
- }
- } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
- appData.noChessProgram = TRUE;
- appData.icsActive = FALSE;
- } else {
- MessageBox(hDlg, "Choose an option, or cancel to exit",
- "Option Error", MB_OK|MB_ICONEXCLAMATION);
- return TRUE;
- }
- if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
- GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
- p = buf;
- ParseArgs(StringGet, &p);
- }
- EndDialog(hDlg, TRUE);
- return TRUE;
-
- case IDCANCEL:
- ExitEvent(0);
- return TRUE;
-
- case IDM_HELPCONTENTS:
- if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
- MessageBox (GetFocus(),
- "Unable to activate help",
- szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
- }
- break;
-
- default:
- SetStartupDialogEnables(hDlg);
- break;
- }
- break;
- }
- return FALSE;
-}
-
-/*---------------------------------------------------------------------------*\
- *
- * About box dialog functions
- *
-\*---------------------------------------------------------------------------*/
-
-/* Process messages for "About" dialog box */
-LRESULT CALLBACK
-About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- switch (message) {
- case WM_INITDIALOG: /* message: initialize dialog box */
- /* Center the dialog over the application window */
- CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
- SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
- return (TRUE);
-
- case WM_COMMAND: /* message: received a command */
- if (LOWORD(wParam) == IDOK /* "OK" box selected? */
- || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
- EndDialog(hDlg, TRUE); /* Exit the dialog */
- return (TRUE);
- }
- break;
- }
- return (FALSE);
-}
-
-/*---------------------------------------------------------------------------*\
- *
- * Comment Dialog functions
- *
-\*---------------------------------------------------------------------------*/
-
-LRESULT CALLBACK
-CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- static HANDLE hwndText = NULL;
- int len, newSizeX, newSizeY, flags;
- static int sizeX, sizeY;
- char *str;
- RECT rect;
- MINMAXINFO *mmi;
-
- switch (message) {
- case WM_INITDIALOG: /* message: initialize dialog box */
- /* Initialize the dialog items */
- hwndText = GetDlgItem(hDlg, OPT_CommentText);
- SetDlgItemText(hDlg, OPT_CommentText, commentText);
- EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
- EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
- EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
- SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
- SetWindowText(hDlg, commentTitle);
- if (editComment) {
- SetFocus(hwndText);
- } else {
- SetFocus(GetDlgItem(hDlg, IDOK));
- }
- SendMessage(GetDlgItem(hDlg, OPT_CommentText),
- WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
- MAKELPARAM(FALSE, 0));
- /* Size and position the dialog */
- if (!commentDialog) {
- commentDialog = hDlg;
- flags = SWP_NOZORDER;
- GetClientRect(hDlg, &rect);
- sizeX = rect.right;
- sizeY = rect.bottom;
- if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
- commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
- WINDOWPLACEMENT wp;
- EnsureOnScreen(&commentX, &commentY);
- wp.length = sizeof(WINDOWPLACEMENT);
- wp.flags = 0;
- wp.showCmd = SW_SHOW;
- wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
- wp.rcNormalPosition.left = commentX;
- wp.rcNormalPosition.right = commentX + commentW;
- wp.rcNormalPosition.top = commentY;
- wp.rcNormalPosition.bottom = commentY + commentH;
- SetWindowPlacement(hDlg, &wp);
-
- GetClientRect(hDlg, &rect);
- newSizeX = rect.right;
- newSizeY = rect.bottom;
- ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
- newSizeX, newSizeY);
- sizeX = newSizeX;
- sizeY = newSizeY;
- }
- }
- return FALSE;
-
- case WM_COMMAND: /* message: received a command */
- switch (LOWORD(wParam)) {
- case IDOK:
- if (editComment) {
- char *p, *q;
- /* Read changed options from the dialog box */
- hwndText = GetDlgItem(hDlg, OPT_CommentText);
- len = GetWindowTextLength(hwndText);
- str = (char *) malloc(len + 1);
- GetWindowText(hwndText, str, len + 1);
- p = q = str;
- while (*q) {
- if (*q == '\r')
- q++;
- else
- *p++ = *q++;
- }
- *p = NULLCHAR;
- ReplaceComment(commentIndex, str);
- free(str);
- }
- CommentPopDown();
- return TRUE;
-
- case IDCANCEL:
- case OPT_CancelComment:
- CommentPopDown();
- return TRUE;
-
- case OPT_ClearComment:
- SetDlgItemText(hDlg, OPT_CommentText, "");
- break;
-
- case OPT_EditComment:
- EditCommentEvent();
- return TRUE;
-
- default:
- break;
- }
- break;
-
- case WM_SIZE:
- newSizeX = LOWORD(lParam);
- newSizeY = HIWORD(lParam);
- ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
- sizeX = newSizeX;
- sizeY = newSizeY;
- break;
-
- case WM_GETMINMAXINFO:
- /* Prevent resizing window too small */
- mmi = (MINMAXINFO *) lParam;
- mmi->ptMinTrackSize.x = 100;
- mmi->ptMinTrackSize.y = 100;
- break;
- }
- return FALSE;
-}
-
-VOID
-EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
-{
- FARPROC lpProc;
- char *p, *q;
-
- CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
-
- if (str == NULL) str = "";
- p = (char *) malloc(2 * strlen(str) + 2);
- q = p;
- while (*str) {
- if (*str == '\n') *q++ = '\r';
- *q++ = *str++;
- }
- *q = NULLCHAR;
- if (commentText != NULL) free(commentText);
-
- commentIndex = index;
- commentTitle = title;
- commentText = p;
- editComment = edit;
-
- if (commentDialog) {
- SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
- if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
- } else {
- lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
- CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
- hwndMain, (DLGPROC)lpProc);
- FreeProcInstance(lpProc);
- }
- commentDialogUp = TRUE;
-}
-
-
-/*---------------------------------------------------------------------------*\
- *
- * Type-in move dialog functions
- *
-\*---------------------------------------------------------------------------*/
-
-LRESULT CALLBACK
-TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- char move[MSG_SIZ];
- HWND hInput;
- ChessMove moveType;
- int fromX, fromY, toX, toY;
- char promoChar;
-
- switch (message) {
- case WM_INITDIALOG:
- move[0] = (char) lParam;
- move[1] = NULLCHAR;
- CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
- hInput = GetDlgItem(hDlg, OPT_Move);
- SetWindowText(hInput, move);
- SetFocus(hInput);
- SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
- return FALSE;
-
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- if (gameMode != EditGame && currentMove != forwardMostMove &&
- gameMode != Training) {
- DisplayMoveError("Displayed move is not current");
- } else {
- GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
- if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
- &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
- if (gameMode != Training)
- forwardMostMove = currentMove;
- UserMoveEvent(fromX, fromY, toX, toY, promoChar);
- } else {
- DisplayMoveError("Could not parse move");
- }
- }
- EndDialog(hDlg, TRUE);
- return TRUE;
- case IDCANCEL:
- EndDialog(hDlg, FALSE);
- return TRUE;
- default:
- break;
- }
- break;
- }
- return FALSE;
-}
-
-VOID
-PopUpMoveDialog(char firstchar)
-{
- FARPROC lpProc;
-
- if ((gameMode == BeginningOfGame && !appData.icsActive) ||
- gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
- gameMode == AnalyzeMode || gameMode == EditGame ||
- gameMode == EditPosition || gameMode == IcsExamining ||
- gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
- gameMode == Training) {
- lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
- DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
- hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
- FreeProcInstance(lpProc);
- }
-}
-
-/*---------------------------------------------------------------------------*\
- *
- * Error dialogs
- *
-\*---------------------------------------------------------------------------*/
-
-/* Nonmodal error box */
-LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
- WPARAM wParam, LPARAM lParam);
-
-VOID
-ErrorPopUp(char *title, char *content)
-{
- FARPROC lpProc;
- char *p, *q;
- BOOLEAN modal = hwndMain == NULL;
-
- p = content;
- q = errorMessage;
- while (*p) {
- if (*p == '\n') {
- if (modal) {
- *q++ = ' ';
- p++;
- } else {
- *q++ = '\r';
- *q++ = *p++;
- }
- } else {
- *q++ = *p++;
- }
- }
- *q = NULLCHAR;
- strncpy(errorTitle, title, sizeof(errorTitle));
- errorTitle[sizeof(errorTitle) - 1] = '\0';
-
- if (modal) {
- MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
- } else {
- lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
- CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
- hwndMain, (DLGPROC)lpProc);
- FreeProcInstance(lpProc);
- }
-}
-
-VOID
-ErrorPopDown()
-{
- if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
- if (errorDialog == NULL) return;
- DestroyWindow(errorDialog);
- errorDialog = NULL;
-}
-
-LRESULT CALLBACK
-ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- HANDLE hwndText;
- RECT rChild;
-
- switch (message) {
- case WM_INITDIALOG:
- GetWindowRect(hDlg, &rChild);
- SetWindowPos(hDlg, NULL, rChild.left,
- rChild.top + boardRect.top - (rChild.bottom - rChild.top),
- 0, 0, SWP_NOZORDER|SWP_NOSIZE);
- errorDialog = hDlg;
- SetWindowText(hDlg, errorTitle);
- hwndText = GetDlgItem(hDlg, OPT_ErrorText);
- SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
- return FALSE;
-
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- if (errorDialog == hDlg) errorDialog = NULL;
- DestroyWindow(hDlg);
- return TRUE;
-
- default:
- break;
- }
- break;
- }
- return FALSE;
-}
-
-/*---------------------------------------------------------------------------*\
- *
- * Ics Interaction console functions
- *
-\*---------------------------------------------------------------------------*/
-
-#define HISTORY_SIZE 64
-static char *history[HISTORY_SIZE];
-int histIn = 0, histP = 0;
-
-VOID
-SaveInHistory(char *cmd)
-{
- if (history[histIn] != NULL) {
- free(history[histIn]);
- history[histIn] = NULL;
- }
- if (*cmd == NULLCHAR) return;
- history[histIn] = StrSave(cmd);
- histIn = (histIn + 1) % HISTORY_SIZE;
- if (history[histIn] != NULL) {
- free(history[histIn]);
- history[histIn] = NULL;
- }
- histP = histIn;
-}
-
-char *
-PrevInHistory(char *cmd)
-{
- int newhp;
- if (histP == histIn) {
- if (history[histIn] != NULL) free(history[histIn]);
- history[histIn] = StrSave(cmd);
- }
- newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
- if (newhp == histIn || history[newhp] == NULL) return NULL;
- histP = newhp;
- return history[histP];
-}
-
-char *
-NextInHistory()
-{
- if (histP == histIn) return NULL;
- histP = (histP + 1) % HISTORY_SIZE;
- return history[histP];
-}
-
-typedef struct {
- char *item;
- char *command;
- BOOLEAN getname;
- BOOLEAN immediate;
-} IcsTextMenuEntry;
-#define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
-IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
-
-void
-ParseIcsTextMenu(char *icsTextMenuString)
-{
- int flags = 0;
- IcsTextMenuEntry *e = icsTextMenuEntry;
- char *p = icsTextMenuString;
- while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
- free(e->item);
- e->item = NULL;
- if (e->command != NULL) {
- free(e->command);
- e->command = NULL;
- }
- e++;
- }
- e = icsTextMenuEntry;
- while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
- if (*p == ';' || *p == '\n') {
- e->item = strdup("-");
- e->command = NULL;
- p++;
- } else if (*p == '-') {
- e->item = strdup("-");
- e->command = NULL;
- p++;
- if (*p) p++;
- } else {
- char *q, *r, *s, *t;
- char c;
- q = strchr(p, ',');
- if (q == NULL) break;
- *q = NULLCHAR;
- r = strchr(q + 1, ',');
- if (r == NULL) break;
- *r = NULLCHAR;
- s = strchr(r + 1, ',');
- if (s == NULL) break;
- *s = NULLCHAR;
- c = ';';
- t = strchr(s + 1, c);
- if (t == NULL) {
- c = '\n';
- t = strchr(s + 1, c);
- }
- if (t != NULL) *t = NULLCHAR;
- e->item = strdup(p);
- e->command = strdup(q + 1);
- e->getname = *(r + 1) != '0';
- e->immediate = *(s + 1) != '0';
- *q = ',';
- *r = ',';
- *s = ',';
- if (t == NULL) break;
- *t = c;
- p = t + 1;
- }
- e++;
- }
-}
-
-HMENU
-LoadIcsTextMenu(IcsTextMenuEntry *e)
-{
- HMENU hmenu, h;
- int i = 0;
- hmenu = LoadMenu(hInst, "TextMenu");
- h = GetSubMenu(hmenu, 0);
- while (e->item) {
- if (strcmp(e->item, "-") == 0) {
- AppendMenu(h, MF_SEPARATOR, 0, 0);
- } else {
- if (e->item[0] == '|') {
- AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
- IDM_CommandX + i, &e->item[1]);
- } else {
- AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
- }
- }
- e++;
- i++;
- }
- return hmenu;
-}
-
-WNDPROC consoleTextWindowProc;
-
-void
-CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
-{
- char buf[MSG_SIZ], name[MSG_SIZ];
- HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
- CHARRANGE sel;
-
- if (!getname) {
- SetWindowText(hInput, command);
- if (immediate) {
- SendMessage(hInput, WM_CHAR, '\r', 0);
- } else {
- sel.cpMin = 999999;
- sel.cpMax = 999999;
- SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
- SetFocus(hInput);
- }
- return;
- }
- SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
- if (sel.cpMin == sel.cpMax) {
- /* Expand to surrounding word */
- TEXTRANGE tr;
- do {
- tr.chrg.cpMax = sel.cpMin;
- tr.chrg.cpMin = --sel.cpMin;
- if (sel.cpMin < 0) break;
- tr.lpstrText = name;
- SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
- } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
- sel.cpMin++;
-
- do {
- tr.chrg.cpMin = sel.cpMax;
- tr.chrg.cpMax = ++sel.cpMax;
- tr.lpstrText = name;
- if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
- } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
- sel.cpMax--;
-
- if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
- MessageBeep(MB_ICONEXCLAMATION);
- return;
- }
- tr.chrg = sel;
- tr.lpstrText = name;
- SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
- } else {
- if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
- MessageBeep(MB_ICONEXCLAMATION);
- return;
- }
- SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
- }
- if (immediate) {
- sprintf(buf, "%s %s", command, name);
- SetWindowText(hInput, buf);
- SendMessage(hInput, WM_CHAR, '\r', 0);
- } else {
- sprintf(buf, "%s %s ", command, name); /* trailing space */
- SetWindowText(hInput, buf);
- sel.cpMin = 999999;
- sel.cpMax = 999999;
- SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
- SetFocus(hInput);
- }
-}
-
-LRESULT CALLBACK
-ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- HWND hInput;
- CHARRANGE sel;
-
- switch (message) {
- case WM_KEYDOWN:
- if (!(GetKeyState(VK_CONTROL) & ~1)) break;
- switch (wParam) {
- case VK_PRIOR:
- SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
- return 0;
- case VK_NEXT:
- sel.cpMin = 999999;
- sel.cpMax = 999999;
- SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
- SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
- return 0;
- }
- break;
- case WM_CHAR:
- if (wParam == '\t') {
- if (GetKeyState(VK_SHIFT) < 0) {
- /* shifted */
- if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
- if (buttonDesc[0].hwnd) {
- SetFocus(buttonDesc[0].hwnd);
- } else {
- SetFocus(hwndMain);
- }
- } else {
- /* unshifted */
- SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
- }
- } else {
- hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
- SetFocus(hInput);
- SendMessage(hInput, message, wParam, lParam);
- }
- return 0;
- case WM_PASTE:
- hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
- SetFocus(hInput);
- return SendMessage(hInput, message, wParam, lParam);
- case WM_MBUTTONDOWN:
- return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
- case WM_RBUTTONDOWN:
- if (!(GetKeyState(VK_SHIFT) & ~1)) {
- /* Move selection here if it was empty */
- POINT pt;
- pt.x = LOWORD(lParam);
- pt.y = HIWORD(lParam);
- SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
- if (sel.cpMin == sel.cpMax) {
- sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
- sel.cpMax = sel.cpMin;
- SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
- }
- SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
- }
- return 0;
- case WM_RBUTTONUP:
- if (GetKeyState(VK_SHIFT) & ~1) {
- SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
- WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
- } else {
- POINT pt;
- HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
- SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
- if (sel.cpMin == sel.cpMax) {
- EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
- EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
- }
- if (!IsClipboardFormatAvailable(CF_TEXT)) {
- EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
- }
- pt.x = LOWORD(lParam);
- pt.y = HIWORD(lParam);
- MenuPopup(hwnd, pt, hmenu, -1);
- }
- return 0;
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDM_QuickPaste:
- {
- SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
- if (sel.cpMin == sel.cpMax) {
- MessageBeep(MB_ICONEXCLAMATION);
- return 0;
- }
- SendMessage(hwnd, WM_COPY, 0, 0);
- hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
- SendMessage(hInput, WM_PASTE, 0, 0);
- SetFocus(hInput);
- return 0;
- }
- case IDM_Cut:
- SendMessage(hwnd, WM_CUT, 0, 0);
- return 0;
- case IDM_Paste:
- SendMessage(hwnd, WM_PASTE, 0, 0);
- return 0;
- case IDM_Copy:
- SendMessage(hwnd, WM_COPY, 0, 0);
- return 0;
- default:
- {
- int i = LOWORD(wParam) - IDM_CommandX;
- if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
- icsTextMenuEntry[i].command != NULL) {
- CommandX(hwnd, icsTextMenuEntry[i].command,
- icsTextMenuEntry[i].getname,
- icsTextMenuEntry[i].immediate);
- return 0;
- }
- }
- break;
- }
- break;
- }
- return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
-}
-
-WNDPROC consoleInputWindowProc;
-
-LRESULT CALLBACK
-ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- char buf[MSG_SIZ];
- char *p;
- static BOOL sendNextChar = FALSE;
- static BOOL quoteNextChar = FALSE;
- InputSource *is = consoleInputSource;
- CHARFORMAT cf;
- CHARRANGE sel;
-
- switch (message) {
- case WM_CHAR:
- if (!appData.localLineEditing || sendNextChar) {
- is->buf[0] = (CHAR) wParam;
- is->count = 1;
- SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
- sendNextChar = FALSE;
- return 0;
- }
- if (quoteNextChar) {
- buf[0] = (char) wParam;
- buf[1] = NULLCHAR;
- SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
- quoteNextChar = FALSE;
- return 0;
- }
- switch (wParam) {
- case '\r': /* Enter key */
- is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
- if (consoleEcho) SaveInHistory(is->buf);
- is->buf[is->count++] = '\n';
- is->buf[is->count] = NULLCHAR;
- SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
- if (consoleEcho) {
- ConsoleOutput(is->buf, is->count, TRUE);
- } else if (appData.localLineEditing) {
- ConsoleOutput("\n", 1, TRUE);
- }
- /* fall thru */
- case '\033': /* Escape key */
- SetWindowText(hwnd, "");
- cf.cbSize = sizeof(CHARFORMAT);
- cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
- if (consoleEcho) {
- cf.crTextColor = textAttribs[ColorNormal].color;
- } else {
- cf.crTextColor = COLOR_ECHOOFF;
- }
- cf.dwEffects = textAttribs[ColorNormal].effects;
- SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
- return 0;
- case '\t': /* Tab key */
- if (GetKeyState(VK_SHIFT) < 0) {
- /* shifted */
- SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
- } else {
- /* unshifted */
- if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
- if (buttonDesc[0].hwnd) {
- SetFocus(buttonDesc[0].hwnd);
- } else {
- SetFocus(hwndMain);
- }
- }
- return 0;
- case '\023': /* Ctrl+S */
- sendNextChar = TRUE;
- return 0;
- case '\021': /* Ctrl+Q */
- quoteNextChar = TRUE;
- return 0;
- default:
- break;
- }
- break;
- case WM_KEYDOWN:
- switch (wParam) {
- case VK_UP:
- GetWindowText(hwnd, buf, MSG_SIZ);
- p = PrevInHistory(buf);
- if (p != NULL) {
- SetWindowText(hwnd, p);
- sel.cpMin = 999999;
- sel.cpMax = 999999;
- SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
- return 0;
- }
- break;
- case VK_DOWN:
- p = NextInHistory();
- if (p != NULL) {
- SetWindowText(hwnd, p);
- sel.cpMin = 999999;
- sel.cpMax = 999999;
- SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
- return 0;
- }
- break;
- case VK_HOME:
- case VK_END:
- if (!(GetKeyState(VK_CONTROL) & ~1)) break;
- /* fall thru */
- case VK_PRIOR:
- case VK_NEXT:
- SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
- return 0;
- }
- break;
- case WM_MBUTTONDOWN:
- SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
- WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
- break;
- case WM_RBUTTONUP:
- if (GetKeyState(VK_SHIFT) & ~1) {
- SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
- WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
- } else {
- POINT pt;
- HMENU hmenu;
- hmenu = LoadMenu(hInst, "InputMenu");
- SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
- if (sel.cpMin == sel.cpMax) {
- EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
- EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
- }
- if (!IsClipboardFormatAvailable(CF_TEXT)) {
- EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
- }
- pt.x = LOWORD(lParam);
- pt.y = HIWORD(lParam);
- MenuPopup(hwnd, pt, hmenu, -1);
- }
- return 0;
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDM_Undo:
- SendMessage(hwnd, EM_UNDO, 0, 0);
- return 0;
- case IDM_SelectAll:
- sel.cpMin = 0;
- sel.cpMax = -1; /*999999?*/
- SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
- return 0;
- case IDM_Cut:
- SendMessage(hwnd, WM_CUT, 0, 0);
- return 0;
- case IDM_Paste:
- SendMessage(hwnd, WM_PASTE, 0, 0);
- return 0;
- case IDM_Copy:
- SendMessage(hwnd, WM_COPY, 0, 0);
- return 0;
- }
- break;
- }
- return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
-}
-
-#define CO_MAX 100000
-#define CO_TRIM 1000
-
-LRESULT CALLBACK
-ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- static HWND hText, hInput, hFocus;
- InputSource *is = consoleInputSource;
- RECT rect;
- static int sizeX, sizeY;
- int newSizeX, newSizeY;
- MINMAXINFO *mmi;
-
- switch (message) {
- case WM_INITDIALOG: /* message: initialize dialog box */
- hwndConsole = hDlg;
- hText = GetDlgItem(hDlg, OPT_ConsoleText);
- hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
- SetFocus(hInput);
- consoleTextWindowProc = (WNDPROC)
- SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
- SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
- consoleInputWindowProc = (WNDPROC)
- SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
- SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
- Colorize(ColorNormal, TRUE);
- SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
- ChangedConsoleFont();
- GetClientRect(hDlg, &rect);
- sizeX = rect.right;
- sizeY = rect.bottom;
- if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
- consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
- WINDOWPLACEMENT wp;
- EnsureOnScreen(&consoleX, &consoleY);
- wp.length = sizeof(WINDOWPLACEMENT);
- wp.flags = 0;
- wp.showCmd = SW_SHOW;
- wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
- wp.rcNormalPosition.left = consoleX;
- wp.rcNormalPosition.right = consoleX + consoleW;
- wp.rcNormalPosition.top = consoleY;
- wp.rcNormalPosition.bottom = consoleY + consoleH;
- SetWindowPlacement(hDlg, &wp);
- }
- return FALSE;
-
- case WM_SETFOCUS:
- SetFocus(hInput);
- return 0;
-
- case WM_CLOSE:
- ExitEvent(0);
- /* not reached */
- break;
-
- case WM_SIZE:
- if (IsIconic(hDlg)) break;
- newSizeX = LOWORD(lParam);
- newSizeY = HIWORD(lParam);
- if (sizeX != newSizeX || sizeY != newSizeY) {
- RECT rectText, rectInput;
- POINT pt;
- int newTextHeight, newTextWidth;
- GetWindowRect(hText, &rectText);
- newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
- newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
- if (newTextHeight < 0) {
- newSizeY += -newTextHeight;
- newTextHeight = 0;
- }
- SetWindowPos(hText, NULL, 0, 0,
- newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
- GetWindowRect(hInput, &rectInput); /* gives screen coords */
- pt.x = rectInput.left;
- pt.y = rectInput.top + newSizeY - sizeY;
- ScreenToClient(hDlg, &pt);
- SetWindowPos(hInput, NULL,
- pt.x, pt.y, /* needs client coords */
- rectInput.right - rectInput.left + newSizeX - sizeX,
- rectInput.bottom - rectInput.top, SWP_NOZORDER);
- }
- sizeX = newSizeX;
- sizeY = newSizeY;
- break;
-
- case WM_GETMINMAXINFO:
- /* Prevent resizing window too small */
- mmi = (MINMAXINFO *) lParam;
- mmi->ptMinTrackSize.x = 100;
- mmi->ptMinTrackSize.y = 100;
- break;
- }
- return DefWindowProc(hDlg, message, wParam, lParam);
-}
-
-
-VOID
-ConsoleCreate()
-{
- HWND hCons;
- if (hwndConsole) return;
- hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
- SendMessage(hCons, WM_INITDIALOG, 0, 0);
-}
-
-
-VOID
-ConsoleOutput(char* data, int length, int forceVisible)
-{
- HWND hText;
- int trim, exlen;
- char *p, *q;
- char buf[CO_MAX+1];
- POINT pEnd;
- RECT rect;
- static int delayLF = 0;
- CHARRANGE savesel, sel;
-
- if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
- p = data;
- q = buf;
- if (delayLF) {
- *q++ = '\r';
- *q++ = '\n';
- delayLF = 0;
- }
- while (length--) {
- if (*p == '\n') {
- if (*++p) {
- *q++ = '\r';
- *q++ = '\n';
- } else {
- delayLF = 1;
- }
- } else if (*p == '\007') {
- MyPlaySound(&sounds[(int)SoundBell]);
- p++;
- } else {
- *q++ = *p++;
- }
- }
- *q = NULLCHAR;
- hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
- SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
- /* Save current selection */
- SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
- exlen = GetWindowTextLength(hText);
- /* Find out whether current end of text is visible */
- SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
- SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
- /* Trim existing text if it's too long */
- if (exlen + (q - buf) > CO_MAX) {
- trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
- sel.cpMin = 0;
- sel.cpMax = trim;
- SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
- SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
- exlen -= trim;
- savesel.cpMin -= trim;
- savesel.cpMax -= trim;
- if (exlen < 0) exlen = 0;
- if (savesel.cpMin < 0) savesel.cpMin = 0;
- if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
- }
- /* Append the new text */
- sel.cpMin = exlen;
- sel.cpMax = exlen;
- SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
- SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
- SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
- if (forceVisible || exlen == 0 ||
- (rect.left <= pEnd.x && pEnd.x < rect.right &&
- rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
- /* Scroll to make new end of text visible if old end of text
- was visible or new text is an echo of user typein */
- sel.cpMin = 9999999;
- sel.cpMax = 9999999;
- SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
- SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
- SendMessage(hText, EM_SCROLLCARET, 0, 0);
- SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
- }
- if (savesel.cpMax == exlen || forceVisible) {
- /* Move insert point to new end of text if it was at the old
- end of text or if the new text is an echo of user typein */
- sel.cpMin = 9999999;
- sel.cpMax = 9999999;
- SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
- } else {
- /* Restore previous selection */
- SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
- }
- SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
-}
-
-/*---------*/
-
-
-void
-DisplayAClock(HDC hdc, int timeRemaining, int highlight,
- RECT *rect, char *color)
-{
- char buf[100];
- char *str;
- COLORREF oldFg, oldBg;
- HFONT oldFont;
-
- if (appData.clockMode) {
- if (tinyLayout)
- sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));
- else
- sprintf(buf, "%s: %s", color, TimeString(timeRemaining));
- str = buf;
- } else {
- str = color;
- }
-
- if (highlight) {
- oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
- oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
- } else {
- oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
- oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
- }
- oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
-
- ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
- rect->top, ETO_CLIPPED|ETO_OPAQUE,
- rect, str, strlen(str), NULL);
-
- (void) SetTextColor(hdc, oldFg);
- (void) SetBkColor(hdc, oldBg);
- (void) SelectObject(hdc, oldFont);
-}
-
-
-int
-DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
- OVERLAPPED *ovl)
-{
- int ok, err;
-
- ResetEvent(ovl->hEvent);
- ovl->Offset = ovl->OffsetHigh = 0;
- ok = ReadFile(hFile, buf, count, outCount, ovl);
- if (ok) {
- err = NO_ERROR;
- } else {
- err = GetLastError();
- if (err == ERROR_IO_PENDING) {
- ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
- if (ok)
- err = NO_ERROR;
- else
- err = GetLastError();
- }
- }
- return err;
-}
-
-int
-DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
- OVERLAPPED *ovl)
-{
- int ok, err;
-
- ResetEvent(ovl->hEvent);
- ovl->Offset = ovl->OffsetHigh = 0;
- ok = WriteFile(hFile, buf, count, outCount, ovl);
- if (ok) {
- err = NO_ERROR;
- } else {
- err = GetLastError();
- if (err == ERROR_IO_PENDING) {
- ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
- if (ok)
- err = NO_ERROR;
- else
- err = GetLastError();
- }
- }
- return err;
-}
-
-
-DWORD
-InputThread(LPVOID arg)
-{
- InputSource *is;
- OVERLAPPED ovl;
-
- is = (InputSource *) arg;
- ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
- while (is->hThread != NULL) {
- is->error = DoReadFile(is->hFile, is->next,
- INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
- &is->count, &ovl);
- if (is->error == NO_ERROR) {
- is->next += is->count;
- } else {
- if (is->error == ERROR_BROKEN_PIPE) {
- /* Correct for MS brain damage. EOF reading a pipe is not an error. */
- is->count = 0;
- } else {
- is->count = (DWORD) -1;
- }
- }
- SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
- if (is->count <= 0) break; /* Quit on EOF or error */
- }
- CloseHandle(ovl.hEvent);
- CloseHandle(is->hFile);
- return 0;
-}
-
-
-/* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
-DWORD
-NonOvlInputThread(LPVOID arg)
-{
- InputSource *is;
- char *p, *q;
- int i;
- char prev;
-
- is = (InputSource *) arg;
- while (is->hThread != NULL) {
- is->error = ReadFile(is->hFile, is->next,
- INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
- &is->count, NULL) ? NO_ERROR : GetLastError();
- if (is->error == NO_ERROR) {
- /* Change CRLF to LF */
- if (is->next > is->buf) {
- p = is->next - 1;
- i = is->count + 1;
- } else {
- p = is->next;
- i = is->count;
- }
- q = p;
- prev = NULLCHAR;
- while (i > 0) {
- if (prev == '\r' && *p == '\n') {
- *(q-1) = '\n';
- is->count--;
- } else {
- *q++ = *p;
- }
- prev = *p++;
- i--;
- }
- *q = NULLCHAR;
- is->next = q;
- } else {
- if (is->error == ERROR_BROKEN_PIPE) {
- /* Correct for MS brain damage. EOF reading a pipe is not an error. */
- is->count = 0;
- } else {
- is->count = (DWORD) -1;
- }
- }
- SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
- if (is->count < 0) break; /* Quit on error */
- }
- CloseHandle(is->hFile);
- return 0;
-}
-
-DWORD
-SocketInputThread(LPVOID arg)
-{
- InputSource *is;
-
- is = (InputSource *) arg;
- while (is->hThread != NULL) {
- is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
- if ((int)is->count == SOCKET_ERROR) {
- is->count = (DWORD) -1;
- is->error = WSAGetLastError();
- } else {
- is->error = NO_ERROR;
- is->next += is->count;
- if (is->count == 0 && is->second == is) {
- /* End of file on stderr; quit with no message */
- break;
- }
- }
- SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
- if (is->count <= 0) break; /* Quit on EOF or error */
- }
- return 0;
-}
-
-VOID
-InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- InputSource *is;
-
- is = (InputSource *) lParam;
- if (is->lineByLine) {
- /* Feed in lines one by one */
- char *p = is->buf;
- char *q = p;
- while (q < is->next) {
- if (*q++ == '\n') {
- (is->func)(is, is->closure, p, q - p, NO_ERROR);
- p = q;
- }
- }
- /* Move any partial line to the start of the buffer */
- q = is->buf;
- while (p < is->next) {
- *q++ = *p++;
- }
- is->next = q;
- if (is->error != NO_ERROR || is->count == 0) {
- /* Notify backend of the error. Note: If there was a partial
- line at the end, it is not flushed through. */
- (is->func)(is, is->closure, is->buf, is->count, is->error);
- }
- } else {
- /* Feed in the whole chunk of input at once */
- (is->func)(is, is->closure, is->buf, is->count, is->error);
- is->next = is->buf;
- }
-}
-
-/*---------------------------------------------------------------------------*\
- *
- * Menu enables. Used when setting various modes.
- *
-\*---------------------------------------------------------------------------*/
-
-typedef struct {
- int item;
- int flags;
-} Enables;
-
-VOID
-SetMenuEnables(HMENU hmenu, Enables *enab)
-{
- while (enab->item > 0) {
- (void) EnableMenuItem(hmenu, enab->item, enab->flags);
- enab++;
- }
-}
-
-Enables gnuEnables[] = {
- { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
- { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
- { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
- { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
- { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
- { -1, -1 }
-};
-
-Enables icsEnables[] = {
- { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
- { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
- { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
- { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
- { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
- { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
- { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
- { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
- { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
- { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
- { -1, -1 }
-};
-
-#ifdef ZIPPY
-Enables zippyEnables[] = {
- { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
- { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
- { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
- { -1, -1 }
-};
-#endif
-
-Enables ncpEnables[] = {
- { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
- { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
- { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
- { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
- { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
- { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
- { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
- { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
- { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
- { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
- { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
- { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
- { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
- { -1, -1 }
-};
-
-Enables trainingOnEnables[] = {
- { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
- { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
- { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
- { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
- { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
- { -1, -1 }
-};
-
-Enables trainingOffEnables[] = {
- { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
- { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
- { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
- { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
- { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
- { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
- { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
- { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
- { -1, -1 }
-};
-
-/* These modify either ncpEnables or gnuEnables */
-Enables cmailEnables[] = {
- { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
- { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
- { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
- { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
- { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
- { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
- { -1, -1 }
-};
-
-Enables machineThinkingEnables[] = {
- { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
- { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
- { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
- { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
- { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
- { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
- { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
- { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
- { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
- { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
- { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
- { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
- { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
- { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
- { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
- { -1, -1 }
-};
-
-Enables userThinkingEnables[] = {
- { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
- { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
- { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
- { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
- { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
- { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
- { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
- { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
- { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
- { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
- { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
- { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
- { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
- { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
- { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
- { -1, -1 }
-};
-
-/*---------------------------------------------------------------------------*\
- *
- * Front-end interface functions exported by XBoard.
- * Functions appear in same order as prototypes in frontend.h.
- *
-\*---------------------------------------------------------------------------*/
-VOID
-ModeHighlight()
-{
- static UINT prevChecked = 0;
- static int prevPausing = 0;
- UINT nowChecked;
-
- if (pausing != prevPausing) {
- prevPausing = pausing;
- (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
- MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
- if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
- }
-
- switch (gameMode) {
- case BeginningOfGame:
- if (appData.icsActive)
- nowChecked = IDM_IcsClient;
- else if (appData.noChessProgram)
- nowChecked = IDM_EditGame;
- else
- nowChecked = IDM_MachineBlack;
- break;
- case MachinePlaysBlack:
- nowChecked = IDM_MachineBlack;
- break;
- case MachinePlaysWhite:
- nowChecked = IDM_MachineWhite;
- break;
- case TwoMachinesPlay:
- nowChecked = IDM_TwoMachines;
- break;
- case AnalyzeMode:
- nowChecked = IDM_AnalysisMode;
- break;
- case AnalyzeFile:
- nowChecked = IDM_AnalyzeFile;
- break;
- case EditGame:
- nowChecked = IDM_EditGame;
- break;
- case PlayFromGameFile:
- nowChecked = IDM_LoadGame;
- break;
- case EditPosition:
- nowChecked = IDM_EditPosition;
- break;
- case Training:
- nowChecked = IDM_Training;
- break;
- case IcsPlayingWhite:
- case IcsPlayingBlack:
- case IcsObserving:
- case IcsIdle:
- nowChecked = IDM_IcsClient;
- break;
- default:
- case EndOfGame:
- nowChecked = 0;
- break;
- }
- if (prevChecked != 0)
- (void) CheckMenuItem(GetMenu(hwndMain),
- prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
- if (nowChecked != 0)
- (void) CheckMenuItem(GetMenu(hwndMain),
- nowChecked, MF_BYCOMMAND|MF_CHECKED);
-
- if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
- (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
- MF_BYCOMMAND|MF_ENABLED);
- } else {
- (void) EnableMenuItem(GetMenu(hwndMain),
- IDM_Training, MF_BYCOMMAND|MF_GRAYED);
- }
-
- prevChecked = nowChecked;
-
- /* icsEngineAnalyze - Do a sceure check too */
- if (appData.icsActive) {
- if (appData.icsEngineAnalyze) {
- (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
- MF_BYCOMMAND|MF_CHECKED);
- } else {
- (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
- MF_BYCOMMAND|MF_UNCHECKED);
- }
- }
-}
-
-VOID
-SetICSMode()
-{
- HMENU hmenu = GetMenu(hwndMain);
- SetMenuEnables(hmenu, icsEnables);
- EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
- MF_BYPOSITION|MF_ENABLED);
-#ifdef ZIPPY
- if (appData.zippyPlay) {
- SetMenuEnables(hmenu, zippyEnables);
- /* icsEngineAnalyze */
- if (!appData.noChessProgram)
- (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
- MF_BYCOMMAND|MF_ENABLED);
- }
-#endif
-}
-
-VOID
-SetGNUMode()
-{
- SetMenuEnables(GetMenu(hwndMain), gnuEnables);
-}
-
-VOID
-SetNCPMode()
-{
- HMENU hmenu = GetMenu(hwndMain);
- SetMenuEnables(hmenu, ncpEnables);
- EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
- MF_BYPOSITION|MF_GRAYED);
- DrawMenuBar(hwndMain);
-}
-
-VOID
-SetCmailMode()
-{
- SetMenuEnables(GetMenu(hwndMain), cmailEnables);
-}
-
-VOID
-SetTrainingModeOn()
-{
- int i;
- SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
- for (i = 0; i < N_BUTTONS; i++) {
- if (buttonDesc[i].hwnd != NULL)
- EnableWindow(buttonDesc[i].hwnd, FALSE);
- }
- CommentPopDown();
-}
-
-VOID SetTrainingModeOff()
-{
- int i;
- SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
- for (i = 0; i < N_BUTTONS; i++) {
- if (buttonDesc[i].hwnd != NULL)
- EnableWindow(buttonDesc[i].hwnd, TRUE);
- }
-}
-
-
-VOID
-SetUserThinkingEnables()
-{
- SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
-}
-
-VOID
-SetMachineThinkingEnables()
-{
- HMENU hMenu = GetMenu(hwndMain);
- int flags = MF_BYCOMMAND|MF_ENABLED;
-
- SetMenuEnables(hMenu, machineThinkingEnables);
-
- if (gameMode == MachinePlaysBlack) {
- (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
- } else if (gameMode == MachinePlaysWhite) {
- (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
- } else if (gameMode == TwoMachinesPlay) {
- (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
- }
-}
-
-
-VOID
-DisplayTitle(char *str)
-{
- char title[MSG_SIZ], *host;
- if (str[0] != NULLCHAR) {
- strcpy(title, str);
- } else if (appData.icsActive) {
- if (appData.icsCommPort[0] != NULLCHAR)
- host = "ICS";
- else
- host = appData.icsHost;
- sprintf(title, "%s: %s", szTitle, host);
- } else if (appData.noChessProgram) {
- strcpy(title, szTitle);
- } else {
- strcpy(title, szTitle);
- strcat(title, ": ");
- strcat(title, first.tidy);
- }
- SetWindowText(hwndMain, title);
-}
-
-
-VOID
-DisplayMessage(char *str1, char *str2)
-{
- HDC hdc;
- HFONT oldFont;
- int remain = MESSAGE_TEXT_MAX - 1;
- int len;
-
- moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
- messageText[0] = NULLCHAR;
- if (*str1) {
- len = strlen(str1);
- if (len > remain) len = remain;
- strncpy(messageText, str1, len);
- messageText[len] = NULLCHAR;
- remain -= len;
- }
- if (*str2 && remain >= 2) {
- if (*str1) {
- strcat(messageText, " ");
- remain -= 2;
- }
- len = strlen(str2);
- if (len > remain) len = remain;
- strncat(messageText, str2, len);
- }
- messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
-
- if (IsIconic(hwndMain)) return;
- hdc = GetDC(hwndMain);
- oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
- ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
- &messageRect, messageText, strlen(messageText), NULL);
- (void) SelectObject(hdc, oldFont);
- (void) ReleaseDC(hwndMain, hdc);
-}
-
-VOID
-DisplayError(char *str, int error)
-{
- char buf[MSG_SIZ*2], buf2[MSG_SIZ];
- int len;
-
- if (error == 0) {
- strcpy(buf, str);
- } else {
- len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, error, LANG_NEUTRAL,
- (LPSTR) buf2, MSG_SIZ, NULL);
- if (len > 0) {
- sprintf(buf, "%s:\n%s", str, buf2);
- } else {
- ErrorMap *em = errmap;
- while (em->err != 0 && em->err != error) em++;
- if (em->err != 0) {
- sprintf(buf, "%s:\n%s", str, em->msg);
- } else {
- sprintf(buf, "%s:\nError code %d", str, error);
- }
- }
- }
-
- ErrorPopUp("Error", buf);
-}
-
-
-VOID
-DisplayMoveError(char *str)
-{
- fromX = fromY = -1;
- ClearHighlights();
- DrawPosition(FALSE, NULL);
- if (appData.popupMoveErrors) {
- ErrorPopUp("Error", str);
- } else {
- DisplayMessage(str, "");
- moveErrorMessageUp = TRUE;
- }
-}
-
-VOID
-DisplayFatalError(char *str, int error, int exitStatus)
-{
- char buf[2*MSG_SIZ], buf2[MSG_SIZ];
- int len;
- char *label = exitStatus ? "Fatal Error" : "Exiting";
-
- if (error != 0) {
- len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, error, LANG_NEUTRAL,
- (LPSTR) buf2, MSG_SIZ, NULL);
- if (len > 0) {
- sprintf(buf, "%s:\n%s", str, buf2);
- } else {
- ErrorMap *em = errmap;
- while (em->err != 0 && em->err != error) em++;
- if (em->err != 0) {
- sprintf(buf, "%s:\n%s", str, em->msg);
- } else {
- sprintf(buf, "%s:\nError code %d", str, error);
- }
- }
- str = buf;
- }
- if (appData.debugMode) {
- fprintf(debugFP, "%s: %s\n", label, str);
- }
- if (appData.popupExitMessage) {
- (void) MessageBox(hwndMain, str, label, MB_OK|
- (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
- }
- ExitEvent(exitStatus);
-}
-
-
-VOID
-DisplayInformation(char *str)
-{
- (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
-}
-
-
-VOID
-DisplayNote(char *str)
-{
- ErrorPopUp("Note", str);
-}
-
-
-typedef struct {
- char *title, *question, *replyPrefix;
- ProcRef pr;
-} QuestionParams;
-
-LRESULT CALLBACK
-QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- static QuestionParams *qp;
- char reply[MSG_SIZ];
- int len, err;
-
- switch (message) {
- case WM_INITDIALOG:
- qp = (QuestionParams *) lParam;
- CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
- SetWindowText(hDlg, qp->title);
- SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
- SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
- return FALSE;
-
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- strcpy(reply, qp->replyPrefix);
- if (*reply) strcat(reply, " ");
- len = strlen(reply);
- GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
- strcat(reply, "\n");
- OutputToProcess(qp->pr, reply, strlen(reply), &err);
- EndDialog(hDlg, TRUE);
- if (err) DisplayFatalError("Error writing to chess program", err, 1);
- return TRUE;
- case IDCANCEL:
- EndDialog(hDlg, FALSE);
- return TRUE;
- default:
- break;
- }
- break;
- }
- return FALSE;
-}
-
-VOID
-AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
-{
- QuestionParams qp;
- FARPROC lpProc;
-
- qp.title = title;
- qp.question = question;
- qp.replyPrefix = replyPrefix;
- qp.pr = pr;
- lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
- DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
- hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
- FreeProcInstance(lpProc);
-}
-
-
-VOID
-DisplayIcsInteractionTitle(char *str)
-{
- char consoleTitle[MSG_SIZ];
-
- sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
- SetWindowText(hwndConsole, consoleTitle);
-}
-
-void
-DrawPosition(int fullRedraw, Board board)
-{
- HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
-}
-
-
-VOID
-ResetFrontEnd()
-{
- fromX = fromY = -1;
- if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
- dragInfo.pos.x = dragInfo.pos.y = -1;
- dragInfo.pos.x = dragInfo.pos.y = -1;
- dragInfo.lastpos = dragInfo.pos;
- dragInfo.start.x = dragInfo.start.y = -1;
- dragInfo.from = dragInfo.start;
- ReleaseCapture();
- DrawPosition(TRUE, NULL);
- }
-}
-
-
-VOID
-CommentPopUp(char *title, char *str)
-{
- HWND hwnd = GetActiveWindow();
- EitherCommentPopUp(0, title, str, FALSE);
- SetActiveWindow(hwnd);
-}
-
-VOID
-CommentPopDown(void)
-{
- CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
- if (commentDialog) {
- ShowWindow(commentDialog, SW_HIDE);
- }
- commentDialogUp = FALSE;
-}
-
-VOID
-EditCommentPopUp(int index, char *title, char *str)
-{
- EitherCommentPopUp(index, title, str, TRUE);
-}
-
-
-VOID
-RingBell()
-{
- MyPlaySound(&sounds[(int)SoundMove]);
-}
-
-VOID PlayIcsWinSound()
-{
- MyPlaySound(&sounds[(int)SoundIcsWin]);
-}
-
-VOID PlayIcsLossSound()
-{
- MyPlaySound(&sounds[(int)SoundIcsLoss]);
-}
-
-VOID PlayIcsDrawSound()
-{
- MyPlaySound(&sounds[(int)SoundIcsDraw]);
-}
-
-VOID PlayIcsUnfinishedSound()
-{
- MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
-}
-
-VOID
-PlayAlarmSound()
-{
- MyPlaySound(&sounds[(int)SoundAlarm]);
-}
-
-
-VOID
-EchoOn()
-{
- HWND hInput;
- consoleEcho = TRUE;
- hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
- SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
- SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
-}
-
-
-VOID
-EchoOff()
-{
- CHARFORMAT cf;
- HWND hInput;
- consoleEcho = FALSE;
- hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
- /* This works OK: set text and background both to the same color */
- cf = consoleCF;
- cf.crTextColor = COLOR_ECHOOFF;
- SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
- SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
-}
-
-/* No Raw()...? */
-
-void Colorize(ColorClass cc, int continuation)
-{
- currentColorClass = cc;
- consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
- consoleCF.crTextColor = textAttribs[cc].color;
- consoleCF.dwEffects = textAttribs[cc].effects;
- if (!continuation) MyPlaySound(&textAttribs[cc].sound);
-}
-
-char *
-UserName()
-{
- static char buf[MSG_SIZ];
- DWORD bufsiz = MSG_SIZ;
-
- if (!GetUserName(buf, &bufsiz)) {
- /*DisplayError("Error getting user name", GetLastError());*/
- strcpy(buf, "User");
- }
- return buf;
-}
-
-char *
-HostName()
-{
- static char buf[MSG_SIZ];
- DWORD bufsiz = MSG_SIZ;
-
- if (!GetComputerName(buf, &bufsiz)) {
- /*DisplayError("Error getting host name", GetLastError());*/
- strcpy(buf, "Unknown");
- }
- return buf;
-}
-
-
-int
-ClockTimerRunning()
-{
- return clockTimerEvent != 0;
-}
-
-int
-StopClockTimer()
-{
- if (clockTimerEvent == 0) return FALSE;
- KillTimer(hwndMain, clockTimerEvent);
- clockTimerEvent = 0;
- return TRUE;
-}
-
-void
-StartClockTimer(long millisec)
-{
- clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
- (UINT) millisec, NULL);
-}
-
-void
-DisplayWhiteClock(long timeRemaining, int highlight)
-{
- HDC hdc;
- hdc = GetDC(hwndMain);
- if (!IsIconic(hwndMain)) {
- DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");
- }
- if (highlight && iconCurrent == iconBlack) {
- iconCurrent = iconWhite;
- PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
- if (IsIconic(hwndMain)) {
- DrawIcon(hdc, 2, 2, iconCurrent);
- }
- }
- (void) ReleaseDC(hwndMain, hdc);
- if (hwndConsole)
- PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
-}
-
-void
-DisplayBlackClock(long timeRemaining, int highlight)
-{
- HDC hdc;
- hdc = GetDC(hwndMain);
- if (!IsIconic(hwndMain)) {
- DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");
- }
- if (highlight && iconCurrent == iconWhite) {
- iconCurrent = iconBlack;
- PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
- if (IsIconic(hwndMain)) {
- DrawIcon(hdc, 2, 2, iconCurrent);
- }
- }
- (void) ReleaseDC(hwndMain, hdc);
- if (hwndConsole)
- PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
-}
-
-
-int
-LoadGameTimerRunning()
-{
- return loadGameTimerEvent != 0;
-}
-
-int
-StopLoadGameTimer()
-{
- if (loadGameTimerEvent == 0) return FALSE;
- KillTimer(hwndMain, loadGameTimerEvent);
- loadGameTimerEvent = 0;
- return TRUE;
-}
-
-void
-StartLoadGameTimer(long millisec)
-{
- loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
- (UINT) millisec, NULL);
-}
-
-void
-AutoSaveGame()
-{
- char *defName;
- FILE *f;
- char fileTitle[MSG_SIZ];
-
- defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
- f = OpenFileDialog(hwndMain, TRUE, defName,
- appData.oldSaveStyle ? "gam" : "pgn",
- GAME_FILT,
- "Save Game to File", NULL, fileTitle, NULL);
- if (f != NULL) {
- SaveGame(f, 0, "");
- fclose(f);
- }
-}
-
-
-void
-ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
-{
- if (delayedTimerEvent != 0) {
- if (appData.debugMode) {
- fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
- }
- KillTimer(hwndMain, delayedTimerEvent);
- delayedTimerEvent = 0;
- delayedTimerCallback();
- }
- delayedTimerCallback = cb;
- delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
- (UINT) millisec, NULL);
-}
-
-DelayedEventCallback
-GetDelayedEvent()
-{
- if (delayedTimerEvent) {
- return delayedTimerCallback;
- } else {
- return NULL;
- }
-}
-
-void
-CancelDelayedEvent()
-{
- if (delayedTimerEvent) {
- KillTimer(hwndMain, delayedTimerEvent);
- delayedTimerEvent = 0;
- }
-}
-
-/* Start a child process running the given program.
- The process's standard output can be read from "from", and its
- standard input can be written to "to".
- Exit with fatal error if anything goes wrong.
- Returns an opaque pointer that can be used to destroy the process
- later.
-*/
-int
-StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
-{
-#define BUFSIZE 4096
-
- HANDLE hChildStdinRd, hChildStdinWr,
- hChildStdoutRd, hChildStdoutWr;
- HANDLE hChildStdinWrDup, hChildStdoutRdDup;
- SECURITY_ATTRIBUTES saAttr;
- BOOL fSuccess;
- PROCESS_INFORMATION piProcInfo;
- STARTUPINFO siStartInfo;
- ChildProc *cp;
- char buf[MSG_SIZ];
- DWORD err;
-
- if (appData.debugMode) {
- fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
- }
-
- *pr = NoProc;
-
- /* Set the bInheritHandle flag so pipe handles are inherited. */
- saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
- saAttr.bInheritHandle = TRUE;
- saAttr.lpSecurityDescriptor = NULL;
-
- /*
- * The steps for redirecting child's STDOUT:
- * 1. Create anonymous pipe to be STDOUT for child.
- * 2. Create a noninheritable duplicate of read handle,
- * and close the inheritable read handle.
- */
-
- /* Create a pipe for the child's STDOUT. */
- if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
- return GetLastError();
- }
-
- /* Duplicate the read handle to the pipe, so it is not inherited. */
- fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
- GetCurrentProcess(), &hChildStdoutRdDup, 0,
- FALSE, /* not inherited */
- DUPLICATE_SAME_ACCESS);
- if (! fSuccess) {
- return GetLastError();
- }
- CloseHandle(hChildStdoutRd);
-
- /*
- * The steps for redirecting child's STDIN:
- * 1. Create anonymous pipe to be STDIN for child.
- * 2. Create a noninheritable duplicate of write handle,
- * and close the inheritable write handle.
- */
-
- /* Create a pipe for the child's STDIN. */
- if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
- return GetLastError();
- }
-
- /* Duplicate the write handle to the pipe, so it is not inherited. */
- fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
- GetCurrentProcess(), &hChildStdinWrDup, 0,
- FALSE, /* not inherited */
- DUPLICATE_SAME_ACCESS);
- if (! fSuccess) {
- return GetLastError();
- }
- CloseHandle(hChildStdinWr);
-
- /* Arrange to (1) look in dir for the child .exe file, and
- * (2) have dir be the child's working directory. Interpret
- * dir relative to the directory WinBoard loaded from. */
- GetCurrentDirectory(MSG_SIZ, buf);
- SetCurrentDirectory(installDir);
- SetCurrentDirectory(dir);
-
- /* Now create the child process. */
-
- siStartInfo.cb = sizeof(STARTUPINFO);
- siStartInfo.lpReserved = NULL;
- siStartInfo.lpDesktop = NULL;
- siStartInfo.lpTitle = NULL;
- siStartInfo.dwFlags = STARTF_USESTDHANDLES;
- siStartInfo.cbReserved2 = 0;
- siStartInfo.lpReserved2 = NULL;
- siStartInfo.hStdInput = hChildStdinRd;
- siStartInfo.hStdOutput = hChildStdoutWr;
- siStartInfo.hStdError = hChildStdoutWr;
-
- fSuccess = CreateProcess(NULL,
- cmdLine, /* command line */
- NULL, /* process security attributes */
- NULL, /* primary thread security attrs */
- TRUE, /* handles are inherited */
- DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
- NULL, /* use parent's environment */
- NULL,
- &siStartInfo, /* STARTUPINFO pointer */
- &piProcInfo); /* receives PROCESS_INFORMATION */
-
- err = GetLastError();
- SetCurrentDirectory(buf); /* return to prev directory */
- if (! fSuccess) {
- return err;
- }
-
- /* Close the handles we don't need in the parent */
- CloseHandle(piProcInfo.hThread);
- CloseHandle(hChildStdinRd);
- CloseHandle(hChildStdoutWr);
-
- /* Prepare return value */
- cp = (ChildProc *) calloc(1, sizeof(ChildProc));
- cp->kind = CPReal;
- cp->hProcess = piProcInfo.hProcess;
- cp->pid = piProcInfo.dwProcessId;
- cp->hFrom = hChildStdoutRdDup;
- cp->hTo = hChildStdinWrDup;
-
- *pr = (void *) cp;
-
- /* Klaus Friedel says that this Sleep solves a problem under Windows
- 2000 where engines sometimes don't see the initial command(s)
- from WinBoard and hang. I don't understand how that can happen,
- but the Sleep is harmless, so I've put it in. Others have also
- reported what may be the same problem, so hopefully this will fix
- it for them too. */
- Sleep(500);
-
- return NO_ERROR;
-}
-
-
-void
-DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
-{
- ChildProc *cp;
-
- cp = (ChildProc *) pr;
- if (cp == NULL) return;
-
- switch (cp->kind) {
- case CPReal:
- /* TerminateProcess is considered harmful, so... */
- CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
- if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
- /* The following doesn't work because the chess program
- doesn't "have the same console" as WinBoard. Maybe
- we could arrange for this even though neither WinBoard
- nor the chess program uses a console for stdio? */
- /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
- CloseHandle(cp->hProcess);
- break;
-
- case CPComm:
- if (cp->hFrom) CloseHandle(cp->hFrom);
- break;
-
- case CPSock:
- closesocket(cp->sock);
- WSACleanup();
- break;
-
- case CPRcmd:
- if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
- closesocket(cp->sock);
- closesocket(cp->sock2);
- WSACleanup();
- break;
- }
- free(cp);
-}
-
-void
-InterruptChildProcess(ProcRef pr)
-{
- ChildProc *cp;
-
- cp = (ChildProc *) pr;
- if (cp == NULL) return;
- switch (cp->kind) {
- case CPReal:
- /* The following doesn't work because the chess program
- doesn't "have the same console" as WinBoard. Maybe
- we could arrange for this even though neither WinBoard
- nor the chess program uses a console for stdio */
- /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
- break;
-
- case CPComm:
- case CPSock:
- /* Can't interrupt */
- break;
-
- case CPRcmd:
- send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
- break;
- }
-}
-
-
-int
-OpenTelnet(char *host, char *port, ProcRef *pr)
-{
- char cmdLine[MSG_SIZ];
-
- if (port[0] == NULLCHAR) {
- sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
- } else {
- sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
- }
- return StartChildProcess(cmdLine, "", pr);
-}
-
-
-/* Code to open TCP sockets */
-
-int
-OpenTCP(char *host, char *port, ProcRef *pr)
-{
- ChildProc *cp;
- int err;
- SOCKET s;
- struct sockaddr_in sa, mysa;
- struct hostent FAR *hp;
- unsigned short uport;
- WORD wVersionRequested;
- WSADATA wsaData;
-
- /* Initialize socket DLL */
- wVersionRequested = MAKEWORD(1, 1);
- err = WSAStartup(wVersionRequested, &wsaData);
- if (err != 0) return err;
-
- /* Make socket */
- if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
- err = WSAGetLastError();
- WSACleanup();
- return err;
- }
-
- /* Bind local address using (mostly) don't-care values.
- */
- memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
- mysa.sin_family = AF_INET;
- mysa.sin_addr.s_addr = INADDR_ANY;
- uport = (unsigned short) 0;
- mysa.sin_port = htons(uport);
- if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
- == SOCKET_ERROR) {
- err = WSAGetLastError();
- WSACleanup();
- return err;
- }
-
- /* Resolve remote host name */
- memset((char *) &sa, 0, sizeof(struct sockaddr_in));
- if (!(hp = gethostbyname(host))) {
- unsigned int b0, b1, b2, b3;
-
- err = WSAGetLastError();
-
- if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
- hp = (struct hostent *) calloc(1, sizeof(struct hostent));
- hp->h_addrtype = AF_INET;
- hp->h_length = 4;
- hp->h_addr_list = (char **) calloc(2, sizeof(char *));
- hp->h_addr_list[0] = (char *) malloc(4);
- hp->h_addr_list[0][0] = (char) b0;
- hp->h_addr_list[0][1] = (char) b1;
- hp->h_addr_list[0][2] = (char) b2;
- hp->h_addr_list[0][3] = (char) b3;
- } else {
- WSACleanup();
- return err;
- }
- }
- sa.sin_family = hp->h_addrtype;
- uport = (unsigned short) atoi(port);
- sa.sin_port = htons(uport);
- memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
-
- /* Make connection */
- if (connect(s, (struct sockaddr *) &sa,
- sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
- err = WSAGetLastError();
- WSACleanup();
- return err;
- }
-
- /* Prepare return value */
- cp = (ChildProc *) calloc(1, sizeof(ChildProc));
- cp->kind = CPSock;
- cp->sock = s;
- *pr = (ProcRef *) cp;
-
- return NO_ERROR;
-}
-
-int
-OpenCommPort(char *name, ProcRef *pr)
-{
- HANDLE h;
- COMMTIMEOUTS ct;
- ChildProc *cp;
- char fullname[MSG_SIZ];
-
- if (*name != '\\')
- sprintf(fullname, "\\\\.\\%s", name);
- else
- strcpy(fullname, name);
-
- h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
- 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
- if (h == (HANDLE) -1) {
- return GetLastError();
- }
- hCommPort = h;
-
- if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
-
- /* Accumulate characters until a 100ms pause, then parse */
- ct.ReadIntervalTimeout = 100;
- ct.ReadTotalTimeoutMultiplier = 0;
- ct.ReadTotalTimeoutConstant = 0;
- ct.WriteTotalTimeoutMultiplier = 0;
- ct.WriteTotalTimeoutConstant = 0;
- if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
-
- /* Prepare return value */
- cp = (ChildProc *) calloc(1, sizeof(ChildProc));
- cp->kind = CPComm;
- cp->hFrom = h;
- cp->hTo = h;
- *pr = (ProcRef *) cp;
-
- return NO_ERROR;
-}
-
-int
-OpenLoopback(ProcRef *pr)
-{
- DisplayFatalError("Not implemented", 0, 1);
- return NO_ERROR;
-}
-
-
-int
-OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
-{
- ChildProc *cp;
- int err;
- SOCKET s, s2, s3;
- struct sockaddr_in sa, mysa;
- struct hostent FAR *hp;
- unsigned short uport;
- WORD wVersionRequested;
- WSADATA wsaData;
- int fromPort;
- char stderrPortStr[MSG_SIZ];
-
- /* Initialize socket DLL */
- wVersionRequested = MAKEWORD(1, 1);
- err = WSAStartup(wVersionRequested, &wsaData);
- if (err != 0) return err;
-
- /* Resolve remote host name */
- memset((char *) &sa, 0, sizeof(struct sockaddr_in));
- if (!(hp = gethostbyname(host))) {
- unsigned int b0, b1, b2, b3;
-
- err = WSAGetLastError();
-
- if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
- hp = (struct hostent *) calloc(1, sizeof(struct hostent));
- hp->h_addrtype = AF_INET;
- hp->h_length = 4;
- hp->h_addr_list = (char **) calloc(2, sizeof(char *));
- hp->h_addr_list[0] = (char *) malloc(4);
- hp->h_addr_list[0][0] = (char) b0;
- hp->h_addr_list[0][1] = (char) b1;
- hp->h_addr_list[0][2] = (char) b2;
- hp->h_addr_list[0][3] = (char) b3;
- } else {
- WSACleanup();
- return err;
- }
- }
- sa.sin_family = hp->h_addrtype;
- uport = (unsigned short) 514;
- sa.sin_port = htons(uport);
- memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
-
- /* Bind local socket to unused "privileged" port address
- */
- s = INVALID_SOCKET;
- memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
- mysa.sin_family = AF_INET;
- mysa.sin_addr.s_addr = INADDR_ANY;
- for (fromPort = 1023;; fromPort--) {
- if (fromPort < 0) {
- WSACleanup();
- return WSAEADDRINUSE;
- }
- if (s == INVALID_SOCKET) {
- if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
- err = WSAGetLastError();
- WSACleanup();
- return err;
- }
- }
- uport = (unsigned short) fromPort;
- mysa.sin_port = htons(uport);
- if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
- == SOCKET_ERROR) {
- err = WSAGetLastError();
- if (err == WSAEADDRINUSE) continue;
- WSACleanup();
- return err;
- }
- if (connect(s, (struct sockaddr *) &sa,
- sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
- err = WSAGetLastError();
- if (err == WSAEADDRINUSE) {
- closesocket(s);
- s = -1;
- continue;
- }
- WSACleanup();
- return err;
- }
- break;
- }
-
- /* Bind stderr local socket to unused "privileged" port address
- */
- s2 = INVALID_SOCKET;
- memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
- mysa.sin_family = AF_INET;
- mysa.sin_addr.s_addr = INADDR_ANY;
- for (fromPort = 1023;; fromPort--) {
- if (fromPort == prevStderrPort) continue; // don't reuse port
- if (fromPort < 0) {
- (void) closesocket(s);
- WSACleanup();
- return WSAEADDRINUSE;
- }
- if (s2 == INVALID_SOCKET) {
- if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
- err = WSAGetLastError();
- closesocket(s);
- WSACleanup();
- return err;
- }
- }
- uport = (unsigned short) fromPort;
- mysa.sin_port = htons(uport);
- if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
- == SOCKET_ERROR) {
- err = WSAGetLastError();
- if (err == WSAEADDRINUSE) continue;
- (void) closesocket(s);
- WSACleanup();
- return err;
- }
- if (listen(s2, 1) == SOCKET_ERROR) {
- err = WSAGetLastError();
- if (err == WSAEADDRINUSE) {
- closesocket(s2);
- s2 = INVALID_SOCKET;
- continue;
- }
- (void) closesocket(s);
- (void) closesocket(s2);
- WSACleanup();
- return err;
- }
- break;
- }
- prevStderrPort = fromPort; // remember port used
- sprintf(stderrPortStr, "%d", fromPort);
-
- if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
- err = WSAGetLastError();
- (void) closesocket(s);
- (void) closesocket(s2);
- WSACleanup();
- return err;
- }
-
- if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
- err = WSAGetLastError();
- (void) closesocket(s);
- (void) closesocket(s2);
- WSACleanup();
- return err;
- }
- if (*user == NULLCHAR) user = UserName();
- if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
- err = WSAGetLastError();
- (void) closesocket(s);
- (void) closesocket(s2);
- WSACleanup();
- return err;
- }
- if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
- err = WSAGetLastError();
- (void) closesocket(s);
- (void) closesocket(s2);
- WSACleanup();
- return err;
- }
-
- if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
- err = WSAGetLastError();
- (void) closesocket(s);
- (void) closesocket(s2);
- WSACleanup();
- return err;
- }
- (void) closesocket(s2); /* Stop listening */
-
- /* Prepare return value */
- cp = (ChildProc *) calloc(1, sizeof(ChildProc));
- cp->kind = CPRcmd;
- cp->sock = s;
- cp->sock2 = s3;
- *pr = (ProcRef *) cp;
-
- return NO_ERROR;
-}
-
-
-InputSourceRef
-AddInputSource(ProcRef pr, int lineByLine,
- InputCallback func, VOIDSTAR closure)
-{
- InputSource *is, *is2;
- ChildProc *cp = (ChildProc *) pr;
-
- is = (InputSource *) calloc(1, sizeof(InputSource));
- is->lineByLine = lineByLine;
- is->func = func;
- is->closure = closure;
- is->second = NULL;
- is->next = is->buf;
- if (pr == NoProc) {
- is->kind = CPReal;
- consoleInputSource = is;
- } else {
- is->kind = cp->kind;
- switch (cp->kind) {
- case CPReal:
- is->hFile = cp->hFrom;
- cp->hFrom = NULL; /* now owned by InputThread */
- is->hThread =
- CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
- (LPVOID) is, 0, &is->id);
- break;
-
- case CPComm:
- is->hFile = cp->hFrom;
- cp->hFrom = NULL; /* now owned by InputThread */
- is->hThread =
- CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
- (LPVOID) is, 0, &is->id);
- break;
-
- case CPSock:
- is->sock = cp->sock;
- is->hThread =
- CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
- (LPVOID) is, 0, &is->id);
- break;
-
- case CPRcmd:
- is2 = (InputSource *) calloc(1, sizeof(InputSource));
- *is2 = *is;
- is->sock = cp->sock;
- is->second = is2;
- is2->sock = cp->sock2;
- is2->second = is2;
- is->hThread =
- CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
- (LPVOID) is, 0, &is->id);
- is2->hThread =
- CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
- (LPVOID) is2, 0, &is2->id);
- break;
- }
- }
- return (InputSourceRef) is;
-}
-
-void
-RemoveInputSource(InputSourceRef isr)
-{
- InputSource *is;
-
- is = (InputSource *) isr;
- is->hThread = NULL; /* tell thread to stop */
- CloseHandle(is->hThread);
- if (is->second != NULL) {
- is->second->hThread = NULL;
- CloseHandle(is->second->hThread);
- }
-}
-
-
-int
-OutputToProcess(ProcRef pr, char *message, int count, int *outError)
-{
- DWORD dOutCount;
- int outCount = SOCKET_ERROR;
- ChildProc *cp = (ChildProc *) pr;
- static OVERLAPPED ovl;
-
- if (pr == NoProc) {
- ConsoleOutput(message, count, FALSE);
- return count;
- }
-
- if (ovl.hEvent == NULL) {
- ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- }
- ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
-
- switch (cp->kind) {
- case CPSock:
- case CPRcmd:
- outCount = send(cp->sock, message, count, 0);
- if (outCount == SOCKET_ERROR) {
- *outError = WSAGetLastError();
- } else {
- *outError = NO_ERROR;
- }
- break;
-
- case CPReal:
- if (WriteFile(((ChildProc *)pr)->hTo, message, count,
- &dOutCount, NULL)) {
- *outError = NO_ERROR;
- outCount = (int) dOutCount;
- } else {
- *outError = GetLastError();
- }
- break;
-
- case CPComm:
- *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
- &dOutCount, &ovl);
- if (*outError == NO_ERROR) {
- outCount = (int) dOutCount;
- }
- break;
- }
- return outCount;
-}
-
-int
-OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
- long msdelay)
-{
- /* Ignore delay, not implemented for WinBoard */
- return OutputToProcess(pr, message, count, outError);
-}
-
-
-void
-CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
- char *buf, int count, int error)
-{
- DisplayFatalError("Not implemented", 0, 1);
-}
-
-/* see wgamelist.c for Game List functions */
-/* see wedittags.c for Edit Tags functions */
-
-
-VOID
-ICSInitScript()
-{
- FILE *f;
- char buf[MSG_SIZ];
- char *dummy;
-
- if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
- f = fopen(buf, "r");
- if (f != NULL) {
- ProcessICSInitScript(f);
- fclose(f);
- }
- }
-}
-
-
-VOID
-StartAnalysisClock()
-{
- if (analysisTimerEvent) return;
- analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
- (UINT) 2000, NULL);
-}
-
-LRESULT CALLBACK
-AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- static HANDLE hwndText;
- RECT rect;
- static int sizeX, sizeY;
- int newSizeX, newSizeY, flags;
- MINMAXINFO *mmi;
-
- switch (message) {
- case WM_INITDIALOG: /* message: initialize dialog box */
- /* Initialize the dialog items */
- hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
- SetWindowText(hDlg, analysisTitle);
- SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
- /* Size and position the dialog */
- if (!analysisDialog) {
- analysisDialog = hDlg;
- flags = SWP_NOZORDER;
- GetClientRect(hDlg, &rect);
- sizeX = rect.right;
- sizeY = rect.bottom;
- if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
- analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
- WINDOWPLACEMENT wp;
- EnsureOnScreen(&analysisX, &analysisY);
- wp.length = sizeof(WINDOWPLACEMENT);
- wp.flags = 0;
- wp.showCmd = SW_SHOW;
- wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
- wp.rcNormalPosition.left = analysisX;
- wp.rcNormalPosition.right = analysisX + analysisW;
- wp.rcNormalPosition.top = analysisY;
- wp.rcNormalPosition.bottom = analysisY + analysisH;
- SetWindowPlacement(hDlg, &wp);
-
- GetClientRect(hDlg, &rect);
- newSizeX = rect.right;
- newSizeY = rect.bottom;
- ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
- newSizeX, newSizeY);
- sizeX = newSizeX;
- sizeY = newSizeY;
- }
- }
- return FALSE;
-
- case WM_COMMAND: /* message: received a command */
- switch (LOWORD(wParam)) {
- case IDCANCEL:
- /* icsEngineAnalyze */
- if (appData.icsActive && appData.icsEngineAnalyze) {
- ExitAnalyzeMode();
- ModeHighlight();
- return TRUE;
- }
- EditGameEvent();
- return TRUE;
- default:
- break;
- }
- break;
-
- case WM_SIZE:
- newSizeX = LOWORD(lParam);
- newSizeY = HIWORD(lParam);
- ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
- sizeX = newSizeX;
- sizeY = newSizeY;
- break;
-
- case WM_GETMINMAXINFO:
- /* Prevent resizing window too small */
- mmi = (MINMAXINFO *) lParam;
- mmi->ptMinTrackSize.x = 100;
- mmi->ptMinTrackSize.y = 100;
- break;
- }
- return FALSE;
-}
-
-VOID
-AnalysisPopUp(char* title, char* str)
-{
- FARPROC lpProc;
- char *p, *q;
-
- if (str == NULL) str = "";
- p = (char *) malloc(2 * strlen(str) + 2);
- q = p;
- while (*str) {
- if (*str == '\n') *q++ = '\r';
- *q++ = *str++;
- }
- *q = NULLCHAR;
- if (analysisText != NULL) free(analysisText);
- analysisText = p;
-
- if (analysisDialog) {
- SetWindowText(analysisDialog, title);
- SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
- ShowWindow(analysisDialog, SW_SHOW);
- } else {
- analysisTitle = title;
- lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
- CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
- hwndMain, (DLGPROC)lpProc);
- FreeProcInstance(lpProc);
- }
- analysisDialogUp = TRUE;
-}
-
-VOID
-AnalysisPopDown()
-{
- if (analysisDialog) {
- ShowWindow(analysisDialog, SW_HIDE);
- }
- analysisDialogUp = FALSE;
-}
-
-
-VOID
-SetHighlights(int fromX, int fromY, int toX, int toY)
-{
- highlightInfo.sq[0].x = fromX;
- highlightInfo.sq[0].y = fromY;
- highlightInfo.sq[1].x = toX;
- highlightInfo.sq[1].y = toY;
-}
-
-VOID
-ClearHighlights()
-{
- highlightInfo.sq[0].x = highlightInfo.sq[0].y =
- highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
-}
-
-VOID
-SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
-{
- premoveHighlightInfo.sq[0].x = fromX;
- premoveHighlightInfo.sq[0].y = fromY;
- premoveHighlightInfo.sq[1].x = toX;
- premoveHighlightInfo.sq[1].y = toY;
-}
-
-VOID
-ClearPremoveHighlights()
-{
- premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
- premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
-}
-
-VOID
-ShutDownFrontEnd()
-{
- if (saveSettingsOnExit) SaveSettings(settingsFileName);
- DeleteClipboardTempFiles();
-}
-
-void
-BoardToTop()
-{
- if (IsIconic(hwndMain))
- ShowWindow(hwndMain, SW_RESTORE);
-
- SetActiveWindow(hwndMain);
-}
-
-/*
- * Prototypes for animation support routines
- */
-static void ScreenSquare(int column, int row, POINT * pt);
-static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
- POINT frames[], int * nFrames);
-
-
-#define kFactor 4
-
-void
-AnimateMove(board, fromX, fromY, toX, toY)
- Board board;
- int fromX;
- int fromY;
- int toX;
- int toY;
-{
- ChessSquare piece;
- POINT start, finish, mid;
- POINT frames[kFactor * 2 + 1];
- int nFrames, n;
-
- if (!appData.animate) return;
- if (doingSizing) return;
- if (fromY < 0 || fromX < 0) return;
- piece = board[fromY][fromX];
- if (piece >= EmptySquare) return;
-
- ScreenSquare(fromX, fromY, &start);
- ScreenSquare(toX, toY, &finish);
-
- /* All pieces except knights move in straight line */
- if (piece != WhiteKnight && piece != BlackKnight) {
- mid.x = start.x + (finish.x - start.x) / 2;
- mid.y = start.y + (finish.y - start.y) / 2;
- } else {
- /* Knight: make diagonal movement then straight */
- if (abs(toY - fromY) < abs(toX - fromX)) {
- mid.x = start.x + (finish.x - start.x) / 2;
- mid.y = finish.y;
- } else {
- mid.x = finish.x;
- mid.y = start.y + (finish.y - start.y) / 2;
- }
- }
-
- /* Don't use as many frames for very short moves */
- if (abs(toY - fromY) + abs(toX - fromX) <= 2)
- Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
- else
- Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
-
- animInfo.from.x = fromX;
- animInfo.from.y = fromY;
- animInfo.to.x = toX;
- animInfo.to.y = toY;
- animInfo.lastpos = start;
- animInfo.piece = piece;
- for (n = 0; n < nFrames; n++) {
- animInfo.pos = frames[n];
- DrawPosition(FALSE, NULL);
- animInfo.lastpos = animInfo.pos;
- Sleep(appData.animSpeed);
- }
- animInfo.pos = finish;
- DrawPosition(FALSE, NULL);
- animInfo.piece = EmptySquare;
-}
-
-/* Convert board position to corner of screen rect and color */
-
-static void
-ScreenSquare(column, row, pt)
- int column; int row; POINT * pt;
-{
- if (flipView) {
- pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
- pt->y = lineGap + row * (squareSize + lineGap);
- } else {
- pt->x = lineGap + column * (squareSize + lineGap);
- pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
- }
-}
-
-/* Generate a series of frame coords from start->mid->finish.
- The movement rate doubles until the half way point is
- reached, then halves back down to the final destination,
- which gives a nice slow in/out effect. The algorithmn
- may seem to generate too many intermediates for short
- moves, but remember that the purpose is to attract the
- viewers attention to the piece about to be moved and
- then to where it ends up. Too few frames would be less
- noticeable. */
-
-static void
-Tween(start, mid, finish, factor, frames, nFrames)
- POINT * start; POINT * mid;
- POINT * finish; int factor;
- POINT frames[]; int * nFrames;
-{
- int n, fraction = 1, count = 0;
-
- /* Slow in, stepping 1/16th, then 1/8th, ... */
- for (n = 0; n < factor; n++)
- fraction *= 2;
- for (n = 0; n < factor; n++) {
- frames[count].x = start->x + (mid->x - start->x) / fraction;
- frames[count].y = start->y + (mid->y - start->y) / fraction;
- count ++;
- fraction = fraction / 2;
- }
-
- /* Midpoint */
- frames[count] = *mid;
- count ++;
-
- /* Slow out, stepping 1/2, then 1/4, ... */
- fraction = 2;
- for (n = 0; n < factor; n++) {
- frames[count].x = finish->x - (finish->x - mid->x) / fraction;
- frames[count].y = finish->y - (finish->y - mid->y) / fraction;
- count ++;
- fraction = fraction * 2;
- }
- *nFrames = count;
-}
-
-void
-HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current)
-{
- /* Currently not implemented in WinBoard */
-}
-
-
+/*\r
+ * WinBoard.c -- Windows NT front end to XBoard\r
+ *\r
+ * Copyright 1991 by Digital Equipment Corporation, Maynard,\r
+ * Massachusetts. \r
+ *\r
+ * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
+ * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.\r
+ *\r
+ * Enhancements Copyright 2005 Alessandro Scotti\r
+ *\r
+ * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,\r
+ * which was written and is copyrighted by Wayne Christopher.\r
+ *\r
+ * The following terms apply to Digital Equipment Corporation's copyright\r
+ * interest in XBoard:\r
+ * ------------------------------------------------------------------------\r
+ * All Rights Reserved\r
+ *\r
+ * Permission to use, copy, modify, and distribute this software and its\r
+ * documentation for any purpose and without fee is hereby granted,\r
+ * provided that the above copyright notice appear in all copies and that\r
+ * both that copyright notice and this permission notice appear in\r
+ * supporting documentation, and that the name of Digital not be\r
+ * used in advertising or publicity pertaining to distribution of the\r
+ * software without specific, written prior permission.\r
+ *\r
+ * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL\r
+ * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\r
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\r
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\r
+ * SOFTWARE.\r
+ * ------------------------------------------------------------------------\r
+ *\r
+ * The following terms apply to the enhanced version of XBoard\r
+ * distributed by the Free Software Foundation:\r
+ * ------------------------------------------------------------------------\r
+ *\r
+ * GNU XBoard is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or (at\r
+ * your option) any later version.\r
+ *\r
+ * GNU XBoard is distributed in the hope that it will be useful, but\r
+ * WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+ * General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see http://www.gnu.org/licenses/. *\r
+ *\r
+ *------------------------------------------------------------------------\r
+ ** See the file ChangeLog for a revision history. */\r
+\r
+#include "config.h"\r
+\r
+#include <windows.h>\r
+#include <winuser.h>\r
+#include <winsock.h>\r
+#include <commctrl.h>\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <time.h>\r
+#include <malloc.h>\r
+#include <sys/stat.h>\r
+#include <fcntl.h>\r
+#include <math.h>\r
+#include <commdlg.h>\r
+#include <dlgs.h>\r
+#include <richedit.h>\r
+#include <mmsystem.h>\r
+#include <ctype.h>\r
+\r
+#if __GNUC__\r
+#include <errno.h>\r
+#include <string.h>\r
+#endif\r
+\r
+#include "common.h"\r
+#include "winboard.h"\r
+#include "frontend.h"\r
+#include "backend.h"\r
+#include "moves.h"\r
+#include "wclipbrd.h"\r
+#include "wgamelist.h"\r
+#include "wedittags.h"\r
+#include "woptions.h"\r
+#include "wsockerr.h"\r
+#include "defaults.h"\r
+#include "help.h"\r
+#include "wsnap.h"\r
+\r
+//void InitEngineUCI( const char * iniDir, ChessProgramState * cps );\r
+\r
+ int myrandom(void);\r
+ void mysrandom(unsigned int seed);\r
+\r
+extern int whiteFlag, blackFlag;\r
+Boolean flipClock = FALSE;\r
+extern HANDLE chatHandle[];\r
+extern int ics_type;\r
+\r
+void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);\r
+VOID NewVariantPopup(HWND hwnd);\r
+int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
+ /*char*/int promoChar));\r
+void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);\r
+void DisplayMove P((int moveNumber));\r
+Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
+void ChatPopUp P(());\r
+typedef struct {\r
+ ChessSquare piece; \r
+ POINT pos; /* window coordinates of current pos */\r
+ POINT lastpos; /* window coordinates of last pos - used for clipping */\r
+ POINT from; /* board coordinates of the piece's orig pos */\r
+ POINT to; /* board coordinates of the piece's new pos */\r
+} AnimInfo;\r
+\r
+static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };\r
+\r
+typedef struct {\r
+ POINT start; /* window coordinates of start pos */\r
+ POINT pos; /* window coordinates of current pos */\r
+ POINT lastpos; /* window coordinates of last pos - used for clipping */\r
+ POINT from; /* board coordinates of the piece's orig pos */\r
+} DragInfo;\r
+\r
+static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };\r
+\r
+typedef struct {\r
+ POINT sq[2]; /* board coordinates of from, to squares */\r
+} HighlightInfo;\r
+\r
+static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };\r
+static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };\r
+\r
+typedef struct { // [HGM] atomic\r
+ int fromX, fromY, toX, toY, radius;\r
+} ExplodeInfo;\r
+\r
+static ExplodeInfo explodeInfo;\r
+\r
+/* Window class names */\r
+char szAppName[] = "WinBoard";\r
+char szConsoleName[] = "WBConsole";\r
+\r
+/* Title bar text */\r
+char szTitle[] = "WinBoard";\r
+char szConsoleTitle[] = "I C S Interaction";\r
+\r
+char *programName;\r
+char *settingsFileName;\r
+BOOLEAN saveSettingsOnExit;\r
+char installDir[MSG_SIZ];\r
+\r
+BoardSize boardSize;\r
+BOOLEAN chessProgram;\r
+static int boardX, boardY;\r
+int minX, minY; // [HGM] placement: volatile limits on upper-left corner\r
+static int squareSize, lineGap, minorSize;\r
+static int winWidth, winHeight, winW, winH;\r
+static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo\r
+static int logoHeight = 0;\r
+static char messageText[MESSAGE_TEXT_MAX];\r
+static int clockTimerEvent = 0;\r
+static int loadGameTimerEvent = 0;\r
+static int analysisTimerEvent = 0;\r
+static DelayedEventCallback delayedTimerCallback;\r
+static int delayedTimerEvent = 0;\r
+static int buttonCount = 2;\r
+char *icsTextMenuString;\r
+char *icsNames;\r
+char *firstChessProgramNames;\r
+char *secondChessProgramNames;\r
+\r
+#define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */\r
+\r
+#define PALETTESIZE 256\r
+\r
+HINSTANCE hInst; /* current instance */\r
+HWND hwndMain = NULL; /* root window*/\r
+HWND hwndConsole = NULL;\r
+BOOLEAN alwaysOnTop = FALSE;\r
+RECT boardRect;\r
+COLORREF lightSquareColor, darkSquareColor, whitePieceColor, \r
+ blackPieceColor, highlightSquareColor, premoveHighlightColor;\r
+HPALETTE hPal;\r
+ColorClass currentColorClass;\r
+\r
+HWND hCommPort = NULL; /* currently open comm port */\r
+static HWND hwndPause; /* pause button */\r
+static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */\r
+static HBRUSH lightSquareBrush, darkSquareBrush,\r
+ blackSquareBrush, /* [HGM] for band between board and holdings */\r
+ explodeBrush, /* [HGM] atomic */\r
+ whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;\r
+static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];\r
+static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];\r
+static HPEN gridPen = NULL;\r
+static HPEN highlightPen = NULL;\r
+static HPEN premovePen = NULL;\r
+static NPLOGPALETTE pLogPal;\r
+static BOOL paletteChanged = FALSE;\r
+static HICON iconWhite, iconBlack, iconCurrent;\r
+static int doingSizing = FALSE;\r
+static int lastSizing = 0;\r
+static int prevStderrPort;\r
+static HBITMAP userLogo;\r
+\r
+/* [AS] Support for background textures */\r
+#define BACK_TEXTURE_MODE_DISABLED 0\r
+#define BACK_TEXTURE_MODE_PLAIN 1\r
+#define BACK_TEXTURE_MODE_FULL_RANDOM 2\r
+\r
+static HBITMAP liteBackTexture = NULL;\r
+static HBITMAP darkBackTexture = NULL;\r
+static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
+static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
+static int backTextureSquareSize = 0;\r
+static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];\r
+\r
+#if __GNUC__ && !defined(_winmajor)\r
+#define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */\r
+#else\r
+#if defined(_winmajor)\r
+#define oldDialog (_winmajor < 4)\r
+#else\r
+#define oldDialog 0\r
+#endif\r
+#endif\r
+\r
+char *defaultTextAttribs[] = \r
+{\r
+ COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,\r
+ COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,\r
+ COLOR_NONE\r
+};\r
+\r
+typedef struct {\r
+ char *name;\r
+ int squareSize;\r
+ int lineGap;\r
+ int smallLayout;\r
+ int tinyLayout;\r
+ int cliWidth, cliHeight;\r
+} SizeInfo;\r
+\r
+SizeInfo sizeInfo[] = \r
+{\r
+ { "tiny", 21, 0, 1, 1, 0, 0 },\r
+ { "teeny", 25, 1, 1, 1, 0, 0 },\r
+ { "dinky", 29, 1, 1, 1, 0, 0 },\r
+ { "petite", 33, 1, 1, 1, 0, 0 },\r
+ { "slim", 37, 2, 1, 0, 0, 0 },\r
+ { "small", 40, 2, 1, 0, 0, 0 },\r
+ { "mediocre", 45, 2, 1, 0, 0, 0 },\r
+ { "middling", 49, 2, 0, 0, 0, 0 },\r
+ { "average", 54, 2, 0, 0, 0, 0 },\r
+ { "moderate", 58, 3, 0, 0, 0, 0 },\r
+ { "medium", 64, 3, 0, 0, 0, 0 },\r
+ { "bulky", 72, 3, 0, 0, 0, 0 },\r
+ { "large", 80, 3, 0, 0, 0, 0 },\r
+ { "big", 87, 3, 0, 0, 0, 0 },\r
+ { "huge", 95, 3, 0, 0, 0, 0 },\r
+ { "giant", 108, 3, 0, 0, 0, 0 },\r
+ { "colossal", 116, 4, 0, 0, 0, 0 },\r
+ { "titanic", 129, 4, 0, 0, 0, 0 },\r
+ { NULL, 0, 0, 0, 0, 0, 0 }\r
+};\r
+\r
+#define MF(x) {x, {{0,}, 0. }, {0, }, 0}\r
+MyFont fontRec[NUM_SIZES][NUM_FONTS] =\r
+{\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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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) },\r
+ { 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
+\r
+MyFont *font[NUM_SIZES][NUM_FONTS];\r
+\r
+typedef struct {\r
+ char *label;\r
+ int id;\r
+ HWND hwnd;\r
+ WNDPROC wndproc;\r
+} MyButtonDesc;\r
+\r
+#define BUTTON_WIDTH (tinyLayout ? 16 : 32)\r
+#define N_BUTTONS 5\r
+\r
+MyButtonDesc buttonDesc[N_BUTTONS] =\r
+{\r
+ {"<<", IDM_ToStart, NULL, NULL},\r
+ {"<", IDM_Backward, NULL, NULL},\r
+ {"P", IDM_Pause, NULL, NULL},\r
+ {">", IDM_Forward, NULL, NULL},\r
+ {">>", IDM_ToEnd, NULL, NULL},\r
+};\r
+\r
+int tinyLayout = 0, smallLayout = 0;\r
+#define MENU_BAR_ITEMS 7\r
+char *menuBarText[2][MENU_BAR_ITEMS+1] = {\r
+ { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },\r
+ { "&F", "&M", "&A", "&S", "&O", "&H", NULL },\r
+};\r
+\r
+\r
+MySound sounds[(int)NSoundClasses];\r
+MyTextAttribs textAttribs[(int)NColorClasses];\r
+\r
+MyColorizeAttribs colorizeAttribs[] = {\r
+ { (COLORREF)0, 0, "Shout Text" },\r
+ { (COLORREF)0, 0, "SShout/CShout" },\r
+ { (COLORREF)0, 0, "Channel 1 Text" },\r
+ { (COLORREF)0, 0, "Channel Text" },\r
+ { (COLORREF)0, 0, "Kibitz Text" },\r
+ { (COLORREF)0, 0, "Tell Text" },\r
+ { (COLORREF)0, 0, "Challenge Text" },\r
+ { (COLORREF)0, 0, "Request Text" },\r
+ { (COLORREF)0, 0, "Seek Text" },\r
+ { (COLORREF)0, 0, "Normal Text" },\r
+ { (COLORREF)0, 0, "None" }\r
+};\r
+\r
+\r
+\r
+static char *commentTitle;\r
+static char *commentText;\r
+static int commentIndex;\r
+static Boolean editComment = FALSE;\r
+HWND commentDialog = NULL;\r
+int commentUp = FALSE;\r
+static int commentX, commentY, commentH, commentW;\r
+\r
+static char *analysisTitle;\r
+static char *analysisText;\r
+HWND analysisDialog = NULL;\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
+BOOLEAN consoleEcho = TRUE;\r
+CHARFORMAT consoleCF;\r
+COLORREF consoleBackgroundColor;\r
+\r
+char *programVersion;\r
+\r
+#define CPReal 1\r
+#define CPComm 2\r
+#define CPSock 3\r
+#define CPRcmd 4\r
+typedef int CPKind;\r
+\r
+typedef struct {\r
+ CPKind kind;\r
+ HANDLE hProcess;\r
+ DWORD pid;\r
+ HANDLE hTo;\r
+ HANDLE hFrom;\r
+ SOCKET sock;\r
+ SOCKET sock2; /* stderr socket for OpenRcmd */\r
+} ChildProc;\r
+\r
+#define INPUT_SOURCE_BUF_SIZE 4096\r
+\r
+typedef struct _InputSource {\r
+ CPKind kind;\r
+ HANDLE hFile;\r
+ SOCKET sock;\r
+ int lineByLine;\r
+ HANDLE hThread;\r
+ DWORD id;\r
+ char buf[INPUT_SOURCE_BUF_SIZE];\r
+ char *next;\r
+ DWORD count;\r
+ int error;\r
+ InputCallback func;\r
+ struct _InputSource *second; /* for stderr thread on CPRcmd */\r
+ VOIDSTAR closure;\r
+} InputSource;\r
+\r
+InputSource *consoleInputSource;\r
+\r
+DCB dcb;\r
+\r
+/* forward */\r
+VOID ConsoleOutput(char* data, int length, int forceVisible);\r
+VOID ConsoleCreate();\r
+LRESULT CALLBACK\r
+ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
+VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);\r
+VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);\r
+VOID ParseCommSettings(char *arg, DCB *dcb);\r
+LRESULT CALLBACK\r
+ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
+VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);\r
+void ParseIcsTextMenu(char *icsTextMenuString);\r
+VOID PopUpMoveDialog(char firstchar);\r
+VOID PopUpNameDialog(char firstchar);\r
+VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);\r
+\r
+/* [AS] */\r
+int NewGameFRC();\r
+int GameListOptions();\r
+\r
+HWND moveHistoryDialog = NULL;\r
+BOOLEAN moveHistoryDialogUp = FALSE;\r
+\r
+WindowPlacement wpMoveHistory;\r
+\r
+HWND evalGraphDialog = NULL;\r
+BOOLEAN evalGraphDialogUp = FALSE;\r
+\r
+WindowPlacement wpEvalGraph;\r
+\r
+HWND engineOutputDialog = NULL;\r
+int engineOutputDialogUp = FALSE;\r
+\r
+WindowPlacement wpEngineOutput;\r
+WindowPlacement wpGameList;\r
+WindowPlacement wpConsole;\r
+\r
+VOID MoveHistoryPopUp();\r
+VOID MoveHistoryPopDown();\r
+VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
+BOOL MoveHistoryIsUp();\r
+\r
+VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
+VOID EvalGraphPopUp();\r
+VOID EvalGraphPopDown();\r
+BOOL EvalGraphIsUp();\r
+\r
+VOID EngineOutputPopUp();\r
+VOID EngineOutputPopDown();\r
+BOOL EngineOutputIsUp();\r
+VOID EngineOutputUpdate( FrontEndProgramStats * stats );\r
+\r
+VOID EngineOptionsPopup(); // [HGM] settings\r
+\r
+VOID GothicPopUp(char *title, VariantClass variant);\r
+/*\r
+ * Setting "frozen" should disable all user input other than deleting\r
+ * the window. We do this while engines are initializing themselves.\r
+ */\r
+static int frozen = 0;\r
+static int oldMenuItemState[MENU_BAR_ITEMS];\r
+void FreezeUI()\r
+{\r
+ HMENU hmenu;\r
+ int i;\r
+\r
+ if (frozen) return;\r
+ frozen = 1;\r
+ hmenu = GetMenu(hwndMain);\r
+ for (i=0; i<MENU_BAR_ITEMS; i++) {\r
+ oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);\r
+ }\r
+ DrawMenuBar(hwndMain);\r
+}\r
+\r
+/* Undo a FreezeUI */\r
+void ThawUI()\r
+{\r
+ HMENU hmenu;\r
+ int i;\r
+\r
+ if (!frozen) return;\r
+ frozen = 0;\r
+ hmenu = GetMenu(hwndMain);\r
+ for (i=0; i<MENU_BAR_ITEMS; i++) {\r
+ EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);\r
+ }\r
+ DrawMenuBar(hwndMain);\r
+}\r
+\r
+/*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them\r
+\r
+/* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */\r
+#ifdef JAWS\r
+#include "jaws.c"\r
+#else\r
+#define JAWS_INIT\r
+#define JAWS_ARGS\r
+#define JAWS_ALT_INTERCEPT\r
+#define JAWS_KB_NAVIGATION\r
+#define JAWS_MENU_ITEMS\r
+#define JAWS_SILENCE\r
+#define JAWS_REPLAY\r
+#define JAWS_ACCEL\r
+#define JAWS_COPYRIGHT\r
+#define JAWS_DELETE(X) X\r
+#define SAYMACHINEMOVE()\r
+#define SAY(X)\r
+#endif\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * WinMain\r
+ *\r
+\*---------------------------------------------------------------------------*/\r
+\r
+int APIENTRY\r
+WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,\r
+ LPSTR lpCmdLine, int nCmdShow)\r
+{\r
+ MSG msg;\r
+ HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;\r
+// INITCOMMONCONTROLSEX ex;\r
+\r
+ debugFP = stderr;\r
+\r
+ LoadLibrary("RICHED32.DLL");\r
+ consoleCF.cbSize = sizeof(CHARFORMAT);\r
+\r
+ if (!InitApplication(hInstance)) {\r
+ return (FALSE);\r
+ }\r
+ if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {\r
+ return (FALSE);\r
+ }\r
+\r
+ JAWS_INIT\r
+\r
+// InitCommonControlsEx(&ex);\r
+ InitCommonControls();\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
+\r
+ /* Acquire and dispatch messages until a WM_QUIT message is received. */\r
+\r
+ while (GetMessage(&msg, /* message structure */\r
+ NULL, /* handle of window receiving the message */\r
+ 0, /* lowest message to examine */\r
+ 0)) /* highest message to examine */\r
+ {\r
+\r
+ if(msg.message == WM_CHAR && msg.wParam == '\t') {\r
+ // [HGM] navigate: switch between all windows with tab\r
+ HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;\r
+ int i, currentElement = 0;\r
+\r
+ // first determine what element of the chain we come from (if any)\r
+ if(appData.icsActive) {\r
+ hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+ hText = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
+ }\r
+ if(engineOutputDialog && EngineOutputIsUp()) {\r
+ e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);\r
+ e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);\r
+ }\r
+ if(moveHistoryDialog && MoveHistoryIsUp()) {\r
+ mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);\r
+ }\r
+ if(msg.hwnd == hwndMain) currentElement = 7 ; else\r
+ if(msg.hwnd == engineOutputDialog) currentElement = 2; else\r
+ if(msg.hwnd == e1) currentElement = 2; else\r
+ if(msg.hwnd == e2) currentElement = 3; else\r
+ if(msg.hwnd == moveHistoryDialog) currentElement = 4; else\r
+ if(msg.hwnd == mh) currentElement = 4; else\r
+ if(msg.hwnd == evalGraphDialog) currentElement = 6; else\r
+ if(msg.hwnd == hText) currentElement = 5; else\r
+ if(msg.hwnd == hInput) currentElement = 6; else\r
+ for (i = 0; i < N_BUTTONS; i++) {\r
+ if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }\r
+ }\r
+\r
+ // determine where to go to\r
+ if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;\r
+ do {\r
+ currentElement = (currentElement + direction) % 7;\r
+ switch(currentElement) {\r
+ case 0:\r
+ h = hwndMain; break; // passing this case always makes the loop exit\r
+ case 1:\r
+ h = buttonDesc[0].hwnd; break; // could be NULL\r
+ case 2:\r
+ if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows\r
+ h = e1; break;\r
+ case 3:\r
+ if(!EngineOutputIsUp()) continue;\r
+ h = e2; break;\r
+ case 4:\r
+ if(!MoveHistoryIsUp()) continue;\r
+ h = mh; break;\r
+// case 6: // input to eval graph does not seem to get here!\r
+// if(!EvalGraphIsUp()) continue;\r
+// h = evalGraphDialog; break;\r
+ case 5:\r
+ if(!appData.icsActive) continue;\r
+ SAY("display");\r
+ h = hText; break;\r
+ case 6:\r
+ if(!appData.icsActive) continue;\r
+ SAY("input");\r
+ h = hInput; break;\r
+ }\r
+ } while(h == 0);\r
+\r
+ if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
+ if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together\r
+ SetFocus(h);\r
+\r
+ continue; // this message now has been processed\r
+ }\r
+ }\r
+\r
+ if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&\r
+ !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&\r
+ !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&\r
+ !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&\r
+ !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&\r
+ !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&\r
+ !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&\r
+ !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL\r
+ !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&\r
+ !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {\r
+ int done = 0, i; // [HGM] chat: dispatch cat-box messages\r
+ for(i=0; i<MAX_CHAT; i++) \r
+ if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {\r
+ done = 1; break;\r
+ }\r
+ if(done) continue; // [HGM] chat: end patch\r
+ TranslateMessage(&msg); /* Translates virtual key codes */\r
+ DispatchMessage(&msg); /* Dispatches message to window */\r
+ }\r
+ }\r
+\r
+\r
+ return (msg.wParam); /* Returns the value from PostQuitMessage */\r
+}\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * Initialization functions\r
+ *\r
+\*---------------------------------------------------------------------------*/\r
+\r
+void\r
+SetUserLogo()\r
+{ // update user logo if necessary\r
+ static char oldUserName[MSG_SIZ], *curName;\r
+\r
+ if(appData.autoLogo) {\r
+ curName = UserName();\r
+ if(strcmp(curName, oldUserName)) {\r
+ sprintf(oldUserName, "logos\\%s.bmp", curName);\r
+ userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); \r
+ strcpy(oldUserName, curName);\r
+ }\r
+ }\r
+}\r
+\r
+BOOL\r
+InitApplication(HINSTANCE hInstance)\r
+{\r
+ WNDCLASS wc;\r
+\r
+ /* Fill in window class structure with parameters that describe the */\r
+ /* main window. */\r
+\r
+ wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */\r
+ wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */\r
+ wc.cbClsExtra = 0; /* No per-class extra data. */\r
+ wc.cbWndExtra = 0; /* No per-window extra data. */\r
+ wc.hInstance = hInstance; /* Owner of this class */\r
+ wc.hIcon = LoadIcon(hInstance, "icon_white");\r
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */\r
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */\r
+ wc.lpszMenuName = szAppName; /* Menu name from .RC */\r
+ wc.lpszClassName = szAppName; /* Name to register as */\r
+\r
+ /* Register the window class and return success/failure code. */\r
+ if (!RegisterClass(&wc)) return FALSE;\r
+\r
+ wc.style = CS_HREDRAW | CS_VREDRAW;\r
+ wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;\r
+ wc.cbClsExtra = 0;\r
+ wc.cbWndExtra = DLGWINDOWEXTRA;\r
+ wc.hInstance = hInstance;\r
+ wc.hIcon = LoadIcon(hInstance, "icon_white");\r
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);\r
+ wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);\r
+ wc.lpszMenuName = NULL;\r
+ wc.lpszClassName = szConsoleName;\r
+\r
+ if (!RegisterClass(&wc)) return FALSE;\r
+ return TRUE;\r
+}\r
+\r
+\r
+/* Set by InitInstance, used by EnsureOnScreen */\r
+int screenHeight, screenWidth;\r
+\r
+void\r
+EnsureOnScreen(int *x, int *y, int minX, int minY)\r
+{\r
+// int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);\r
+ /* Be sure window at (x,y) is not off screen (or even mostly off screen) */\r
+ if (*x > screenWidth - 32) *x = 0;\r
+ if (*y > screenHeight - 32) *y = 0;\r
+ if (*x < minX) *x = minX;\r
+ if (*y < minY) *y = minY;\r
+}\r
+\r
+BOOL\r
+InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)\r
+{\r
+ HWND hwnd; /* Main window handle. */\r
+ int ibs;\r
+ WINDOWPLACEMENT wp;\r
+ char *filepart;\r
+\r
+ hInst = hInstance; /* Store instance handle in our global variable */\r
+\r
+ if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {\r
+ *filepart = NULLCHAR;\r
+ } else {\r
+ GetCurrentDirectory(MSG_SIZ, installDir);\r
+ }\r
+ gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise\r
+ screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData\r
+ InitAppData(lpCmdLine); /* Get run-time parameters */\r
+ if (appData.debugMode) {\r
+ debugFP = fopen(appData.nameOfDebugFile, "w");\r
+ setbuf(debugFP, NULL);\r
+ }\r
+\r
+ InitBackEnd1();\r
+\r
+// InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()\r
+// InitEngineUCI( installDir, &second );\r
+\r
+ /* Create a main window for this application instance. */\r
+ hwnd = CreateWindow(szAppName, szTitle,\r
+ (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),\r
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,\r
+ NULL, NULL, hInstance, NULL);\r
+ hwndMain = hwnd;\r
+\r
+ /* If window could not be created, return "failure" */\r
+ if (!hwnd) {\r
+ return (FALSE);\r
+ }\r
+\r
+ /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */\r
+ if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {\r
+ first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+\r
+ if (first.programLogo == NULL && appData.debugMode) {\r
+ fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );\r
+ }\r
+ } else if(appData.autoLogo) {\r
+ if(appData.firstDirectory && appData.firstDirectory[0]) {\r
+ char buf[MSG_SIZ];\r
+ sprintf(buf, "%s/logo.bmp", appData.firstDirectory);\r
+ first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); \r
+ }\r
+ }\r
+\r
+ if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {\r
+ second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+\r
+ if (second.programLogo == NULL && appData.debugMode) {\r
+ fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );\r
+ }\r
+ } else if(appData.autoLogo) {\r
+ char buf[MSG_SIZ];\r
+ if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS\r
+ sprintf(buf, "logos\\%s.bmp", appData.icsHost);\r
+ second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+ } else\r
+ if(appData.secondDirectory && appData.secondDirectory[0]) {\r
+ sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);\r
+ second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); \r
+ }\r
+ }\r
+\r
+ SetUserLogo();\r
+\r
+ iconWhite = LoadIcon(hInstance, "icon_white");\r
+ iconBlack = LoadIcon(hInstance, "icon_black");\r
+ iconCurrent = iconWhite;\r
+ InitDrawingColors();\r
+ screenHeight = GetSystemMetrics(SM_CYSCREEN);\r
+ screenWidth = GetSystemMetrics(SM_CXSCREEN);\r
+ for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {\r
+ /* Compute window size for each board size, and use the largest\r
+ size that fits on this screen as the default. */\r
+ InitDrawingSizes((BoardSize)(ibs+1000), 0);\r
+ if (boardSize == (BoardSize)-1 &&\r
+ winH <= screenHeight\r
+ - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10\r
+ && winW <= screenWidth) {\r
+ boardSize = (BoardSize)ibs;\r
+ }\r
+ }\r
+\r
+ InitDrawingSizes(boardSize, 0);\r
+ InitMenuChecks();\r
+ buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);\r
+\r
+ /* [AS] Load textures if specified */\r
+ ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );\r
+ \r
+ if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {\r
+ liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+ liteBackTextureMode = appData.liteBackTextureMode;\r
+\r
+ if (liteBackTexture == NULL && appData.debugMode) {\r
+ fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );\r
+ }\r
+ }\r
+ \r
+ if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {\r
+ darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+ darkBackTextureMode = appData.darkBackTextureMode;\r
+\r
+ if (darkBackTexture == NULL && appData.debugMode) {\r
+ fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );\r
+ }\r
+ }\r
+\r
+ mysrandom( (unsigned) time(NULL) );\r
+\r
+ /* [AS] Restore layout */\r
+ if( wpMoveHistory.visible ) {\r
+ MoveHistoryPopUp();\r
+ }\r
+\r
+ if( wpEvalGraph.visible ) {\r
+ EvalGraphPopUp();\r
+ }\r
+\r
+ if( wpEngineOutput.visible ) {\r
+ EngineOutputPopUp();\r
+ }\r
+\r
+ InitBackEnd2();\r
+\r
+ /* Make the window visible; update its client area; and return "success" */\r
+ EnsureOnScreen(&boardX, &boardY, minX, minY);\r
+ wp.length = sizeof(WINDOWPLACEMENT);\r
+ wp.flags = 0;\r
+ wp.showCmd = nCmdShow;\r
+ wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
+ wp.rcNormalPosition.left = boardX;\r
+ wp.rcNormalPosition.right = boardX + winWidth;\r
+ wp.rcNormalPosition.top = boardY;\r
+ wp.rcNormalPosition.bottom = boardY + winHeight;\r
+ SetWindowPlacement(hwndMain, &wp);\r
+\r
+ if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
+ 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
+\r
+ if (hwndConsole) {\r
+#if AOT_CONSOLE\r
+ SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
+ 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
+#endif\r
+ ShowWindow(hwndConsole, nCmdShow);\r
+ }\r
+ if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);\r
+ if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file\r
+\r
+ return TRUE;\r
+\r
+}\r
+\r
+\r
+typedef enum {\r
+ ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone, \r
+ ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,\r
+ ArgSettingsFilename,\r
+ ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window\r
+} ArgType;\r
+\r
+typedef struct {\r
+ char *argName;\r
+ ArgType argType;\r
+ /***\r
+ union {\r
+ String *pString; // ArgString\r
+ int *pInt; // ArgInt\r
+ float *pFloat; // ArgFloat\r
+ Boolean *pBoolean; // ArgBoolean\r
+ COLORREF *pColor; // ArgColor\r
+ ColorClass cc; // ArgAttribs\r
+ String *pFilename; // ArgFilename\r
+ BoardSize *pBoardSize; // ArgBoardSize\r
+ int whichFont; // ArgFont\r
+ DCB *pDCB; // ArgCommSettings\r
+ String *pFilename; // ArgSettingsFilename\r
+ } argLoc;\r
+ ***/\r
+ LPVOID argLoc;\r
+ BOOL save;\r
+} ArgDescriptor;\r
+\r
+int junk;\r
+ArgDescriptor argDescriptors[] = {\r
+ /* positional arguments */\r
+ { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
+ { "", ArgNone, NULL },\r
+ /* keyword arguments */\r
+ JAWS_ARGS\r
+ { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },\r
+ { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },\r
+ { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },\r
+ { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },\r
+ { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },\r
+ { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },\r
+ { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },\r
+ { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },\r
+ { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },\r
+ { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },\r
+ { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },\r
+ { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },\r
+ { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },\r
+ { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },\r
+ { "initString", ArgString, (LPVOID) &appData.initString, FALSE },\r
+ { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },\r
+ { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },\r
+ { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,\r
+ FALSE },\r
+ { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,\r
+ FALSE },\r
+ { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,\r
+ FALSE },\r
+ { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },\r
+ { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,\r
+ FALSE },\r
+ { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },\r
+ { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
+ { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
+ { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
+ { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
+ { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },\r
+ { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },\r
+ { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },\r
+ { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },\r
+ { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },\r
+ { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },\r
+ { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },\r
+ { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },\r
+ { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },\r
+ { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },\r
+ { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },\r
+ { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },\r
+ /*!!bitmapDirectory?*/\r
+ { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },\r
+ { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },\r
+ { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },\r
+ { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },\r
+ { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },\r
+ { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },\r
+ { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },\r
+ { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },\r
+ { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },\r
+ { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },\r
+ { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },\r
+ { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },\r
+ { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },\r
+ { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },\r
+ { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },\r
+ { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },\r
+ { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },\r
+ { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },\r
+ { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
+ { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
+ { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
+ { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
+ { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },\r
+ { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },\r
+ { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },\r
+ { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },\r
+ { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },\r
+ { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },\r
+ { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },\r
+ { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },\r
+ { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },\r
+ { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
+ { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
+ { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },\r
+ { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },\r
+ { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },\r
+ { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },\r
+ { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },\r
+ { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },\r
+ { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },\r
+ { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },\r
+ { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },\r
+ { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },\r
+ { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },\r
+ { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },\r
+ { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },\r
+ { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },\r
+ { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },\r
+ { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },\r
+ { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },\r
+ { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },\r
+ { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },\r
+ { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },\r
+ { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },\r
+ { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },\r
+ { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },\r
+ { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },\r
+ { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },\r
+ { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },\r
+ { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },\r
+ { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },\r
+ { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },\r
+ { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },\r
+ { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },\r
+ { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },\r
+ { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },\r
+ { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },\r
+ { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },\r
+ { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },\r
+ { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },\r
+ { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },\r
+ { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },\r
+ { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },\r
+ { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },\r
+ { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },\r
+ { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },\r
+ { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },\r
+ { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },\r
+ { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },\r
+ { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },\r
+ { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },\r
+ { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },\r
+ { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },\r
+ { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },\r
+ { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },\r
+ { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },\r
+ { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },\r
+ { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },\r
+ { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },\r
+ { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },\r
+ { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },\r
+ { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },\r
+ { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },\r
+ { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, \r
+ FALSE }, /* only so that old WinBoard.ini files from betas can be read */\r
+ { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },\r
+ { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },\r
+ { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },\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] */\r
+ { "boardSize", ArgBoardSize, (LPVOID) &boardSize,\r
+ TRUE }, /* must come after all fonts */\r
+ { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },\r
+ { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,\r
+ FALSE }, /* historical; kept only so old winboard.ini files will parse */\r
+ { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },\r
+ { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },\r
+ { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },\r
+ { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },\r
+ { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },\r
+ { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },\r
+ { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },\r
+ { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },\r
+ { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },\r
+ { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },\r
+ { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },\r
+ { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },\r
+ { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },\r
+ { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },\r
+ { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },\r
+ { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },\r
+ { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },\r
+ { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },\r
+ { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },\r
+ { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },\r
+ { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },\r
+ { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },\r
+ { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },\r
+ { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },\r
+ { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },\r
+ { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
+ { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
+ { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
+ { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },\r
+ { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
+ { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
+ { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
+ { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },\r
+ { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },\r
+ { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },\r
+ { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },\r
+ { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },\r
+ { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },\r
+ { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },\r
+ { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },\r
+ { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },\r
+ { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },\r
+ { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },\r
+ { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },\r
+ { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },\r
+ { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },\r
+ { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },\r
+ { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },\r
+ { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },\r
+ { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },\r
+ { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },\r
+ { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },\r
+ { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },\r
+ { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },\r
+ { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },\r
+ { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },\r
+ { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },\r
+ { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },\r
+ { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },\r
+ { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },\r
+ { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },\r
+ { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },\r
+ { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},\r
+ { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},\r
+ { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},\r
+ { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},\r
+ { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},\r
+ { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},\r
+ { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},\r
+ { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },\r
+ { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },\r
+ { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },\r
+ { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },\r
+ { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },\r
+ { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },\r
+ { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },\r
+ { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },\r
+ { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },\r
+ { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },\r
+ { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },\r
+ { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },\r
+ { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },\r
+ { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },\r
+ { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },\r
+ { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },\r
+ { "highlightLastMove", ArgBoolean,\r
+ (LPVOID) &appData.highlightLastMove, TRUE },\r
+ { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },\r
+ { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },\r
+ { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },\r
+ { "highlightDragging", ArgBoolean,\r
+ (LPVOID) &appData.highlightDragging, TRUE },\r
+ { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },\r
+ { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },\r
+ { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },\r
+ { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },\r
+ { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },\r
+ { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },\r
+ { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },\r
+ { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },\r
+ { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },\r
+ { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },\r
+ { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },\r
+ { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },\r
+ { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },\r
+ { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },\r
+ { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },\r
+ { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },\r
+ { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },\r
+ { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },\r
+ { "soundShout", ArgFilename,\r
+ (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },\r
+ { "soundSShout", ArgFilename,\r
+ (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },\r
+ { "soundChannel1", ArgFilename,\r
+ (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },\r
+ { "soundChannel", ArgFilename,\r
+ (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },\r
+ { "soundKibitz", ArgFilename,\r
+ (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },\r
+ { "soundTell", ArgFilename,\r
+ (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },\r
+ { "soundChallenge", ArgFilename,\r
+ (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },\r
+ { "soundRequest", ArgFilename,\r
+ (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },\r
+ { "soundSeek", ArgFilename,\r
+ (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },\r
+ { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },\r
+ { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },\r
+ { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },\r
+ { "soundIcsLoss", ArgFilename, \r
+ (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },\r
+ { "soundIcsDraw", ArgFilename, \r
+ (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },\r
+ { "soundIcsUnfinished", ArgFilename, \r
+ (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},\r
+ { "soundIcsAlarm", ArgFilename, \r
+ (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },\r
+ { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },\r
+ { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },\r
+ { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },\r
+ { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },\r
+ { "reuseChessPrograms", ArgBoolean,\r
+ (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */\r
+ { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },\r
+ { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },\r
+ { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
+ { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
+ { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },\r
+ { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
+ { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
+ { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },\r
+ { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },\r
+ { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },\r
+ { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },\r
+ { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },\r
+ { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },\r
+ { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },\r
+ { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,\r
+ TRUE },\r
+ { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,\r
+ TRUE },\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, FALSE },\r
+ { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },\r
+ { "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 */\r
+ { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },\r
+ { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },\r
+ { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },\r
+ { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },\r
+ { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },\r
+ { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },\r
+ { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },\r
+ { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },\r
+ { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },\r
+ { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },\r
+ { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },\r
+ { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },\r
+ { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },\r
+ { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },\r
+ { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },\r
+ { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },\r
+ { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },\r
+ { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },\r
+ { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },\r
+ { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },\r
+ { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },\r
+ { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },\r
+ { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },\r
+ { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },\r
+ { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },\r
+ { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },\r
+ { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },\r
+ { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },\r
+ { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },\r
+ { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },\r
+ { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },\r
+ { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },\r
+ { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },\r
+ { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },\r
+ { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },\r
+ { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },\r
+ { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },\r
+ { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },\r
+ { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
+ { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
+ { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
+ { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
+ { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
+ { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
+ { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },\r
+ { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },\r
+ { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },\r
+ { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE }, \r
+ { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },\r
+ { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },\r
+\r
+ /* [HGM] board-size, adjudication and misc. options */\r
+ { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },\r
+ { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },\r
+ { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },\r
+ { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },\r
+ { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },\r
+ { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },\r
+ { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },\r
+ { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },\r
+ { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },\r
+ { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },\r
+ { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },\r
+ { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },\r
+ { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },\r
+ { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },\r
+ { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },\r
+ { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },\r
+ { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },\r
+ { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },\r
+ { "userName", ArgString, (LPVOID) &appData.userName, FALSE },\r
+ { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },\r
+ { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },\r
+ { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },\r
+ { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },\r
+ { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },\r
+ { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },\r
+ { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },\r
+ { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },\r
+ { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },\r
+ { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },\r
+ { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },\r
+ { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },\r
+ { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },\r
+ { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },\r
+ { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },\r
+\r
+#ifdef ZIPPY\r
+ { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
+ { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },\r
+ { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
+ { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
+ { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },\r
+ { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },\r
+ { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
+ { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
+ { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },\r
+ { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },\r
+ { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },\r
+ { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },\r
+ { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,\r
+ FALSE },\r
+ { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },\r
+ { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },\r
+ { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },\r
+ { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
+ { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
+ { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },\r
+ { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,\r
+ FALSE },\r
+ { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
+ { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
+ { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
+ { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },\r
+ { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },\r
+ { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },\r
+ { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },\r
+ { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
+ { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
+ { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },\r
+ { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },\r
+ { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
+ { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
+ { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },\r
+ { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },\r
+ { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },\r
+ { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },\r
+ /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */\r
+ { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },\r
+#endif\r
+ /* [HGM] options for broadcasting and time odds */\r
+ { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },\r
+ { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },\r
+ { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },\r
+ { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },\r
+ { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },\r
+ { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },\r
+ { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },\r
+ { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },\r
+ { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },\r
+ { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },\r
+ { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },\r
+ { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE },\r
+ { "wrapContinuationSequence", ArgString, (LPVOID) &appData.wrapContSeq, FALSE },\r
+ { "useInternalWrap", ArgTrue, (LPVOID) &appData.useInternalWrap, FALSE }, /* noJoin usurps this if set */\r
+ \r
+ // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others\r
+ { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed\r
+ { "minY", ArgZ, (LPVOID) &minY, FALSE },\r
+ { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom\r
+ { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them\r
+ { "x", ArgInt, (LPVOID) &boardX, TRUE },\r
+ { "y", ArgInt, (LPVOID) &boardY, TRUE },\r
+ { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },\r
+ { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },\r
+ { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },\r
+ { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },\r
+ { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists\r
+ { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files\r
+ { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },\r
+ { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },\r
+ { "commentX", ArgX, (LPVOID) &commentX, TRUE },\r
+ { "commentY", ArgY, (LPVOID) &commentY, TRUE },\r
+ { "commentW", ArgInt, (LPVOID) &commentW, TRUE },\r
+ { "commentH", ArgInt, (LPVOID) &commentH, TRUE },\r
+ { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },\r
+ { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },\r
+ { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },\r
+ { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },\r
+ { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },\r
+ { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },\r
+ { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },\r
+ { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },\r
+ /* [AS] Layout stuff */\r
+ { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },\r
+ { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },\r
+ { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },\r
+ { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },\r
+ { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },\r
+\r
+ { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },\r
+ { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },\r
+ { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },\r
+ { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },\r
+ { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },\r
+\r
+ { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },\r
+ { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },\r
+ { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },\r
+ { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },\r
+ { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },\r
+\r
+ { NULL, ArgNone, NULL, FALSE }\r
+};\r
+\r
+\r
+/* Kludge for indirection files on command line */\r
+char* lastIndirectionFilename;\r
+ArgDescriptor argDescriptorIndirection =\r
+{ "", ArgSettingsFilename, (LPVOID) NULL, FALSE };\r
+\r
+\r
+VOID\r
+ExitArgError(char *msg, char *badArg)\r
+{\r
+ char buf[MSG_SIZ];\r
+\r
+ sprintf(buf, "%s %s", msg, badArg);\r
+ DisplayFatalError(buf, 0, 2);\r
+ exit(2);\r
+}\r
+\r
+int\r
+ValidateInt(char *s)\r
+{\r
+ char *p = s;\r
+ if(*p == '-' || *p == '+') p++;\r
+ while(*p) if(!isdigit(*p++)) ExitArgError("Bad integer value", s);\r
+ return atoi(s);\r
+}\r
+\r
+/* Command line font name parser. NULL name means do nothing.\r
+ Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"\r
+ For backward compatibility, syntax without the colon is also\r
+ accepted, but font names with digits in them won't work in that case.\r
+*/\r
+VOID\r
+ParseFontName(char *name, MyFontParams *mfp)\r
+{\r
+ char *p, *q;\r
+ if (name == NULL) return;\r
+ p = name;\r
+ q = strchr(p, ':');\r
+ if (q) {\r
+ if (q - p >= sizeof(mfp->faceName))\r
+ ExitArgError("Font name too long:", name);\r
+ memcpy(mfp->faceName, p, q - p);\r
+ mfp->faceName[q - p] = NULLCHAR;\r
+ p = q + 1;\r
+ } else {\r
+ q = mfp->faceName;\r
+ while (*p && !isdigit(*p)) {\r
+ *q++ = *p++;\r
+ if (q - mfp->faceName >= sizeof(mfp->faceName))\r
+ ExitArgError("Font name too long:", name);\r
+ }\r
+ while (q > mfp->faceName && q[-1] == ' ') q--;\r
+ *q = NULLCHAR;\r
+ }\r
+ if (!*p) ExitArgError("Font point size missing:", name);\r
+ mfp->pointSize = (float) atof(p);\r
+ mfp->bold = (strchr(p, 'b') != NULL);\r
+ mfp->italic = (strchr(p, 'i') != NULL);\r
+ mfp->underline = (strchr(p, 'u') != NULL);\r
+ mfp->strikeout = (strchr(p, 's') != NULL);\r
+ mfp->charset = DEFAULT_CHARSET;\r
+ q = strchr(p, 'c');\r
+ if (q)\r
+ mfp->charset = (BYTE) atoi(q+1);\r
+}\r
+\r
+/* Color name parser.\r
+ X version accepts X color names, but this one\r
+ handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */\r
+COLORREF\r
+ParseColorName(char *name)\r
+{\r
+ int red, green, blue, count;\r
+ char buf[MSG_SIZ];\r
+\r
+ count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);\r
+ if (count != 3) {\r
+ count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d", \r
+ &red, &green, &blue);\r
+ }\r
+ if (count != 3) {\r
+ sprintf(buf, "Can't parse color name %s", name);\r
+ DisplayError(buf, 0);\r
+ return RGB(0, 0, 0);\r
+ }\r
+ return PALETTERGB(red, green, blue);\r
+}\r
+\r
+\r
+void ParseAttribs(COLORREF *color, int *effects, char* argValue)\r
+{\r
+ char *e = argValue;\r
+ int eff = 0;\r
+\r
+ while (*e) {\r
+ if (*e == 'b') eff |= CFE_BOLD;\r
+ else if (*e == 'i') eff |= CFE_ITALIC;\r
+ else if (*e == 'u') eff |= CFE_UNDERLINE;\r
+ else if (*e == 's') eff |= CFE_STRIKEOUT;\r
+ else if (*e == '#' || isdigit(*e)) break;\r
+ e++;\r
+ }\r
+ *effects = eff;\r
+ *color = ParseColorName(e);\r
+}\r
+\r
+\r
+BoardSize\r
+ParseBoardSize(char *name)\r
+{\r
+ BoardSize bs = SizeTiny;\r
+ while (sizeInfo[bs].name != NULL) {\r
+ if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;\r
+ bs++;\r
+ }\r
+ ExitArgError("Unrecognized board size value", name);\r
+ return bs; /* not reached */\r
+}\r
+\r
+\r
+char\r
+StringGet(void *getClosure)\r
+{\r
+ char **p = (char **) getClosure;\r
+ return *((*p)++);\r
+}\r
+\r
+char\r
+FileGet(void *getClosure)\r
+{\r
+ int c;\r
+ FILE* f = (FILE*) getClosure;\r
+\r
+ c = getc(f);\r
+ if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely\r
+ if (c == EOF)\r
+ return NULLCHAR;\r
+ else\r
+ return (char) c;\r
+}\r
+\r
+/* Parse settings file named "name". If file found, return the\r
+ full name in fullname and return TRUE; else return FALSE */\r
+BOOLEAN\r
+ParseSettingsFile(char *name, char fullname[MSG_SIZ])\r
+{\r
+ char *dummy;\r
+ FILE *f;\r
+ int ok; char buf[MSG_SIZ];\r
+\r
+ ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);\r
+ if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed\r
+ sprintf(buf, "%s.ini", name);\r
+ ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);\r
+ }\r
+ if (ok) {\r
+ f = fopen(fullname, "r");\r
+ if (f != NULL) {\r
+ ParseArgs(FileGet, f);\r
+ fclose(f);\r
+ return TRUE;\r
+ }\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+VOID\r
+ParseArgs(GetFunc get, void *cl)\r
+{\r
+ char argName[ARG_MAX];\r
+ char argValue[ARG_MAX];\r
+ ArgDescriptor *ad;\r
+ char start;\r
+ char *q;\r
+ int i, octval;\r
+ char ch;\r
+ int posarg = 0;\r
+\r
+ ch = get(cl);\r
+ for (;;) {\r
+ while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);\r
+ if (ch == NULLCHAR) break;\r
+ if (ch == ';') {\r
+ /* Comment to end of line */\r
+ ch = get(cl);\r
+ while (ch != '\n' && ch != NULLCHAR) ch = get(cl);\r
+ continue;\r
+ } else if (ch == '/' || ch == '-') {\r
+ /* Switch */\r
+ q = argName;\r
+ while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&\r
+ ch != '\n' && ch != '\t') {\r
+ *q++ = ch;\r
+ ch = get(cl);\r
+ }\r
+ *q = NULLCHAR;\r
+\r
+ for (ad = argDescriptors; ad->argName != NULL; ad++)\r
+ if (strcmp(ad->argName, argName + 1) == 0) break;\r
+\r
+ if (ad->argName == NULL)\r
+ ExitArgError("Unrecognized argument", argName);\r
+\r
+ } else if (ch == '@') {\r
+ /* Indirection file */\r
+ ad = &argDescriptorIndirection;\r
+ ch = get(cl);\r
+ } else {\r
+ /* Positional argument */\r
+ ad = &argDescriptors[posarg++];\r
+ strcpy(argName, ad->argName);\r
+ }\r
+\r
+ if (ad->argType == ArgTrue) {\r
+ *(Boolean *) ad->argLoc = TRUE;\r
+ continue;\r
+ }\r
+ if (ad->argType == ArgFalse) {\r
+ *(Boolean *) ad->argLoc = FALSE;\r
+ continue;\r
+ }\r
+\r
+ while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);\r
+ if (ch == NULLCHAR || ch == '\n') {\r
+ ExitArgError("No value provided for argument", argName);\r
+ }\r
+ q = argValue;\r
+ if (ch == '{') {\r
+ // Quoting with { }. No characters have to (or can) be escaped.\r
+ // Thus the string cannot contain a '}' character.\r
+ start = ch;\r
+ ch = get(cl);\r
+ while (start) {\r
+ switch (ch) {\r
+ case NULLCHAR:\r
+ start = NULLCHAR;\r
+ break;\r
+ \r
+ case '}':\r
+ ch = get(cl);\r
+ start = NULLCHAR;\r
+ break;\r
+\r
+ default:\r
+ *q++ = ch;\r
+ ch = get(cl);\r
+ break;\r
+ }\r
+ } \r
+ } else if (ch == '\'' || ch == '"') {\r
+ // Quoting with ' ' or " ", with \ as escape character.\r
+ // Inconvenient for long strings that may contain Windows filenames.\r
+ start = ch;\r
+ ch = get(cl);\r
+ while (start) {\r
+ switch (ch) {\r
+ case NULLCHAR:\r
+ start = NULLCHAR;\r
+ break;\r
+\r
+ default:\r
+ not_special:\r
+ *q++ = ch;\r
+ ch = get(cl);\r
+ break;\r
+\r
+ case '\'':\r
+ case '\"':\r
+ if (ch == start) {\r
+ ch = get(cl);\r
+ start = NULLCHAR;\r
+ break;\r
+ } else {\r
+ goto not_special;\r
+ }\r
+\r
+ case '\\':\r
+ if (ad->argType == ArgFilename\r
+ || ad->argType == ArgSettingsFilename) {\r
+ goto not_special;\r
+ }\r
+ ch = get(cl);\r
+ switch (ch) {\r
+ case NULLCHAR:\r
+ ExitArgError("Incomplete \\ escape in value for", argName);\r
+ break;\r
+ case 'n':\r
+ *q++ = '\n';\r
+ ch = get(cl);\r
+ break;\r
+ case 'r':\r
+ *q++ = '\r';\r
+ ch = get(cl);\r
+ break;\r
+ case 't':\r
+ *q++ = '\t';\r
+ ch = get(cl);\r
+ break;\r
+ case 'b':\r
+ *q++ = '\b';\r
+ ch = get(cl);\r
+ break;\r
+ case 'f':\r
+ *q++ = '\f';\r
+ ch = get(cl);\r
+ break;\r
+ default:\r
+ octval = 0;\r
+ for (i = 0; i < 3; i++) {\r
+ if (ch >= '0' && ch <= '7') {\r
+ octval = octval*8 + (ch - '0');\r
+ ch = get(cl);\r
+ } else {\r
+ break;\r
+ }\r
+ }\r
+ if (i > 0) {\r
+ *q++ = (char) octval;\r
+ } else {\r
+ *q++ = ch;\r
+ ch = get(cl);\r
+ }\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ } else {\r
+ while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {\r
+ *q++ = ch;\r
+ ch = get(cl);\r
+ }\r
+ }\r
+ *q = NULLCHAR;\r
+\r
+ switch (ad->argType) {\r
+ case ArgInt:\r
+ *(int *) ad->argLoc = ValidateInt(argValue);\r
+ break;\r
+\r
+ case ArgX:\r
+ *(int *) ad->argLoc = ValidateInt(argValue) + boardX; // [HGM] placement: translate stored relative to absolute \r
+ break;\r
+\r
+ case ArgY:\r
+ *(int *) ad->argLoc = ValidateInt(argValue) + boardY; // (this is really kludgey, it should be done where used...)\r
+ break;\r
+\r
+ case ArgZ:\r
+ *(int *) ad->argLoc = ValidateInt(argValue);\r
+ EnsureOnScreen(&boardX, &boardY, minX, minY); \r
+ break;\r
+\r
+ case ArgFloat:\r
+ *(float *) ad->argLoc = (float) atof(argValue);\r
+ break;\r
+\r
+ case ArgString:\r
+ case ArgFilename:\r
+ *(char **) ad->argLoc = strdup(argValue);\r
+ break;\r
+\r
+ case ArgSettingsFilename:\r
+ {\r
+ char fullname[MSG_SIZ];\r
+ if (ParseSettingsFile(argValue, fullname)) {\r
+ if (ad->argLoc != NULL) {\r
+ *(char **) ad->argLoc = strdup(fullname);\r
+ }\r
+ } else {\r
+ if (ad->argLoc != NULL) {\r
+ } else {\r
+ ExitArgError("Failed to open indirection file", argValue);\r
+ }\r
+ }\r
+ }\r
+ break;\r
+\r
+ case ArgBoolean:\r
+ switch (argValue[0]) {\r
+ case 't':\r
+ case 'T':\r
+ *(Boolean *) ad->argLoc = TRUE;\r
+ break;\r
+ case 'f':\r
+ case 'F':\r
+ *(Boolean *) ad->argLoc = FALSE;\r
+ break;\r
+ default:\r
+ ExitArgError("Unrecognized boolean argument value", argValue);\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case ArgColor:\r
+ *(COLORREF *)ad->argLoc = ParseColorName(argValue);\r
+ break;\r
+\r
+ case ArgAttribs: {\r
+ ColorClass cc = (ColorClass)ad->argLoc;\r
+ ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);\r
+ }\r
+ break;\r
+ \r
+ case ArgBoardSize:\r
+ *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);\r
+ break;\r
+\r
+ case ArgFont:\r
+ ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);\r
+ break;\r
+\r
+ case ArgCommSettings:\r
+ ParseCommSettings(argValue, &dcb);\r
+ break;\r
+\r
+ case ArgNone:\r
+ ExitArgError("Unrecognized argument", argValue);\r
+ break;\r
+ case ArgTrue:\r
+ case ArgFalse: ;\r
+ }\r
+ }\r
+}\r
+\r
+VOID\r
+LFfromMFP(LOGFONT* lf, MyFontParams *mfp)\r
+{\r
+ HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);\r
+ lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);\r
+ DeleteDC(hdc);\r
+ lf->lfWidth = 0;\r
+ lf->lfEscapement = 0;\r
+ lf->lfOrientation = 0;\r
+ lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;\r
+ lf->lfItalic = mfp->italic;\r
+ lf->lfUnderline = mfp->underline;\r
+ lf->lfStrikeOut = mfp->strikeout;\r
+ lf->lfCharSet = mfp->charset;\r
+ lf->lfOutPrecision = OUT_DEFAULT_PRECIS;\r
+ lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
+ lf->lfQuality = DEFAULT_QUALITY;\r
+ lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;\r
+ strcpy(lf->lfFaceName, mfp->faceName);\r
+}\r
+\r
+VOID\r
+CreateFontInMF(MyFont *mf)\r
+{\r
+ LFfromMFP(&mf->lf, &mf->mfp);\r
+ if (mf->hf) DeleteObject(mf->hf);\r
+ mf->hf = CreateFontIndirect(&mf->lf);\r
+}\r
+\r
+VOID\r
+SetDefaultTextAttribs()\r
+{\r
+ ColorClass cc;\r
+ for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
+ ParseAttribs(&textAttribs[cc].color, \r
+ &textAttribs[cc].effects, \r
+ defaultTextAttribs[cc]);\r
+ }\r
+}\r
+\r
+VOID\r
+SetDefaultSounds()\r
+{\r
+ ColorClass cc;\r
+ SoundClass sc;\r
+ for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
+ textAttribs[cc].sound.name = strdup("");\r
+ textAttribs[cc].sound.data = NULL;\r
+ }\r
+ for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
+ sounds[sc].name = strdup("");\r
+ sounds[sc].data = NULL;\r
+ }\r
+ sounds[(int)SoundBell].name = strdup(SOUND_BELL);\r
+}\r
+\r
+VOID\r
+LoadAllSounds()\r
+{\r
+ ColorClass cc;\r
+ SoundClass sc;\r
+ for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
+ MyLoadSound(&textAttribs[cc].sound);\r
+ }\r
+ for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
+ MyLoadSound(&sounds[sc]);\r
+ }\r
+}\r
+\r
+VOID\r
+InitAppData(LPSTR lpCmdLine)\r
+{\r
+ int i, j;\r
+ char buf[ARG_MAX], currDir[MSG_SIZ];\r
+ char *dummy, *p;\r
+\r
+ programName = szAppName;\r
+\r
+ /* Initialize to defaults */\r
+ lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);\r
+ darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);\r
+ whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);\r
+ blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);\r
+ highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);\r
+ premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);\r
+ consoleBackgroundColor = ParseColorName(COLOR_BKGD);\r
+ SetDefaultTextAttribs();\r
+ SetDefaultSounds();\r
+ appData.movesPerSession = MOVES_PER_SESSION;\r
+ appData.initString = INIT_STRING;\r
+ appData.secondInitString = INIT_STRING;\r
+ appData.firstComputerString = COMPUTER_STRING;\r
+ appData.secondComputerString = COMPUTER_STRING;\r
+ appData.firstChessProgram = FIRST_CHESS_PROGRAM;\r
+ appData.secondChessProgram = SECOND_CHESS_PROGRAM;\r
+ appData.firstPlaysBlack = FALSE;\r
+ appData.noChessProgram = FALSE;\r
+ chessProgram = FALSE;\r
+ appData.firstHost = FIRST_HOST;\r
+ appData.secondHost = SECOND_HOST;\r
+ appData.firstDirectory = FIRST_DIRECTORY;\r
+ appData.secondDirectory = SECOND_DIRECTORY;\r
+ appData.bitmapDirectory = "";\r
+ appData.remoteShell = REMOTE_SHELL;\r
+ appData.remoteUser = "";\r
+ appData.timeDelay = TIME_DELAY;\r
+ appData.timeControl = TIME_CONTROL;\r
+ appData.timeIncrement = TIME_INCREMENT;\r
+ appData.icsActive = FALSE;\r
+ appData.icsHost = "";\r
+ appData.icsPort = ICS_PORT;\r
+ appData.icsCommPort = ICS_COMM_PORT;\r
+ appData.icsLogon = ICS_LOGON;\r
+ appData.icsHelper = "";\r
+ appData.useTelnet = FALSE;\r
+ appData.telnetProgram = TELNET_PROGRAM;\r
+ appData.gateway = "";\r
+ appData.loadGameFile = "";\r
+ appData.loadGameIndex = 0;\r
+ appData.saveGameFile = "";\r
+ appData.autoSaveGames = FALSE;\r
+ appData.loadPositionFile = "";\r
+ appData.loadPositionIndex = 1;\r
+ appData.savePositionFile = "";\r
+ appData.matchMode = FALSE;\r
+ appData.matchGames = 0;\r
+ appData.monoMode = FALSE;\r
+ appData.debugMode = FALSE;\r
+ appData.clockMode = TRUE;\r
+ boardSize = (BoardSize) -1; /* determine by screen size */\r
+ appData.Iconic = FALSE; /*unused*/\r
+ appData.searchTime = "";\r
+ appData.searchDepth = 0;\r
+ appData.showCoords = FALSE;\r
+ appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/\r
+ appData.autoCallFlag = FALSE;\r
+ appData.flipView = FALSE;\r
+ appData.autoFlipView = TRUE;\r
+ appData.cmailGameName = "";\r
+ appData.alwaysPromoteToQueen = FALSE;\r
+ appData.oldSaveStyle = FALSE;\r
+ appData.quietPlay = FALSE;\r
+ appData.showThinking = FALSE;\r
+ appData.ponderNextMove = TRUE;\r
+ appData.periodicUpdates = TRUE;\r
+ appData.popupExitMessage = TRUE;\r
+ appData.popupMoveErrors = FALSE;\r
+ appData.autoObserve = FALSE;\r
+ appData.autoComment = FALSE;\r
+ appData.animate = TRUE;\r
+ appData.animSpeed = 10;\r
+ appData.animateDragging = TRUE;\r
+ appData.highlightLastMove = TRUE;\r
+ appData.getMoveList = TRUE;\r
+ appData.testLegality = TRUE;\r
+ appData.premove = TRUE;\r
+ appData.premoveWhite = FALSE;\r
+ appData.premoveWhiteText = "";\r
+ appData.premoveBlack = FALSE;\r
+ appData.premoveBlackText = "";\r
+ appData.icsAlarm = TRUE;\r
+ appData.icsAlarmTime = 5000;\r
+ appData.autoRaiseBoard = TRUE;\r
+ appData.localLineEditing = TRUE;\r
+ appData.colorize = TRUE;\r
+ appData.reuseFirst = TRUE;\r
+ appData.reuseSecond = TRUE;\r
+ appData.blindfold = FALSE;\r
+ appData.icsEngineAnalyze = FALSE;\r
+ memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +\r
+ dcb.DCBlength = sizeof(DCB);\r
+ dcb.BaudRate = 9600;\r
+ dcb.fBinary = TRUE;\r
+ dcb.fParity = FALSE;\r
+ dcb.fOutxCtsFlow = FALSE;\r
+ dcb.fOutxDsrFlow = FALSE;\r
+ dcb.fDtrControl = DTR_CONTROL_ENABLE;\r
+ dcb.fDsrSensitivity = FALSE;\r
+ dcb.fTXContinueOnXoff = TRUE;\r
+ dcb.fOutX = FALSE;\r
+ dcb.fInX = FALSE;\r
+ dcb.fNull = FALSE;\r
+ dcb.fRtsControl = RTS_CONTROL_ENABLE;\r
+ dcb.fAbortOnError = FALSE;\r
+ dcb.ByteSize = 7;\r
+ dcb.Parity = SPACEPARITY;\r
+ dcb.StopBits = ONESTOPBIT;\r
+ settingsFileName = SETTINGS_FILE;\r
+ saveSettingsOnExit = TRUE;\r
+ boardX = CW_USEDEFAULT;\r
+ boardY = CW_USEDEFAULT;\r
+ analysisX = CW_USEDEFAULT; \r
+ analysisY = CW_USEDEFAULT; \r
+ analysisW = CW_USEDEFAULT;\r
+ analysisH = CW_USEDEFAULT;\r
+ commentX = CW_USEDEFAULT; \r
+ commentY = CW_USEDEFAULT; \r
+ commentW = CW_USEDEFAULT;\r
+ commentH = CW_USEDEFAULT;\r
+ editTagsX = CW_USEDEFAULT; \r
+ editTagsY = CW_USEDEFAULT; \r
+ editTagsW = CW_USEDEFAULT;\r
+ editTagsH = CW_USEDEFAULT;\r
+ icsTextMenuString = ICS_TEXT_MENU_DEFAULT;\r
+ icsNames = ICS_NAMES;\r
+ firstChessProgramNames = FCP_NAMES;\r
+ secondChessProgramNames = SCP_NAMES;\r
+ appData.initialMode = "";\r
+ appData.variant = "normal";\r
+ appData.firstProtocolVersion = PROTOVER;\r
+ appData.secondProtocolVersion = PROTOVER;\r
+ appData.showButtonBar = TRUE;\r
+\r
+ /* [AS] New properties (see comments in header file) */\r
+ appData.firstScoreIsAbsolute = FALSE;\r
+ appData.secondScoreIsAbsolute = FALSE;\r
+ appData.saveExtendedInfoInPGN = FALSE;\r
+ appData.hideThinkingFromHuman = FALSE;\r
+ appData.liteBackTextureFile = "";\r
+ appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
+ appData.darkBackTextureFile = "";\r
+ appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
+ appData.renderPiecesWithFont = "";\r
+ appData.fontToPieceTable = "";\r
+ appData.fontBackColorWhite = 0;\r
+ appData.fontForeColorWhite = 0;\r
+ appData.fontBackColorBlack = 0;\r
+ appData.fontForeColorBlack = 0;\r
+ appData.fontPieceSize = 80;\r
+ appData.overrideLineGap = 1;\r
+ appData.adjudicateLossThreshold = 0;\r
+ appData.delayBeforeQuit = 0;\r
+ appData.delayAfterQuit = 0;\r
+ appData.nameOfDebugFile = "winboard.debug";\r
+ appData.pgnEventHeader = "Computer Chess Game";\r
+ appData.defaultFrcPosition = -1;\r
+ appData.gameListTags = GLT_DEFAULT_TAGS;\r
+ appData.saveOutOfBookInfo = TRUE;\r
+ appData.showEvalInMoveHistory = TRUE;\r
+ appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );\r
+ appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );\r
+ appData.highlightMoveWithArrow = FALSE;\r
+ appData.highlightArrowColor = ParseColorName( "#FFFF80" );\r
+ appData.useStickyWindows = TRUE;\r
+ appData.adjudicateDrawMoves = 0;\r
+ appData.autoDisplayComment = TRUE;\r
+ appData.autoDisplayTags = TRUE;\r
+ appData.firstIsUCI = FALSE;\r
+ appData.secondIsUCI = FALSE;\r
+ appData.firstHasOwnBookUCI = TRUE;\r
+ appData.secondHasOwnBookUCI = TRUE;\r
+ appData.polyglotDir = "";\r
+ appData.usePolyglotBook = FALSE;\r
+ appData.polyglotBook = "";\r
+ appData.defaultHashSize = 64;\r
+ appData.defaultCacheSizeEGTB = 4;\r
+ appData.defaultPathEGTB = "c:\\egtb";\r
+ appData.firstOptions = "";\r
+ appData.secondOptions = "";\r
+\r
+ InitWindowPlacement( &wpGameList );\r
+ InitWindowPlacement( &wpMoveHistory );\r
+ InitWindowPlacement( &wpEvalGraph );\r
+ InitWindowPlacement( &wpEngineOutput );\r
+ InitWindowPlacement( &wpConsole );\r
+\r
+ /* [HGM] User-selectable board size, adjudication control, miscellaneous */\r
+ appData.NrFiles = -1;\r
+ appData.NrRanks = -1;\r
+ appData.holdingsSize = -1;\r
+ appData.testClaims = FALSE;\r
+ appData.checkMates = FALSE;\r
+ appData.materialDraws= FALSE;\r
+ appData.trivialDraws = FALSE;\r
+ appData.ruleMoves = 51;\r
+ appData.drawRepeats = 6;\r
+ appData.matchPause = 10000;\r
+ appData.alphaRank = FALSE;\r
+ appData.allWhite = FALSE;\r
+ appData.upsideDown = FALSE;\r
+ appData.serverPause = 15;\r
+ appData.serverMovesName = NULL;\r
+ appData.suppressLoadMoves = FALSE;\r
+ appData.firstTimeOdds = 1;\r
+ appData.secondTimeOdds = 1;\r
+ appData.firstAccumulateTC = 1; // combine previous and current sessions\r
+ appData.secondAccumulateTC = 1;\r
+ appData.firstNPS = -1; // [HGM] nps: use wall-clock time\r
+ appData.secondNPS = -1;\r
+ appData.engineComments = 1;\r
+ appData.smpCores = 1; // [HGM] SMP: max nr of cores\r
+ appData.egtFormats = "";\r
+\r
+#ifdef ZIPPY\r
+ appData.zippyTalk = ZIPPY_TALK;\r
+ appData.zippyPlay = ZIPPY_PLAY;\r
+ appData.zippyLines = ZIPPY_LINES;\r
+ appData.zippyPinhead = ZIPPY_PINHEAD;\r
+ appData.zippyPassword = ZIPPY_PASSWORD;\r
+ appData.zippyPassword2 = ZIPPY_PASSWORD2;\r
+ appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;\r
+ appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;\r
+ appData.zippyUseI = ZIPPY_USE_I;\r
+ appData.zippyBughouse = ZIPPY_BUGHOUSE;\r
+ appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;\r
+ appData.zippyGameEnd = ZIPPY_GAME_END;\r
+ appData.zippyGameStart = ZIPPY_GAME_START;\r
+ appData.zippyAdjourn = ZIPPY_ADJOURN;\r
+ appData.zippyAbort = ZIPPY_ABORT;\r
+ appData.zippyVariants = ZIPPY_VARIANTS;\r
+ appData.zippyMaxGames = ZIPPY_MAX_GAMES;\r
+ appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;\r
+#endif\r
+\r
+ /* Point font array elements to structures and\r
+ parse default font names */\r
+ for (i=0; i<NUM_FONTS; i++) {\r
+ for (j=0; j<NUM_SIZES; j++) {\r
+ font[j][i] = &fontRec[j][i];\r
+ ParseFontName(font[j][i]->def, &font[j][i]->mfp);\r
+ }\r
+ }\r
+ \r
+ /* Parse default settings file if any */\r
+ if (ParseSettingsFile(settingsFileName, buf)) {\r
+ settingsFileName = strdup(buf);\r
+ }\r
+\r
+ /* Parse command line */\r
+ ParseArgs(StringGet, &lpCmdLine);\r
+\r
+ /* [HGM] make sure board size is acceptable */\r
+ if(appData.NrFiles > BOARD_SIZE ||\r
+ appData.NrRanks > BOARD_SIZE )\r
+ DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);\r
+\r
+ /* [HGM] After parsing the options from the .ini file, and overruling them\r
+ * with options from the command line, we now make an even higher priority\r
+ * overrule by WB options attached to the engine command line. This so that\r
+ * tournament managers can use WB options (such as /timeOdds) that follow\r
+ * the engines.\r
+ */\r
+ if(appData.firstChessProgram != NULL) {\r
+ char *p = StrStr(appData.firstChessProgram, "WBopt");\r
+ static char *f = "first";\r
+ char buf[MSG_SIZ], *q = buf;\r
+ if(p != NULL) { // engine command line contains WinBoard options\r
+ sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"\r
+ ParseArgs(StringGet, &q);\r
+ p[-1] = 0; // cut them offengine command line\r
+ }\r
+ }\r
+ // now do same for second chess program\r
+ if(appData.secondChessProgram != NULL) {\r
+ char *p = StrStr(appData.secondChessProgram, "WBopt");\r
+ static char *s = "second";\r
+ char buf[MSG_SIZ], *q = buf;\r
+ if(p != NULL) { // engine command line contains WinBoard options\r
+ sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"\r
+ ParseArgs(StringGet, &q);\r
+ p[-1] = 0; // cut them offengine command line\r
+ }\r
+ }\r
+\r
+\r
+ /* Propagate options that affect others */\r
+ if (appData.matchMode || appData.matchGames) chessProgram = TRUE;\r
+ if (appData.icsActive || appData.noChessProgram) {\r
+ chessProgram = FALSE; /* not local chess program mode */\r
+ }\r
+\r
+ /* Open startup dialog if needed */\r
+ if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||\r
+ (appData.icsActive && *appData.icsHost == NULLCHAR) ||\r
+ (chessProgram && (*appData.firstChessProgram == NULLCHAR ||\r
+ *appData.secondChessProgram == NULLCHAR))) {\r
+ FARPROC lpProc;\r
+ \r
+ lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);\r
+ DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);\r
+ FreeProcInstance(lpProc);\r
+ }\r
+\r
+ /* Make sure save files land in the right (?) directory */\r
+ if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {\r
+ appData.saveGameFile = strdup(buf);\r
+ }\r
+ if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {\r
+ appData.savePositionFile = strdup(buf);\r
+ }\r
+\r
+ /* Finish initialization for fonts and sounds */\r
+ for (i=0; i<NUM_FONTS; i++) {\r
+ for (j=0; j<NUM_SIZES; j++) {\r
+ CreateFontInMF(font[j][i]);\r
+ }\r
+ }\r
+ /* xboard, and older WinBoards, controlled the move sound with the\r
+ appData.ringBellAfterMoves option. In the current WinBoard, we\r
+ always turn the option on (so that the backend will call us),\r
+ then let the user turn the sound off by setting it to silence if\r
+ desired. To accommodate old winboard.ini files saved by old\r
+ versions of WinBoard, we also turn off the sound if the option\r
+ was initially set to false. */\r
+ if (!appData.ringBellAfterMoves) {\r
+ sounds[(int)SoundMove].name = strdup("");\r
+ appData.ringBellAfterMoves = TRUE;\r
+ }\r
+ GetCurrentDirectory(MSG_SIZ, currDir);\r
+ SetCurrentDirectory(installDir);\r
+ LoadAllSounds();\r
+ SetCurrentDirectory(currDir);\r
+\r
+ p = icsTextMenuString;\r
+ if (p[0] == '@') {\r
+ FILE* f = fopen(p + 1, "r");\r
+ if (f == NULL) {\r
+ DisplayFatalError(p + 1, errno, 2);\r
+ return;\r
+ }\r
+ i = fread(buf, 1, sizeof(buf)-1, f);\r
+ fclose(f);\r
+ buf[i] = NULLCHAR;\r
+ p = buf;\r
+ }\r
+ ParseIcsTextMenu(strdup(p));\r
+}\r
+\r
+\r
+VOID\r
+InitMenuChecks()\r
+{\r
+ HMENU hmenu = GetMenu(hwndMain);\r
+\r
+ (void) EnableMenuItem(hmenu, IDM_CommPort,\r
+ MF_BYCOMMAND|((appData.icsActive &&\r
+ *appData.icsCommPort != NULLCHAR) ?\r
+ MF_ENABLED : MF_GRAYED));\r
+ (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,\r
+ MF_BYCOMMAND|(saveSettingsOnExit ?\r
+ MF_CHECKED : MF_UNCHECKED));\r
+}\r
+\r
+\r
+VOID\r
+SaveSettings(char* name)\r
+{\r
+ FILE *f;\r
+ ArgDescriptor *ad;\r
+ WINDOWPLACEMENT wp;\r
+ char dir[MSG_SIZ];\r
+\r
+ if (!hwndMain) return;\r
+\r
+ GetCurrentDirectory(MSG_SIZ, dir);\r
+ SetCurrentDirectory(installDir);\r
+ f = fopen(name, "w");\r
+ SetCurrentDirectory(dir);\r
+ if (f == NULL) {\r
+ DisplayError(name, errno);\r
+ return;\r
+ }\r
+ fprintf(f, ";\n");\r
+ fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);\r
+ fprintf(f, ";\n");\r
+ fprintf(f, "; You can edit the values of options that are already set in this file,\n");\r
+ fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");\r
+ fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");\r
+ fprintf(f, ";\n");\r
+\r
+ wp.length = sizeof(WINDOWPLACEMENT);\r
+ GetWindowPlacement(hwndMain, &wp);\r
+ boardX = wp.rcNormalPosition.left;\r
+ boardY = wp.rcNormalPosition.top;\r
+\r
+ if (hwndConsole) {\r
+ GetWindowPlacement(hwndConsole, &wp);\r
+ wpConsole.x = wp.rcNormalPosition.left;\r
+ wpConsole.y = wp.rcNormalPosition.top;\r
+ wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+ wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+ }\r
+\r
+ if (analysisDialog) {\r
+ GetWindowPlacement(analysisDialog, &wp);\r
+ analysisX = wp.rcNormalPosition.left;\r
+ analysisY = wp.rcNormalPosition.top;\r
+ analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+ analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+ }\r
+\r
+ if (commentDialog) {\r
+ GetWindowPlacement(commentDialog, &wp);\r
+ commentX = wp.rcNormalPosition.left;\r
+ commentY = wp.rcNormalPosition.top;\r
+ commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+ commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+ }\r
+\r
+ if (editTagsDialog) {\r
+ GetWindowPlacement(editTagsDialog, &wp);\r
+ editTagsX = wp.rcNormalPosition.left;\r
+ editTagsY = wp.rcNormalPosition.top;\r
+ editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+ editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+ }\r
+\r
+ if (gameListDialog) {\r
+ GetWindowPlacement(gameListDialog, &wp);\r
+ wpGameList.x = wp.rcNormalPosition.left;\r
+ wpGameList.y = wp.rcNormalPosition.top;\r
+ wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+ wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+ }\r
+\r
+ /* [AS] Move history */\r
+ wpMoveHistory.visible = MoveHistoryIsUp();\r
+ \r
+ if( moveHistoryDialog ) {\r
+ GetWindowPlacement(moveHistoryDialog, &wp);\r
+ wpMoveHistory.x = wp.rcNormalPosition.left;\r
+ wpMoveHistory.y = wp.rcNormalPosition.top;\r
+ wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+ wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+ }\r
+\r
+ /* [AS] Eval graph */\r
+ wpEvalGraph.visible = EvalGraphIsUp();\r
+\r
+ if( evalGraphDialog ) {\r
+ GetWindowPlacement(evalGraphDialog, &wp);\r
+ wpEvalGraph.x = wp.rcNormalPosition.left;\r
+ wpEvalGraph.y = wp.rcNormalPosition.top;\r
+ wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+ wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+ }\r
+\r
+ /* [AS] Engine output */\r
+ wpEngineOutput.visible = EngineOutputIsUp();\r
+\r
+ if( engineOutputDialog ) {\r
+ GetWindowPlacement(engineOutputDialog, &wp);\r
+ wpEngineOutput.x = wp.rcNormalPosition.left;\r
+ wpEngineOutput.y = wp.rcNormalPosition.top;\r
+ wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+ wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+ }\r
+\r
+ for (ad = argDescriptors; ad->argName != NULL; ad++) {\r
+ if (!ad->save) continue;\r
+ switch (ad->argType) {\r
+ case ArgString:\r
+ {\r
+ char *p = *(char **)ad->argLoc;\r
+ if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {\r
+ /* Quote multiline values or \-containing values\r
+ with { } if possible */\r
+ fprintf(f, "/%s={%s}\n", ad->argName, p);\r
+ } else {\r
+ /* Else quote with " " */\r
+ fprintf(f, "/%s=\"", ad->argName);\r
+ while (*p) {\r
+ if (*p == '\n') fprintf(f, "\n");\r
+ else if (*p == '\r') fprintf(f, "\\r");\r
+ else if (*p == '\t') fprintf(f, "\\t");\r
+ else if (*p == '\b') fprintf(f, "\\b");\r
+ else if (*p == '\f') fprintf(f, "\\f");\r
+ else if (*p < ' ') fprintf(f, "\\%03o", *p);\r
+ else if (*p == '\"') fprintf(f, "\\\"");\r
+ else if (*p == '\\') fprintf(f, "\\\\");\r
+ else putc(*p, f);\r
+ p++;\r
+ }\r
+ fprintf(f, "\"\n");\r
+ }\r
+ }\r
+ break;\r
+ case ArgInt:\r
+ case ArgZ:\r
+ fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);\r
+ break;\r
+ case ArgX:\r
+ fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value\r
+ break;\r
+ case ArgY:\r
+ fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);\r
+ break;\r
+ case ArgFloat:\r
+ fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);\r
+ break;\r
+ case ArgBoolean:\r
+ fprintf(f, "/%s=%s\n", ad->argName, \r
+ (*(Boolean *)ad->argLoc) ? "true" : "false");\r
+ break;\r
+ case ArgTrue:\r
+ if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
+ break;\r
+ case ArgFalse:\r
+ if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
+ break;\r
+ case ArgColor:\r
+ {\r
+ COLORREF color = *(COLORREF *)ad->argLoc;\r
+ fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName, \r
+ color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
+ }\r
+ break;\r
+ case ArgAttribs:\r
+ {\r
+ MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];\r
+ fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,\r
+ (ta->effects & CFE_BOLD) ? "b" : "",\r
+ (ta->effects & CFE_ITALIC) ? "i" : "",\r
+ (ta->effects & CFE_UNDERLINE) ? "u" : "",\r
+ (ta->effects & CFE_STRIKEOUT) ? "s" : "",\r
+ (ta->effects) ? " " : "",\r
+ ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);\r
+ }\r
+ break;\r
+ case ArgFilename:\r
+ if (strchr(*(char **)ad->argLoc, '\"')) {\r
+ fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);\r
+ } else {\r
+ fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);\r
+ }\r
+ break;\r
+ case ArgBoardSize:\r
+ fprintf(f, "/%s=%s\n", ad->argName,\r
+ sizeInfo[*(BoardSize *)ad->argLoc].name);\r
+ break;\r
+ case ArgFont:\r
+ {\r
+ int bs;\r
+ for (bs=0; bs<NUM_SIZES; bs++) {\r
+ MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;\r
+ fprintf(f, "/size=%s ", sizeInfo[bs].name);\r
+ fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",\r
+ ad->argName, mfp->faceName, mfp->pointSize,\r
+ mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",\r
+ mfp->bold ? "b" : "",\r
+ mfp->italic ? "i" : "",\r
+ mfp->underline ? "u" : "",\r
+ mfp->strikeout ? "s" : "",\r
+ (int)mfp->charset);\r
+ }\r
+ }\r
+ break;\r
+ case ArgCommSettings:\r
+ PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);\r
+ case ArgNone:\r
+ case ArgSettingsFilename: ;\r
+ }\r
+ }\r
+ fclose(f);\r
+}\r
+\r
+\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * GDI board drawing routines\r
+ *\r
+\*---------------------------------------------------------------------------*/\r
+\r
+/* [AS] Draw square using background texture */\r
+static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )\r
+{\r
+ XFORM x;\r
+\r
+ if( mode == 0 ) {\r
+ return; /* Should never happen! */\r
+ }\r
+\r
+ SetGraphicsMode( dst, GM_ADVANCED );\r
+\r
+ switch( mode ) {\r
+ case 1:\r
+ /* Identity */\r
+ break;\r
+ case 2:\r
+ /* X reflection */\r
+ x.eM11 = -1.0;\r
+ x.eM12 = 0;\r
+ x.eM21 = 0;\r
+ x.eM22 = 1.0;\r
+ x.eDx = (FLOAT) dw + dx - 1;\r
+ x.eDy = 0;\r
+ dx = 0;\r
+ SetWorldTransform( dst, &x );\r
+ break;\r
+ case 3:\r
+ /* Y reflection */\r
+ x.eM11 = 1.0;\r
+ x.eM12 = 0;\r
+ x.eM21 = 0;\r
+ x.eM22 = -1.0;\r
+ x.eDx = 0;\r
+ x.eDy = (FLOAT) dh + dy - 1;\r
+ dy = 0;\r
+ SetWorldTransform( dst, &x );\r
+ break;\r
+ case 4:\r
+ /* X/Y flip */\r
+ x.eM11 = 0;\r
+ x.eM12 = 1.0;\r
+ x.eM21 = 1.0;\r
+ x.eM22 = 0;\r
+ x.eDx = (FLOAT) dx;\r
+ x.eDy = (FLOAT) dy;\r
+ dx = 0;\r
+ dy = 0;\r
+ SetWorldTransform( dst, &x );\r
+ break;\r
+ }\r
+\r
+ BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );\r
+\r
+ x.eM11 = 1.0;\r
+ x.eM12 = 0;\r
+ x.eM21 = 0;\r
+ x.eM22 = 1.0;\r
+ x.eDx = 0;\r
+ x.eDy = 0;\r
+ SetWorldTransform( dst, &x );\r
+\r
+ ModifyWorldTransform( dst, 0, MWT_IDENTITY );\r
+}\r
+\r
+/* [AS] [HGM] Make room for more piece types, so all pieces can be different */\r
+enum {\r
+ PM_WP = (int) WhitePawn, \r
+ PM_WN = (int) WhiteKnight, \r
+ PM_WB = (int) WhiteBishop, \r
+ PM_WR = (int) WhiteRook, \r
+ PM_WQ = (int) WhiteQueen, \r
+ PM_WF = (int) WhiteFerz, \r
+ PM_WW = (int) WhiteWazir, \r
+ PM_WE = (int) WhiteAlfil, \r
+ PM_WM = (int) WhiteMan, \r
+ PM_WO = (int) WhiteCannon, \r
+ PM_WU = (int) WhiteUnicorn, \r
+ PM_WH = (int) WhiteNightrider, \r
+ PM_WA = (int) WhiteAngel, \r
+ PM_WC = (int) WhiteMarshall, \r
+ PM_WAB = (int) WhiteCardinal, \r
+ PM_WD = (int) WhiteDragon, \r
+ PM_WL = (int) WhiteLance, \r
+ PM_WS = (int) WhiteCobra, \r
+ PM_WV = (int) WhiteFalcon, \r
+ PM_WSG = (int) WhiteSilver, \r
+ PM_WG = (int) WhiteGrasshopper, \r
+ PM_WK = (int) WhiteKing,\r
+ PM_BP = (int) BlackPawn, \r
+ PM_BN = (int) BlackKnight, \r
+ PM_BB = (int) BlackBishop, \r
+ PM_BR = (int) BlackRook, \r
+ PM_BQ = (int) BlackQueen, \r
+ PM_BF = (int) BlackFerz, \r
+ PM_BW = (int) BlackWazir, \r
+ PM_BE = (int) BlackAlfil, \r
+ PM_BM = (int) BlackMan,\r
+ PM_BO = (int) BlackCannon, \r
+ PM_BU = (int) BlackUnicorn, \r
+ PM_BH = (int) BlackNightrider, \r
+ PM_BA = (int) BlackAngel, \r
+ PM_BC = (int) BlackMarshall, \r
+ PM_BG = (int) BlackGrasshopper, \r
+ PM_BAB = (int) BlackCardinal,\r
+ PM_BD = (int) BlackDragon,\r
+ PM_BL = (int) BlackLance,\r
+ PM_BS = (int) BlackCobra,\r
+ PM_BV = (int) BlackFalcon,\r
+ PM_BSG = (int) BlackSilver,\r
+ PM_BK = (int) BlackKing\r
+};\r
+\r
+static HFONT hPieceFont = NULL;\r
+static HBITMAP hPieceMask[(int) EmptySquare];\r
+static HBITMAP hPieceFace[(int) EmptySquare];\r
+static int fontBitmapSquareSize = 0;\r
+static char pieceToFontChar[(int) EmptySquare] =\r
+ { 'p', 'n', 'b', 'r', 'q', \r
+ 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',\r
+ 'k', 'o', 'm', 'v', 't', 'w', \r
+ 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',\r
+ 'l' };\r
+\r
+extern BOOL SetCharTable( char *table, const char * map );\r
+/* [HGM] moved to backend.c */\r
+\r
+static void SetPieceBackground( HDC hdc, COLORREF color, int mode )\r
+{\r
+ HBRUSH hbrush;\r
+ BYTE r1 = GetRValue( color );\r
+ BYTE g1 = GetGValue( color );\r
+ BYTE b1 = GetBValue( color );\r
+ BYTE r2 = r1 / 2;\r
+ BYTE g2 = g1 / 2;\r
+ BYTE b2 = b1 / 2;\r
+ RECT rc;\r
+\r
+ /* Create a uniform background first */\r
+ hbrush = CreateSolidBrush( color );\r
+ SetRect( &rc, 0, 0, squareSize, squareSize );\r
+ FillRect( hdc, &rc, hbrush );\r
+ DeleteObject( hbrush );\r
+ \r
+ if( mode == 1 ) {\r
+ /* Vertical gradient, good for pawn, knight and rook, less for queen and king */\r
+ int steps = squareSize / 2;\r
+ int i;\r
+\r
+ for( i=0; i<steps; i++ ) {\r
+ BYTE r = r1 - (r1-r2) * i / steps;\r
+ BYTE g = g1 - (g1-g2) * i / steps;\r
+ BYTE b = b1 - (b1-b2) * i / steps;\r
+\r
+ hbrush = CreateSolidBrush( RGB(r,g,b) );\r
+ SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );\r
+ FillRect( hdc, &rc, hbrush );\r
+ DeleteObject(hbrush);\r
+ }\r
+ }\r
+ else if( mode == 2 ) {\r
+ /* Diagonal gradient, good more or less for every piece */\r
+ POINT triangle[3];\r
+ HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );\r
+ HBRUSH hbrush_old;\r
+ int steps = squareSize;\r
+ int i;\r
+\r
+ triangle[0].x = squareSize - steps;\r
+ triangle[0].y = squareSize;\r
+ triangle[1].x = squareSize;\r
+ triangle[1].y = squareSize;\r
+ triangle[2].x = squareSize;\r
+ triangle[2].y = squareSize - steps;\r
+\r
+ for( i=0; i<steps; i++ ) {\r
+ BYTE r = r1 - (r1-r2) * i / steps;\r
+ BYTE g = g1 - (g1-g2) * i / steps;\r
+ BYTE b = b1 - (b1-b2) * i / steps;\r
+\r
+ hbrush = CreateSolidBrush( RGB(r,g,b) );\r
+ hbrush_old = SelectObject( hdc, hbrush );\r
+ Polygon( hdc, triangle, 3 );\r
+ SelectObject( hdc, hbrush_old );\r
+ DeleteObject(hbrush);\r
+ triangle[0].x++;\r
+ triangle[2].y++;\r
+ }\r
+\r
+ SelectObject( hdc, hpen );\r
+ }\r
+}\r
+\r
+/*\r
+ [AS] The method I use to create the bitmaps it a bit tricky, but it\r
+ seems to work ok. The main problem here is to find the "inside" of a chess\r
+ piece: follow the steps as explained below.\r
+*/\r
+static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )\r
+{\r
+ HBITMAP hbm;\r
+ HBITMAP hbm_old;\r
+ COLORREF chroma = RGB(0xFF,0x00,0xFF);\r
+ RECT rc;\r
+ SIZE sz;\r
+ POINT pt;\r
+ int backColor = whitePieceColor; \r
+ int foreColor = blackPieceColor;\r
+ \r
+ if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {\r
+ backColor = appData.fontBackColorWhite;\r
+ foreColor = appData.fontForeColorWhite;\r
+ }\r
+ else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {\r
+ backColor = appData.fontBackColorBlack;\r
+ foreColor = appData.fontForeColorBlack;\r
+ }\r
+\r
+ /* Mask */\r
+ hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
+\r
+ hbm_old = SelectObject( hdc, hbm );\r
+\r
+ rc.left = 0;\r
+ rc.top = 0;\r
+ rc.right = squareSize;\r
+ rc.bottom = squareSize;\r
+\r
+ /* Step 1: background is now black */\r
+ FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );\r
+\r
+ GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );\r
+\r
+ pt.x = (squareSize - sz.cx) / 2;\r
+ pt.y = (squareSize - sz.cy) / 2;\r
+\r
+ SetBkMode( hdc, TRANSPARENT );\r
+ SetTextColor( hdc, chroma );\r
+ /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */\r
+ TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
+\r
+ SelectObject( hdc, GetStockObject(WHITE_BRUSH) );\r
+ /* Step 3: the area outside the piece is filled with white */\r
+// FloodFill( hdc, 0, 0, chroma );\r
+ ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );\r
+ ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big\r
+ ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );\r
+ ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );\r
+ SelectObject( hdc, GetStockObject(BLACK_BRUSH) );\r
+ /* \r
+ Step 4: this is the tricky part, the area inside the piece is filled with black,\r
+ but if the start point is not inside the piece we're lost!\r
+ There should be a better way to do this... if we could create a region or path\r
+ from the fill operation we would be fine for example.\r
+ */\r
+// FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );\r
+ ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );\r
+\r
+ { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */\r
+ HDC dc2 = CreateCompatibleDC( hdc_window );\r
+ HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
+\r
+ SelectObject( dc2, bm2 );\r
+ BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy\r
+ BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
+ BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
+ BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
+ BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
+\r
+ DeleteDC( dc2 );\r
+ DeleteObject( bm2 );\r
+ }\r
+\r
+ SetTextColor( hdc, 0 );\r
+ /* \r
+ Step 5: some fonts have "disconnected" areas that are skipped by the fill:\r
+ draw the piece again in black for safety.\r
+ */\r
+ TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
+\r
+ SelectObject( hdc, hbm_old );\r
+\r
+ if( hPieceMask[index] != NULL ) {\r
+ DeleteObject( hPieceMask[index] );\r
+ }\r
+\r
+ hPieceMask[index] = hbm;\r
+\r
+ /* Face */\r
+ hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
+\r
+ SelectObject( hdc, hbm );\r
+\r
+ {\r
+ HDC dc1 = CreateCompatibleDC( hdc_window );\r
+ HDC dc2 = CreateCompatibleDC( hdc_window );\r
+ HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
+\r
+ SelectObject( dc1, hPieceMask[index] );\r
+ SelectObject( dc2, bm2 );\r
+ FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );\r
+ BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );\r
+ \r
+ /* \r
+ Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves\r
+ the piece background and deletes (makes transparent) the rest.\r
+ Thanks to that mask, we are free to paint the background with the greates\r
+ freedom, as we'll be able to mask off the unwanted parts when finished.\r
+ We use this, to make gradients and give the pieces a "roundish" look.\r
+ */\r
+ SetPieceBackground( hdc, backColor, 2 );\r
+ BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );\r
+\r
+ DeleteDC( dc2 );\r
+ DeleteDC( dc1 );\r
+ DeleteObject( bm2 );\r
+ }\r
+\r
+ SetTextColor( hdc, foreColor );\r
+ TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
+\r
+ SelectObject( hdc, hbm_old );\r
+\r
+ if( hPieceFace[index] != NULL ) {\r
+ DeleteObject( hPieceFace[index] );\r
+ }\r
+\r
+ hPieceFace[index] = hbm;\r
+}\r
+\r
+static int TranslatePieceToFontPiece( int piece )\r
+{\r
+ switch( piece ) {\r
+ case BlackPawn:\r
+ return PM_BP;\r
+ case BlackKnight:\r
+ return PM_BN;\r
+ case BlackBishop:\r
+ return PM_BB;\r
+ case BlackRook:\r
+ return PM_BR;\r
+ case BlackQueen:\r
+ return PM_BQ;\r
+ case BlackKing:\r
+ return PM_BK;\r
+ case WhitePawn:\r
+ return PM_WP;\r
+ case WhiteKnight:\r
+ return PM_WN;\r
+ case WhiteBishop:\r
+ return PM_WB;\r
+ case WhiteRook:\r
+ return PM_WR;\r
+ case WhiteQueen:\r
+ return PM_WQ;\r
+ case WhiteKing:\r
+ return PM_WK;\r
+\r
+ case BlackAngel:\r
+ return PM_BA;\r
+ case BlackMarshall:\r
+ return PM_BC;\r
+ case BlackFerz:\r
+ return PM_BF;\r
+ case BlackNightrider:\r
+ return PM_BH;\r
+ case BlackAlfil:\r
+ return PM_BE;\r
+ case BlackWazir:\r
+ return PM_BW;\r
+ case BlackUnicorn:\r
+ return PM_BU;\r
+ case BlackCannon:\r
+ return PM_BO;\r
+ case BlackGrasshopper:\r
+ return PM_BG;\r
+ case BlackMan:\r
+ return PM_BM;\r
+ case BlackSilver:\r
+ return PM_BSG;\r
+ case BlackLance:\r
+ return PM_BL;\r
+ case BlackFalcon:\r
+ return PM_BV;\r
+ case BlackCobra:\r
+ return PM_BS;\r
+ case BlackCardinal:\r
+ return PM_BAB;\r
+ case BlackDragon:\r
+ return PM_BD;\r
+\r
+ case WhiteAngel:\r
+ return PM_WA;\r
+ case WhiteMarshall:\r
+ return PM_WC;\r
+ case WhiteFerz:\r
+ return PM_WF;\r
+ case WhiteNightrider:\r
+ return PM_WH;\r
+ case WhiteAlfil:\r
+ return PM_WE;\r
+ case WhiteWazir:\r
+ return PM_WW;\r
+ case WhiteUnicorn:\r
+ return PM_WU;\r
+ case WhiteCannon:\r
+ return PM_WO;\r
+ case WhiteGrasshopper:\r
+ return PM_WG;\r
+ case WhiteMan:\r
+ return PM_WM;\r
+ case WhiteSilver:\r
+ return PM_WSG;\r
+ case WhiteLance:\r
+ return PM_WL;\r
+ case WhiteFalcon:\r
+ return PM_WV;\r
+ case WhiteCobra:\r
+ return PM_WS;\r
+ case WhiteCardinal:\r
+ return PM_WAB;\r
+ case WhiteDragon:\r
+ return PM_WD;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+void CreatePiecesFromFont()\r
+{\r
+ LOGFONT lf;\r
+ HDC hdc_window = NULL;\r
+ HDC hdc = NULL;\r
+ HFONT hfont_old;\r
+ int fontHeight;\r
+ int i;\r
+\r
+ if( fontBitmapSquareSize < 0 ) {\r
+ /* Something went seriously wrong in the past: do not try to recreate fonts! */\r
+ return;\r
+ }\r
+\r
+ if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {\r
+ fontBitmapSquareSize = -1;\r
+ return;\r
+ }\r
+\r
+ if( fontBitmapSquareSize != squareSize ) {\r
+ hdc_window = GetDC( hwndMain );\r
+ hdc = CreateCompatibleDC( hdc_window );\r
+\r
+ if( hPieceFont != NULL ) {\r
+ DeleteObject( hPieceFont );\r
+ }\r
+ else {\r
+ for( i=0; i<=(int)BlackKing; i++ ) {\r
+ hPieceMask[i] = NULL;\r
+ hPieceFace[i] = NULL;\r
+ }\r
+ }\r
+\r
+ fontHeight = 75;\r
+\r
+ if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {\r
+ fontHeight = appData.fontPieceSize;\r
+ }\r
+\r
+ fontHeight = (fontHeight * squareSize) / 100;\r
+\r
+ lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );\r
+ lf.lfWidth = 0;\r
+ lf.lfEscapement = 0;\r
+ lf.lfOrientation = 0;\r
+ lf.lfWeight = FW_NORMAL;\r
+ lf.lfItalic = 0;\r
+ lf.lfUnderline = 0;\r
+ lf.lfStrikeOut = 0;\r
+ lf.lfCharSet = DEFAULT_CHARSET;\r
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;\r
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
+ lf.lfQuality = PROOF_QUALITY;\r
+ lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;\r
+ strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );\r
+ lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';\r
+\r
+ hPieceFont = CreateFontIndirect( &lf );\r
+\r
+ if( hPieceFont == NULL ) {\r
+ fontBitmapSquareSize = -2;\r
+ }\r
+ else {\r
+ /* Setup font-to-piece character table */\r
+ if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {\r
+ /* No (or wrong) global settings, try to detect the font */\r
+ if( strstr(lf.lfFaceName,"Alpha") != NULL ) {\r
+ /* Alpha */\r
+ SetCharTable(pieceToFontChar, "phbrqkojntwl");\r
+ }\r
+ else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {\r
+ /* DiagramTT* family */\r
+ SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");\r
+ }\r
+ else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {\r
+ /* Fairy symbols */\r
+ SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");\r
+ }\r
+ else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {\r
+ /* Good Companion (Some characters get warped as literal :-( */\r
+ char s[] = "1cmWG0ñueOS¯®oYI23wgQU";\r
+ s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;\r
+ SetCharTable(pieceToFontChar, s);\r
+ }\r
+ else {\r
+ /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */\r
+ SetCharTable(pieceToFontChar, "pnbrqkomvtwl");\r
+ }\r
+ }\r
+\r
+ /* Create bitmaps */\r
+ hfont_old = SelectObject( hdc, hPieceFont );\r
+ for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */\r
+ if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */\r
+ CreatePieceMaskFromFont( hdc_window, hdc, i );\r
+\r
+ SelectObject( hdc, hfont_old );\r
+\r
+ fontBitmapSquareSize = squareSize;\r
+ }\r
+ }\r
+\r
+ if( hdc != NULL ) {\r
+ DeleteDC( hdc );\r
+ }\r
+\r
+ if( hdc_window != NULL ) {\r
+ ReleaseDC( hwndMain, hdc_window );\r
+ }\r
+}\r
+\r
+HBITMAP\r
+DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)\r
+{\r
+ char name[128];\r
+\r
+ sprintf(name, "%s%d%s", piece, squareSize, suffix);\r
+ if (gameInfo.event &&\r
+ strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&\r
+ strcmp(name, "k80s") == 0) {\r
+ strcpy(name, "tim");\r
+ }\r
+ return LoadBitmap(hinst, name);\r
+}\r
+\r
+\r
+/* Insert a color into the program's logical palette\r
+ structure. This code assumes the given color is\r
+ the result of the RGB or PALETTERGB macro, and it\r
+ knows how those macros work (which is documented).\r
+*/\r
+VOID\r
+InsertInPalette(COLORREF color)\r
+{\r
+ LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);\r
+\r
+ if (pLogPal->palNumEntries++ >= PALETTESIZE) {\r
+ DisplayFatalError("Too many colors", 0, 1);\r
+ pLogPal->palNumEntries--;\r
+ return;\r
+ }\r
+\r
+ pe->peFlags = (char) 0;\r
+ pe->peRed = (char) (0xFF & color);\r
+ pe->peGreen = (char) (0xFF & (color >> 8));\r
+ pe->peBlue = (char) (0xFF & (color >> 16));\r
+ return;\r
+}\r
+\r
+\r
+VOID\r
+InitDrawingColors()\r
+{\r
+ if (pLogPal == NULL) {\r
+ /* Allocate enough memory for a logical palette with\r
+ * PALETTESIZE entries and set the size and version fields\r
+ * of the logical palette structure.\r
+ */\r
+ pLogPal = (NPLOGPALETTE)\r
+ LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +\r
+ (sizeof(PALETTEENTRY) * (PALETTESIZE))));\r
+ pLogPal->palVersion = 0x300;\r
+ }\r
+ pLogPal->palNumEntries = 0;\r
+\r
+ InsertInPalette(lightSquareColor);\r
+ InsertInPalette(darkSquareColor);\r
+ InsertInPalette(whitePieceColor);\r
+ InsertInPalette(blackPieceColor);\r
+ InsertInPalette(highlightSquareColor);\r
+ InsertInPalette(premoveHighlightColor);\r
+\r
+ /* create a logical color palette according the information\r
+ * in the LOGPALETTE structure.\r
+ */\r
+ hPal = CreatePalette((LPLOGPALETTE) pLogPal);\r
+\r
+ lightSquareBrush = CreateSolidBrush(lightSquareColor);\r
+ blackSquareBrush = CreateSolidBrush(blackPieceColor);\r
+ darkSquareBrush = CreateSolidBrush(darkSquareColor);\r
+ whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
+ blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
+ iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
+ explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic\r
+ /* [AS] Force rendering of the font-based pieces */\r
+ if( fontBitmapSquareSize > 0 ) {\r
+ fontBitmapSquareSize = 0;\r
+ }\r
+}\r
+\r
+\r
+int\r
+BoardWidth(int boardSize, int n)\r
+{ /* [HGM] argument n added to allow different width and height */\r
+ int lineGap = sizeInfo[boardSize].lineGap;\r
+\r
+ if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
+ lineGap = appData.overrideLineGap;\r
+ }\r
+\r
+ return (n + 1) * lineGap +\r
+ n * sizeInfo[boardSize].squareSize;\r
+}\r
+\r
+/* Respond to board resize by dragging edge */\r
+VOID\r
+ResizeBoard(int newSizeX, int newSizeY, int flags)\r
+{\r
+ BoardSize newSize = NUM_SIZES - 1;\r
+ static int recurse = 0;\r
+ if (IsIconic(hwndMain)) return;\r
+ if (recurse > 0) return;\r
+ recurse++;\r
+ while (newSize > 0) {\r
+ InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects\r
+ if(newSizeX >= sizeInfo[newSize].cliWidth &&\r
+ newSizeY >= sizeInfo[newSize].cliHeight) break;\r
+ newSize--;\r
+ } \r
+ boardSize = newSize;\r
+ InitDrawingSizes(boardSize, flags);\r
+ recurse--;\r
+}\r
+\r
+\r
+\r
+VOID\r
+InitDrawingSizes(BoardSize boardSize, int flags)\r
+{\r
+ int i, boardWidth, boardHeight; /* [HGM] height treated separately */\r
+ ChessSquare piece;\r
+ static int oldBoardSize = -1, oldTinyLayout = 0;\r
+ HDC hdc;\r
+ SIZE clockSize, messageSize;\r
+ HFONT oldFont;\r
+ char buf[MSG_SIZ];\r
+ char *str;\r
+ HMENU hmenu = GetMenu(hwndMain);\r
+ RECT crect, wrect, oldRect;\r
+ int offby;\r
+ LOGBRUSH logbrush;\r
+\r
+ int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only\r
+ if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }\r
+\r
+ /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */\r
+ if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;\r
+\r
+ oldRect.left = boardX; //[HGM] placement: remember previous window params\r
+ oldRect.top = boardY;\r
+ oldRect.right = boardX + winWidth;\r
+ oldRect.bottom = boardY + winHeight;\r
+\r
+ tinyLayout = sizeInfo[boardSize].tinyLayout;\r
+ smallLayout = sizeInfo[boardSize].smallLayout;\r
+ squareSize = sizeInfo[boardSize].squareSize;\r
+ lineGap = sizeInfo[boardSize].lineGap;\r
+ minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */\r
+\r
+ if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
+ lineGap = appData.overrideLineGap;\r
+ }\r
+\r
+ if (tinyLayout != oldTinyLayout) {\r
+ long style = GetWindowLong(hwndMain, GWL_STYLE);\r
+ if (tinyLayout) {\r
+ style &= ~WS_SYSMENU;\r
+ InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,\r
+ "&Minimize\tCtrl+F4");\r
+ } else {\r
+ style |= WS_SYSMENU;\r
+ RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);\r
+ }\r
+ SetWindowLong(hwndMain, GWL_STYLE, style);\r
+\r
+ for (i=0; menuBarText[tinyLayout][i]; i++) {\r
+ ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP, \r
+ (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);\r
+ }\r
+ DrawMenuBar(hwndMain);\r
+ }\r
+\r
+ boardWidth = BoardWidth(boardSize, BOARD_WIDTH);\r
+ boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);\r
+\r
+ /* Get text area sizes */\r
+ hdc = GetDC(hwndMain);\r
+ if (appData.clockMode) {\r
+ sprintf(buf, "White: %s", TimeString(23*60*60*1000L));\r
+ } else {\r
+ sprintf(buf, "White");\r
+ }\r
+ oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
+ GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);\r
+ SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
+ str = "We only care about the height here";\r
+ GetTextExtentPoint(hdc, str, strlen(str), &messageSize);\r
+ SelectObject(hdc, oldFont);\r
+ ReleaseDC(hwndMain, hdc);\r
+\r
+ /* Compute where everything goes */\r
+ if((first.programLogo || second.programLogo) && !tinyLayout) {\r
+ /* [HGM] logo: if either logo is on, reserve space for it */\r
+ logoHeight = 2*clockSize.cy;\r
+ leftLogoRect.left = OUTER_MARGIN;\r
+ leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;\r
+ leftLogoRect.top = OUTER_MARGIN;\r
+ leftLogoRect.bottom = OUTER_MARGIN + logoHeight;\r
+\r
+ rightLogoRect.right = OUTER_MARGIN + boardWidth;\r
+ rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;\r
+ rightLogoRect.top = OUTER_MARGIN;\r
+ rightLogoRect.bottom = OUTER_MARGIN + logoHeight;\r
+\r
+\r
+ whiteRect.left = leftLogoRect.right;\r
+ whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;\r
+ whiteRect.top = OUTER_MARGIN;\r
+ whiteRect.bottom = whiteRect.top + logoHeight;\r
+\r
+ blackRect.right = rightLogoRect.left;\r
+ blackRect.left = whiteRect.right + INNER_MARGIN;\r
+ blackRect.top = whiteRect.top;\r
+ blackRect.bottom = whiteRect.bottom;\r
+ } else {\r
+ whiteRect.left = OUTER_MARGIN;\r
+ whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;\r
+ whiteRect.top = OUTER_MARGIN;\r
+ whiteRect.bottom = whiteRect.top + clockSize.cy;\r
+\r
+ blackRect.left = whiteRect.right + INNER_MARGIN;\r
+ blackRect.right = blackRect.left + boardWidth/2 - 1;\r
+ blackRect.top = whiteRect.top;\r
+ blackRect.bottom = whiteRect.bottom;\r
+\r
+ logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!\r
+ }\r
+\r
+ messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;\r
+ if (appData.showButtonBar) {\r
+ messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement\r
+ - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;\r
+ } else {\r
+ messageRect.right = OUTER_MARGIN + boardWidth;\r
+ }\r
+ messageRect.top = whiteRect.bottom + INNER_MARGIN;\r
+ messageRect.bottom = messageRect.top + messageSize.cy;\r
+\r
+ boardRect.left = OUTER_MARGIN;\r
+ boardRect.right = boardRect.left + boardWidth;\r
+ boardRect.top = messageRect.bottom + INNER_MARGIN;\r
+ boardRect.bottom = boardRect.top + boardHeight;\r
+\r
+ sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;\r
+ sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;\r
+ oldBoardSize = boardSize;\r
+ oldTinyLayout = tinyLayout;\r
+ winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;\r
+ winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +\r
+ GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;\r
+ if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only\r
+ winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice\r
+ winHeight = winH; // without disturbing window attachments\r
+ GetWindowRect(hwndMain, &wrect);\r
+ SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,\r
+ SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
+\r
+ // [HGM] placement: let attached windows follow size change.\r
+ ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );\r
+ ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );\r
+ ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );\r
+ ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );\r
+ ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );\r
+\r
+ /* compensate if menu bar wrapped */\r
+ GetClientRect(hwndMain, &crect);\r
+ offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;\r
+ winHeight += offby;\r
+ switch (flags) {\r
+ case WMSZ_TOPLEFT:\r
+ SetWindowPos(hwndMain, NULL, \r
+ wrect.right - winWidth, wrect.bottom - winHeight, \r
+ winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
+ break;\r
+\r
+ case WMSZ_TOPRIGHT:\r
+ case WMSZ_TOP:\r
+ SetWindowPos(hwndMain, NULL, \r
+ wrect.left, wrect.bottom - winHeight, \r
+ winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
+ break;\r
+\r
+ case WMSZ_BOTTOMLEFT:\r
+ case WMSZ_LEFT:\r
+ SetWindowPos(hwndMain, NULL, \r
+ wrect.right - winWidth, wrect.top, \r
+ winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
+ break;\r
+\r
+ case WMSZ_BOTTOMRIGHT:\r
+ case WMSZ_BOTTOM:\r
+ case WMSZ_RIGHT:\r
+ default:\r
+ SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,\r
+ SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
+ break;\r
+ }\r
+\r
+ hwndPause = NULL;\r
+ for (i = 0; i < N_BUTTONS; i++) {\r
+ if (buttonDesc[i].hwnd != NULL) {\r
+ DestroyWindow(buttonDesc[i].hwnd);\r
+ buttonDesc[i].hwnd = NULL;\r
+ }\r
+ if (appData.showButtonBar) {\r
+ buttonDesc[i].hwnd =\r
+ CreateWindow("BUTTON", buttonDesc[i].label,\r
+ WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,\r
+ boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),\r
+ messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,\r
+ (HMENU) buttonDesc[i].id,\r
+ (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);\r
+ if (tinyLayout) {\r
+ SendMessage(buttonDesc[i].hwnd, WM_SETFONT, \r
+ (WPARAM)font[boardSize][MESSAGE_FONT]->hf,\r
+ MAKELPARAM(FALSE, 0));\r
+ }\r
+ if (buttonDesc[i].id == IDM_Pause)\r
+ hwndPause = buttonDesc[i].hwnd;\r
+ buttonDesc[i].wndproc = (WNDPROC)\r
+ SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);\r
+ }\r
+ }\r
+ if (gridPen != NULL) DeleteObject(gridPen);\r
+ if (highlightPen != NULL) DeleteObject(highlightPen);\r
+ if (premovePen != NULL) DeleteObject(premovePen);\r
+ if (lineGap != 0) {\r
+ logbrush.lbStyle = BS_SOLID;\r
+ logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */\r
+ gridPen =\r
+ ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
+ lineGap, &logbrush, 0, NULL);\r
+ logbrush.lbColor = highlightSquareColor;\r
+ highlightPen =\r
+ ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
+ lineGap, &logbrush, 0, NULL);\r
+\r
+ logbrush.lbColor = premoveHighlightColor; \r
+ premovePen =\r
+ ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
+ lineGap, &logbrush, 0, NULL);\r
+\r
+ /* [HGM] Loop had to be split in part for vert. and hor. lines */\r
+ for (i = 0; i < BOARD_HEIGHT + 1; i++) {\r
+ gridEndpoints[i*2].x = boardRect.left + lineGap / 2;\r
+ gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =\r
+ boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));\r
+ gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +\r
+ BOARD_WIDTH * (squareSize + lineGap);\r
+ gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
+ }\r
+ for (i = 0; i < BOARD_WIDTH + 1; i++) {\r
+ gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;\r
+ gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =\r
+ gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +\r
+ lineGap / 2 + (i * (squareSize + lineGap));\r
+ gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =\r
+ boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);\r
+ gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
+ }\r
+ }\r
+\r
+ /* [HGM] Licensing requirement */\r
+#ifdef GOTHIC\r
+ if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else\r
+#endif\r
+#ifdef FALCON\r
+ if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else\r
+#endif\r
+ GothicPopUp( "", VariantNormal);\r
+\r
+\r
+/* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */\r
+\r
+ /* Load piece bitmaps for this board size */\r
+ for (i=0; i<=2; i++) {\r
+ for (piece = WhitePawn;\r
+ (int) piece < (int) BlackPawn;\r
+ piece = (ChessSquare) ((int) piece + 1)) {\r
+ if (pieceBitmap[i][piece] != NULL)\r
+ DeleteObject(pieceBitmap[i][piece]);\r
+ }\r
+ }\r
+\r
+ fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */\r
+ // Orthodox Chess pieces\r
+ pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");\r
+ pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");\r
+ pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");\r
+ pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");\r
+ pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");\r
+ pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");\r
+ pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");\r
+ pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");\r
+ pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");\r
+ pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");\r
+ pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");\r
+ pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");\r
+ pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");\r
+ pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");\r
+ pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");\r
+ if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {\r
+ // in Shogi, Hijack the unused Queen for Lance\r
+ pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
+ pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
+ pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
+ } else {\r
+ pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");\r
+ pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");\r
+ pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");\r
+ }\r
+\r
+ if(squareSize <= 72 && squareSize >= 33) { \r
+ /* A & C are available in most sizes now */\r
+ if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like\r
+ pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");\r
+ pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");\r
+ pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");\r
+ pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
+ pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
+ pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
+ pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
+ pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
+ pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
+ pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
+ pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
+ pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
+ } else { // Smirf-like\r
+ pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");\r
+ pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");\r
+ pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");\r
+ }\r
+ if(gameInfo.variant == VariantGothic) { // Vortex-like\r
+ pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
+ pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
+ pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
+ } else { // WinBoard standard\r
+ pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");\r
+ pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");\r
+ pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");\r
+ }\r
+ }\r
+\r
+\r
+ if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */\r
+ pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");\r
+ pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");\r
+ pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");\r
+ pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");\r
+ pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");\r
+ pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+ pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");\r
+ pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");\r
+ pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");\r
+ pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");\r
+ pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");\r
+ pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");\r
+ pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");\r
+ pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");\r
+ pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");\r
+ pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");\r
+ pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");\r
+ pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");\r
+ pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");\r
+ pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");\r
+ pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");\r
+ pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");\r
+ pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");\r
+ pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");\r
+ pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
+ pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
+ pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
+ pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");\r
+ pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");\r
+ pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");\r
+\r
+ if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */\r
+ pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");\r
+ pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");\r
+ pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+ pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");\r
+ pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");\r
+ pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+ pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");\r
+ pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");\r
+ pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+ pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");\r
+ pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");\r
+ pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+ } else {\r
+ pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");\r
+ pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");\r
+ pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");\r
+ pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");\r
+ pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");\r
+ pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");\r
+ pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
+ pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
+ pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
+ pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");\r
+ pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");\r
+ pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");\r
+ }\r
+\r
+ } else { /* other size, no special bitmaps available. Use smaller symbols */\r
+ if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;\r
+ else minorSize = sizeInfo[(int)boardSize - 2].squareSize;\r
+ pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");\r
+ pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");\r
+ pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");\r
+ pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");\r
+ pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");\r
+ pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");\r
+ pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");\r
+ pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");\r
+ pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");\r
+ pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");\r
+ pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");\r
+ pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");\r
+ }\r
+\r
+\r
+ if(gameInfo.variant == VariantShogi && squareSize == 58)\r
+ /* special Shogi support in this size */\r
+ { for (i=0; i<=2; i++) { /* replace all bitmaps */\r
+ for (piece = WhitePawn;\r
+ (int) piece < (int) BlackPawn;\r
+ piece = (ChessSquare) ((int) piece + 1)) {\r
+ if (pieceBitmap[i][piece] != NULL)\r
+ DeleteObject(pieceBitmap[i][piece]);\r
+ }\r
+ }\r
+ pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");\r
+ pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");\r
+ pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");\r
+ pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");\r
+ pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");\r
+ pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");\r
+ pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");\r
+ pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");\r
+ pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");\r
+ pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");\r
+ pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");\r
+ pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");\r
+ pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");\r
+ pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");\r
+ pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");\r
+ pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");\r
+ pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");\r
+ pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");\r
+ pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");\r
+ pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");\r
+ pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");\r
+ pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");\r
+ pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");\r
+ pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");\r
+ pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");\r
+ pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");\r
+ pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");\r
+ pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");\r
+ pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");\r
+ pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");\r
+ pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
+ pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
+ pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");\r
+ pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");\r
+ pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
+ pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
+ pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");\r
+ pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");\r
+ pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
+ pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
+ pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");\r
+ pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
+ minorSize = 0;\r
+ }\r
+}\r
+\r
+HBITMAP\r
+PieceBitmap(ChessSquare p, int kind)\r
+{\r
+ if ((int) p >= (int) BlackPawn)\r
+ p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);\r
+\r
+ return pieceBitmap[kind][(int) p];\r
+}\r
+\r
+/***************************************************************/\r
+\r
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))\r
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))\r
+/*\r
+#define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))\r
+#define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))\r
+*/\r
+\r
+VOID\r
+SquareToPos(int row, int column, int * x, int * y)\r
+{\r
+ if (flipView) {\r
+ *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);\r
+ *y = boardRect.top + lineGap + row * (squareSize + lineGap);\r
+ } else {\r
+ *x = boardRect.left + lineGap + column * (squareSize + lineGap);\r
+ *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);\r
+ }\r
+}\r
+\r
+VOID\r
+DrawCoordsOnDC(HDC hdc)\r
+{\r
+ static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};\r
+ static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};\r
+ char str[2] = { NULLCHAR, NULLCHAR };\r
+ int oldMode, oldAlign, x, y, start, i;\r
+ HFONT oldFont;\r
+ HBRUSH oldBrush;\r
+\r
+ if (!appData.showCoords)\r
+ return;\r
+\r
+ start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;\r
+\r
+ oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));\r
+ oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));\r
+ oldAlign = GetTextAlign(hdc);\r
+ oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);\r
+\r
+ y = boardRect.top + lineGap;\r
+ x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);\r
+\r
+ SetTextAlign(hdc, TA_LEFT|TA_TOP);\r
+ for (i = 0; i < BOARD_HEIGHT; i++) {\r
+ str[0] = files[start + i];\r
+ ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);\r
+ y += squareSize + lineGap;\r
+ }\r
+\r
+ start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;\r
+\r
+ SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);\r
+ for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {\r
+ str[0] = ranks[start + i];\r
+ ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);\r
+ x += squareSize + lineGap;\r
+ } \r
+\r
+ SelectObject(hdc, oldBrush);\r
+ SetBkMode(hdc, oldMode);\r
+ SetTextAlign(hdc, oldAlign);\r
+ SelectObject(hdc, oldFont);\r
+}\r
+\r
+VOID\r
+DrawGridOnDC(HDC hdc)\r
+{\r
+ HPEN oldPen;\r
+ \r
+ if (lineGap != 0) {\r
+ oldPen = SelectObject(hdc, gridPen);\r
+ PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);\r
+ SelectObject(hdc, oldPen);\r
+ }\r
+}\r
+\r
+#define HIGHLIGHT_PEN 0\r
+#define PREMOVE_PEN 1\r
+\r
+VOID\r
+DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)\r
+{\r
+ int x1, y1;\r
+ HPEN oldPen, hPen;\r
+ if (lineGap == 0) return;\r
+ if (flipView) {\r
+ x1 = boardRect.left +\r
+ lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);\r
+ y1 = boardRect.top +\r
+ lineGap/2 + y * (squareSize + lineGap);\r
+ } else {\r
+ x1 = boardRect.left +\r
+ lineGap/2 + x * (squareSize + lineGap);\r
+ y1 = boardRect.top +\r
+ lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);\r
+ }\r
+ hPen = pen ? premovePen : highlightPen;\r
+ oldPen = SelectObject(hdc, on ? hPen : gridPen);\r
+ MoveToEx(hdc, x1, y1, NULL);\r
+ LineTo(hdc, x1 + squareSize + lineGap, y1);\r
+ LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);\r
+ LineTo(hdc, x1, y1 + squareSize + lineGap);\r
+ LineTo(hdc, x1, y1);\r
+ SelectObject(hdc, oldPen);\r
+}\r
+\r
+VOID\r
+DrawHighlightsOnDC(HDC hdc)\r
+{\r
+ int i;\r
+ for (i=0; i<2; i++) {\r
+ if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) \r
+ DrawHighlightOnDC(hdc, TRUE,\r
+ highlightInfo.sq[i].x, highlightInfo.sq[i].y,\r
+ HIGHLIGHT_PEN);\r
+ }\r
+ for (i=0; i<2; i++) {\r
+ if (premoveHighlightInfo.sq[i].x >= 0 && \r
+ premoveHighlightInfo.sq[i].y >= 0) {\r
+ DrawHighlightOnDC(hdc, TRUE,\r
+ premoveHighlightInfo.sq[i].x, \r
+ premoveHighlightInfo.sq[i].y,\r
+ PREMOVE_PEN);\r
+ }\r
+ }\r
+}\r
+\r
+/* Note: sqcolor is used only in monoMode */\r
+/* Note that this code is largely duplicated in woptions.c,\r
+ function DrawSampleSquare, so that needs to be updated too */\r
+VOID\r
+DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)\r
+{\r
+ HBITMAP oldBitmap;\r
+ HBRUSH oldBrush;\r
+ int tmpSize;\r
+\r
+ if (appData.blindfold) return;\r
+\r
+ /* [AS] Use font-based pieces if needed */\r
+ if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {\r
+ /* Create piece bitmaps, or do nothing if piece set is up to date */\r
+ CreatePiecesFromFont();\r
+\r
+ if( fontBitmapSquareSize == squareSize ) {\r
+ int index = TranslatePieceToFontPiece(piece);\r
+\r
+ SelectObject( tmphdc, hPieceMask[ index ] );\r
+\r
+ BitBlt( hdc,\r
+ x, y,\r
+ squareSize, squareSize,\r
+ tmphdc,\r
+ 0, 0,\r
+ SRCAND );\r
+\r
+ SelectObject( tmphdc, hPieceFace[ index ] );\r
+\r
+ BitBlt( hdc,\r
+ x, y,\r
+ squareSize, squareSize,\r
+ tmphdc,\r
+ 0, 0,\r
+ SRCPAINT );\r
+\r
+ return;\r
+ }\r
+ }\r
+\r
+ if (appData.monoMode) {\r
+ SelectObject(tmphdc, PieceBitmap(piece, \r
+ color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));\r
+ BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,\r
+ sqcolor ? SRCCOPY : NOTSRCCOPY);\r
+ } else {\r
+ tmpSize = squareSize;\r
+ if(minorSize &&\r
+ ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||\r
+ (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {\r
+ /* [HGM] no bitmap available for promoted pieces in Crazyhouse */\r
+ /* Bitmaps of smaller size are substituted, but we have to align them */\r
+ x += (squareSize - minorSize)>>1;\r
+ y += squareSize - minorSize - 2;\r
+ tmpSize = minorSize;\r
+ }\r
+ if (color || appData.allWhite ) {\r
+ oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));\r
+ if( color )\r
+ oldBrush = SelectObject(hdc, whitePieceBrush);\r
+ else oldBrush = SelectObject(hdc, blackPieceBrush);\r
+ if(appData.upsideDown && color==flipView)\r
+ StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);\r
+ else\r
+ BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
+ /* Use black for outline of white pieces */\r
+ SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));\r
+ if(appData.upsideDown && color==flipView)\r
+ StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);\r
+ else\r
+ BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);\r
+ } else {\r
+ /* Use square color for details of black pieces */\r
+ oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));\r
+ oldBrush = SelectObject(hdc, blackPieceBrush);\r
+ if(appData.upsideDown && !flipView)\r
+ StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);\r
+ else\r
+ BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
+ }\r
+ SelectObject(hdc, oldBrush);\r
+ SelectObject(tmphdc, oldBitmap);\r
+ }\r
+}\r
+\r
+/* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */\r
+int GetBackTextureMode( int algo )\r
+{\r
+ int result = BACK_TEXTURE_MODE_DISABLED;\r
+\r
+ switch( algo ) \r
+ {\r
+ case BACK_TEXTURE_MODE_PLAIN:\r
+ result = 1; /* Always use identity map */\r
+ break;\r
+ case BACK_TEXTURE_MODE_FULL_RANDOM:\r
+ result = 1 + (myrandom() % 3); /* Pick a transformation at random */\r
+ break;\r
+ }\r
+\r
+ return result;\r
+}\r
+\r
+/* \r
+ [AS] Compute and save texture drawing info, otherwise we may not be able\r
+ to handle redraws cleanly (as random numbers would always be different).\r
+*/\r
+VOID RebuildTextureSquareInfo()\r
+{\r
+ BITMAP bi;\r
+ int lite_w = 0;\r
+ int lite_h = 0;\r
+ int dark_w = 0;\r
+ int dark_h = 0;\r
+ int row;\r
+ int col;\r
+\r
+ ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );\r
+\r
+ if( liteBackTexture != NULL ) {\r
+ if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {\r
+ lite_w = bi.bmWidth;\r
+ lite_h = bi.bmHeight;\r
+ }\r
+ }\r
+\r
+ if( darkBackTexture != NULL ) {\r
+ if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {\r
+ dark_w = bi.bmWidth;\r
+ dark_h = bi.bmHeight;\r
+ }\r
+ }\r
+\r
+ for( row=0; row<BOARD_HEIGHT; row++ ) {\r
+ for( col=0; col<BOARD_WIDTH; col++ ) {\r
+ if( (col + row) & 1 ) {\r
+ /* Lite square */\r
+ if( lite_w >= squareSize && lite_h >= squareSize ) {\r
+ backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */\r
+ backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);\r
+ backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);\r
+ }\r
+ }\r
+ else {\r
+ /* Dark square */\r
+ if( dark_w >= squareSize && dark_h >= squareSize ) {\r
+ backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);\r
+ backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);\r
+ backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/* [AS] Arrow highlighting support */\r
+\r
+static int A_WIDTH = 5; /* Width of arrow body */\r
+\r
+#define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */\r
+#define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */\r
+\r
+static double Sqr( double x )\r
+{\r
+ return x*x;\r
+}\r
+\r
+static int Round( double x )\r
+{\r
+ return (int) (x + 0.5);\r
+}\r
+\r
+/* Draw an arrow between two points using current settings */\r
+VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )\r
+{\r
+ POINT arrow[7];\r
+ double dx, dy, j, k, x, y;\r
+\r
+ if( d_x == s_x ) {\r
+ int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;\r
+\r
+ arrow[0].x = s_x + A_WIDTH;\r
+ arrow[0].y = s_y;\r
+\r
+ arrow[1].x = s_x + A_WIDTH;\r
+ arrow[1].y = d_y - h;\r
+\r
+ arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;\r
+ arrow[2].y = d_y - h;\r
+\r
+ arrow[3].x = d_x;\r
+ arrow[3].y = d_y;\r
+\r
+ arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;\r
+ arrow[4].y = d_y - h;\r
+\r
+ arrow[5].x = s_x - A_WIDTH;\r
+ arrow[5].y = d_y - h;\r
+\r
+ arrow[6].x = s_x - A_WIDTH;\r
+ arrow[6].y = s_y;\r
+ }\r
+ else if( d_y == s_y ) {\r
+ int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;\r
+\r
+ arrow[0].x = s_x;\r
+ arrow[0].y = s_y + A_WIDTH;\r
+\r
+ arrow[1].x = d_x - w;\r
+ arrow[1].y = s_y + A_WIDTH;\r
+\r
+ arrow[2].x = d_x - w;\r
+ arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;\r
+\r
+ arrow[3].x = d_x;\r
+ arrow[3].y = d_y;\r
+\r
+ arrow[4].x = d_x - w;\r
+ arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;\r
+\r
+ arrow[5].x = d_x - w;\r
+ arrow[5].y = s_y - A_WIDTH;\r
+\r
+ arrow[6].x = s_x;\r
+ arrow[6].y = s_y - A_WIDTH;\r
+ }\r
+ else {\r
+ /* [AS] Needed a lot of paper for this! :-) */\r
+ dy = (double) (d_y - s_y) / (double) (d_x - s_x);\r
+ dx = (double) (s_x - d_x) / (double) (s_y - d_y);\r
+ \r
+ j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );\r
+\r
+ k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );\r
+\r
+ x = s_x;\r
+ y = s_y;\r
+\r
+ arrow[0].x = Round(x - j);\r
+ arrow[0].y = Round(y + j*dx);\r
+\r
+ arrow[1].x = Round(x + j);\r
+ arrow[1].y = Round(y - j*dx);\r
+\r
+ if( d_x > s_x ) {\r
+ x = (double) d_x - k;\r
+ y = (double) d_y - k*dy;\r
+ }\r
+ else {\r
+ x = (double) d_x + k;\r
+ y = (double) d_y + k*dy;\r
+ }\r
+\r
+ arrow[2].x = Round(x + j);\r
+ arrow[2].y = Round(y - j*dx);\r
+\r
+ arrow[3].x = Round(x + j*A_WIDTH_FACTOR);\r
+ arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);\r
+\r
+ arrow[4].x = d_x;\r
+ arrow[4].y = d_y;\r
+\r
+ arrow[5].x = Round(x - j*A_WIDTH_FACTOR);\r
+ arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);\r
+\r
+ arrow[6].x = Round(x - j);\r
+ arrow[6].y = Round(y + j*dx);\r
+ }\r
+\r
+ Polygon( hdc, arrow, 7 );\r
+}\r
+\r
+/* [AS] Draw an arrow between two squares */\r
+VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )\r
+{\r
+ int s_x, s_y, d_x, d_y;\r
+ HPEN hpen;\r
+ HPEN holdpen;\r
+ HBRUSH hbrush;\r
+ HBRUSH holdbrush;\r
+ LOGBRUSH stLB;\r
+\r
+ if( s_col == d_col && s_row == d_row ) {\r
+ return;\r
+ }\r
+\r
+ /* Get source and destination points */\r
+ SquareToPos( s_row, s_col, &s_x, &s_y);\r
+ SquareToPos( d_row, d_col, &d_x, &d_y);\r
+\r
+ if( d_y > s_y ) {\r
+ d_y += squareSize / 4;\r
+ }\r
+ else if( d_y < s_y ) {\r
+ d_y += 3 * squareSize / 4;\r
+ }\r
+ else {\r
+ d_y += squareSize / 2;\r
+ }\r
+\r
+ if( d_x > s_x ) {\r
+ d_x += squareSize / 4;\r
+ }\r
+ else if( d_x < s_x ) {\r
+ d_x += 3 * squareSize / 4;\r
+ }\r
+ else {\r
+ d_x += squareSize / 2;\r
+ }\r
+\r
+ s_x += squareSize / 2;\r
+ s_y += squareSize / 2;\r
+\r
+ /* Adjust width */\r
+ A_WIDTH = squareSize / 14;\r
+\r
+ /* Draw */\r
+ stLB.lbStyle = BS_SOLID;\r
+ stLB.lbColor = appData.highlightArrowColor;\r
+ stLB.lbHatch = 0;\r
+\r
+ hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );\r
+ holdpen = SelectObject( hdc, hpen );\r
+ hbrush = CreateBrushIndirect( &stLB );\r
+ holdbrush = SelectObject( hdc, hbrush );\r
+\r
+ DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );\r
+\r
+ SelectObject( hdc, holdpen );\r
+ SelectObject( hdc, holdbrush );\r
+ DeleteObject( hpen );\r
+ DeleteObject( hbrush );\r
+}\r
+\r
+BOOL HasHighlightInfo()\r
+{\r
+ BOOL result = FALSE;\r
+\r
+ if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&\r
+ highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )\r
+ {\r
+ result = TRUE;\r
+ }\r
+\r
+ return result;\r
+}\r
+\r
+BOOL IsDrawArrowEnabled()\r
+{\r
+ BOOL result = FALSE;\r
+\r
+ if( appData.highlightMoveWithArrow && squareSize >= 32 ) {\r
+ result = TRUE;\r
+ }\r
+\r
+ return result;\r
+}\r
+\r
+VOID DrawArrowHighlight( HDC hdc )\r
+{\r
+ if( IsDrawArrowEnabled() && HasHighlightInfo() ) {\r
+ DrawArrowBetweenSquares( hdc,\r
+ highlightInfo.sq[0].x, highlightInfo.sq[0].y,\r
+ highlightInfo.sq[1].x, highlightInfo.sq[1].y );\r
+ }\r
+}\r
+\r
+HRGN GetArrowHighlightClipRegion( HDC hdc )\r
+{\r
+ HRGN result = NULL;\r
+\r
+ if( HasHighlightInfo() ) {\r
+ int x1, y1, x2, y2;\r
+ int sx, sy, dx, dy;\r
+\r
+ SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );\r
+ SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );\r
+\r
+ sx = MIN( x1, x2 );\r
+ sy = MIN( y1, y2 );\r
+ dx = MAX( x1, x2 ) + squareSize;\r
+ dy = MAX( y1, y2 ) + squareSize;\r
+\r
+ result = CreateRectRgn( sx, sy, dx, dy );\r
+ }\r
+\r
+ return result;\r
+}\r
+\r
+/*\r
+ Warning: this function modifies the behavior of several other functions. \r
+ \r
+ Basically, Winboard is optimized to avoid drawing the whole board if not strictly\r
+ needed. Unfortunately, the decision whether or not to perform a full or partial\r
+ repaint is scattered all over the place, which is not good for features such as\r
+ "arrow highlighting" that require a full repaint of the board.\r
+\r
+ So, I've tried to patch the code where I thought it made sense (e.g. after or during\r
+ user interaction, when speed is not so important) but especially to avoid errors\r
+ in the displayed graphics.\r
+\r
+ In such patched places, I always try refer to this function so there is a single\r
+ place to maintain knowledge.\r
+ \r
+ To restore the original behavior, just return FALSE unconditionally.\r
+*/\r
+BOOL IsFullRepaintPreferrable()\r
+{\r
+ BOOL result = FALSE;\r
+\r
+ if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {\r
+ /* Arrow may appear on the board */\r
+ result = TRUE;\r
+ }\r
+\r
+ return result;\r
+}\r
+\r
+/* \r
+ This function is called by DrawPosition to know whether a full repaint must\r
+ be forced or not.\r
+\r
+ Only DrawPosition may directly call this function, which makes use of \r
+ some state information. Other function should call DrawPosition specifying \r
+ the repaint flag, and can use IsFullRepaintPreferrable if needed.\r
+*/\r
+BOOL DrawPositionNeedsFullRepaint()\r
+{\r
+ BOOL result = FALSE;\r
+\r
+ /* \r
+ Probably a slightly better policy would be to trigger a full repaint\r
+ when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),\r
+ but animation is fast enough that it's difficult to notice.\r
+ */\r
+ if( animInfo.piece == EmptySquare ) {\r
+ if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {\r
+ result = TRUE;\r
+ }\r
+ }\r
+\r
+ return result;\r
+}\r
+\r
+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;\r
+\r
+ /* [AS] Initialize background textures if needed */\r
+ if( liteBackTexture != NULL || darkBackTexture != NULL ) {\r
+ static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */\r
+ if( backTextureSquareSize != squareSize \r
+ || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {\r
+ backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;\r
+ backTextureSquareSize = squareSize;\r
+ RebuildTextureSquareInfo();\r
+ }\r
+\r
+ texture_hdc = CreateCompatibleDC( hdc );\r
+ }\r
+\r
+ for (row = 0; row < BOARD_HEIGHT; row++) {\r
+ for (column = 0; column < BOARD_WIDTH; column++) {\r
+ \r
+ SquareToPos(row, column, &x, &y);\r
+\r
+ piece = board[row][column];\r
+\r
+ square_color = ((column + row) % 2) == 1;\r
+ if( gameInfo.variant == VariantXiangqi ) {\r
+ square_color = !InPalace(row, column);\r
+ if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }\r
+ else if(row < BOARD_HEIGHT/2) square_color ^= 1;\r
+ }\r
+ piece_color = (int) piece < (int) BlackPawn;\r
+\r
+\r
+ /* [HGM] holdings file: light square or black */\r
+ if(column == BOARD_LEFT-2) {\r
+ if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )\r
+ square_color = 1;\r
+ else {\r
+ DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */\r
+ continue;\r
+ }\r
+ } else\r
+ if(column == BOARD_RGHT + 1 ) {\r
+ if( row < gameInfo.holdingsSize )\r
+ square_color = 1;\r
+ else {\r
+ DisplayHoldingsCount(hdc, x, y, 0, 0); \r
+ continue;\r
+ }\r
+ }\r
+ if(column == BOARD_LEFT-1 ) /* left align */\r
+ DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);\r
+ else if( column == BOARD_RGHT) /* right align */\r
+ DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);\r
+ else\r
+ if (appData.monoMode) {\r
+ if (piece == EmptySquare) {\r
+ BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,\r
+ square_color ? WHITENESS : BLACKNESS);\r
+ } else {\r
+ DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);\r
+ }\r
+ } \r
+ else if( backTextureSquareInfo[row][column].mode > 0 ) {\r
+ /* [AS] Draw the square using a texture bitmap */\r
+ HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );\r
+ int r = row, c = column; // [HGM] do not flip board in flipView\r
+ if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }\r
+\r
+ DrawTile( x, y, \r
+ squareSize, squareSize, \r
+ hdc, \r
+ texture_hdc,\r
+ backTextureSquareInfo[r][c].mode,\r
+ backTextureSquareInfo[r][c].x,\r
+ backTextureSquareInfo[r][c].y );\r
+\r
+ SelectObject( texture_hdc, hbm );\r
+\r
+ if (piece != EmptySquare) {\r
+ DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);\r
+ }\r
+ }\r
+ else {\r
+ HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;\r
+\r
+ oldBrush = SelectObject(hdc, brush );\r
+ BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);\r
+ SelectObject(hdc, oldBrush);\r
+ if (piece != EmptySquare)\r
+ DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);\r
+ }\r
+ }\r
+ }\r
+\r
+ if( texture_hdc != NULL ) {\r
+ DeleteDC( texture_hdc );\r
+ }\r
+}\r
+\r
+int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag\r
+void fputDW(FILE *f, int x)\r
+{\r
+ fputc(x & 255, f);\r
+ fputc(x>>8 & 255, f);\r
+ fputc(x>>16 & 255, f);\r
+ fputc(x>>24 & 255, f);\r
+}\r
+\r
+#define MAX_CLIPS 200 /* more than enough */\r
+\r
+VOID\r
+DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)\r
+{\r
+// HBITMAP bufferBitmap;\r
+ BITMAP bi;\r
+// RECT Rect;\r
+ HDC tmphdc;\r
+ HBITMAP hbm;\r
+ int w = 100, h = 50;\r
+\r
+ if(logo == NULL) return;\r
+// GetClientRect(hwndMain, &Rect);\r
+// bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,\r
+// Rect.bottom-Rect.top+1);\r
+ tmphdc = CreateCompatibleDC(hdc);\r
+ hbm = SelectObject(tmphdc, logo);\r
+ if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {\r
+ w = bi.bmWidth;\r
+ h = bi.bmHeight;\r
+ }\r
+ StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left, \r
+ logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);\r
+ SelectObject(tmphdc, hbm);\r
+ DeleteDC(tmphdc);\r
+}\r
+\r
+VOID\r
+HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)\r
+{\r
+ static Board lastReq, lastDrawn;\r
+ static HighlightInfo lastDrawnHighlight, lastDrawnPremove;\r
+ static int lastDrawnFlipView = 0;\r
+ static int lastReqValid = 0, lastDrawnValid = 0;\r
+ int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;\r
+ HDC tmphdc;\r
+ HDC hdcmem;\r
+ HBITMAP bufferBitmap;\r
+ HBITMAP oldBitmap;\r
+ RECT Rect;\r
+ HRGN clips[MAX_CLIPS];\r
+ ChessSquare dragged_piece = EmptySquare;\r
+\r
+ /* I'm undecided on this - this function figures out whether a full\r
+ * repaint is necessary on its own, so there's no real reason to have the\r
+ * caller tell it that. I think this can safely be set to FALSE - but\r
+ * if we trust the callers not to request full repaints unnessesarily, then\r
+ * we could skip some clipping work. In other words, only request a full\r
+ * redraw when the majority of pieces have changed positions (ie. flip, \r
+ * gamestart and similar) --Hawk\r
+ */\r
+ Boolean fullrepaint = repaint;\r
+\r
+ if( DrawPositionNeedsFullRepaint() ) {\r
+ fullrepaint = TRUE;\r
+ }\r
+\r
+ if (board == NULL) {\r
+ if (!lastReqValid) {\r
+ return;\r
+ }\r
+ board = lastReq;\r
+ } else {\r
+ CopyBoard(lastReq, board);\r
+ lastReqValid = 1;\r
+ }\r
+\r
+ if (doingSizing) {\r
+ return;\r
+ }\r
+\r
+ if (IsIconic(hwndMain)) {\r
+ return;\r
+ }\r
+\r
+ if (hdc == NULL) {\r
+ hdc = GetDC(hwndMain);\r
+ if (!appData.monoMode) {\r
+ SelectPalette(hdc, hPal, FALSE);\r
+ RealizePalette(hdc);\r
+ }\r
+ releaseDC = TRUE;\r
+ } else {\r
+ releaseDC = FALSE;\r
+ }\r
+\r
+ /* Create some work-DCs */\r
+ hdcmem = CreateCompatibleDC(hdc);\r
+ tmphdc = CreateCompatibleDC(hdc);\r
+\r
+ /* If dragging is in progress, we temporarely remove the piece */\r
+ /* [HGM] or temporarily decrease count if stacked */\r
+ /* !! Moved to before board compare !! */\r
+ if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {\r
+ dragged_piece = board[dragInfo.from.y][dragInfo.from.x];\r
+ if(dragInfo.from.x == BOARD_LEFT-2 ) {\r
+ if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )\r
+ board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
+ } else \r
+ if(dragInfo.from.x == BOARD_RGHT+1) {\r
+ if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )\r
+ board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
+ } else \r
+ board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
+ }\r
+\r
+ /* Figure out which squares need updating by comparing the \r
+ * newest board with the last drawn board and checking if\r
+ * flipping has changed.\r
+ */\r
+ if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {\r
+ for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */\r
+ for (column = 0; column < BOARD_WIDTH; column++) {\r
+ if (lastDrawn[row][column] != board[row][column]) {\r
+ SquareToPos(row, column, &x, &y);\r
+ clips[num_clips++] =\r
+ CreateRectRgn(x, y, x + squareSize, y + squareSize);\r
+ }\r
+ }\r
+ }\r
+ for (i=0; i<2; i++) {\r
+ if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||\r
+ lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {\r
+ if (lastDrawnHighlight.sq[i].x >= 0 &&\r
+ lastDrawnHighlight.sq[i].y >= 0) {\r
+ SquareToPos(lastDrawnHighlight.sq[i].y,\r
+ lastDrawnHighlight.sq[i].x, &x, &y);\r
+ clips[num_clips++] =\r
+ CreateRectRgn(x - lineGap, y - lineGap, \r
+ x + squareSize + lineGap, y + squareSize + lineGap);\r
+ }\r
+ if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {\r
+ SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);\r
+ clips[num_clips++] =\r
+ CreateRectRgn(x - lineGap, y - lineGap, \r
+ x + squareSize + lineGap, y + squareSize + lineGap);\r
+ }\r
+ }\r
+ }\r
+ for (i=0; i<2; i++) {\r
+ if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||\r
+ lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {\r
+ if (lastDrawnPremove.sq[i].x >= 0 &&\r
+ lastDrawnPremove.sq[i].y >= 0) {\r
+ SquareToPos(lastDrawnPremove.sq[i].y,\r
+ lastDrawnPremove.sq[i].x, &x, &y);\r
+ clips[num_clips++] =\r
+ CreateRectRgn(x - lineGap, y - lineGap, \r
+ x + squareSize + lineGap, y + squareSize + lineGap);\r
+ }\r
+ if (premoveHighlightInfo.sq[i].x >= 0 && \r
+ premoveHighlightInfo.sq[i].y >= 0) {\r
+ SquareToPos(premoveHighlightInfo.sq[i].y, \r
+ premoveHighlightInfo.sq[i].x, &x, &y);\r
+ clips[num_clips++] =\r
+ CreateRectRgn(x - lineGap, y - lineGap, \r
+ x + squareSize + lineGap, y + squareSize + lineGap);\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ fullrepaint = TRUE;\r
+ }\r
+\r
+ /* Create a buffer bitmap - this is the actual bitmap\r
+ * being written to. When all the work is done, we can\r
+ * copy it to the real DC (the screen). This avoids\r
+ * the problems with flickering.\r
+ */\r
+ GetClientRect(hwndMain, &Rect);\r
+ bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,\r
+ Rect.bottom-Rect.top+1);\r
+ oldBitmap = SelectObject(hdcmem, bufferBitmap);\r
+ if (!appData.monoMode) {\r
+ SelectPalette(hdcmem, hPal, FALSE);\r
+ }\r
+\r
+ /* Create clips for dragging */\r
+ if (!fullrepaint) {\r
+ if (dragInfo.from.x >= 0) {\r
+ SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);\r
+ clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);\r
+ }\r
+ if (dragInfo.start.x >= 0) {\r
+ SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);\r
+ clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);\r
+ }\r
+ if (dragInfo.pos.x >= 0) {\r
+ x = dragInfo.pos.x - squareSize / 2;\r
+ y = dragInfo.pos.y - squareSize / 2;\r
+ clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);\r
+ }\r
+ if (dragInfo.lastpos.x >= 0) {\r
+ x = dragInfo.lastpos.x - squareSize / 2;\r
+ y = dragInfo.lastpos.y - squareSize / 2;\r
+ clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);\r
+ }\r
+ }\r
+\r
+ /* Are we animating a move? \r
+ * If so, \r
+ * - remove the piece from the board (temporarely)\r
+ * - calculate the clipping region\r
+ */\r
+ if (!fullrepaint) {\r
+ if (animInfo.piece != EmptySquare) {\r
+ board[animInfo.from.y][animInfo.from.x] = EmptySquare;\r
+ x = boardRect.left + animInfo.lastpos.x;\r
+ y = boardRect.top + animInfo.lastpos.y;\r
+ x2 = boardRect.left + animInfo.pos.x;\r
+ y2 = boardRect.top + animInfo.pos.y;\r
+ clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);\r
+ /* Slight kludge. The real problem is that after AnimateMove is\r
+ done, the position on the screen does not match lastDrawn.\r
+ This currently causes trouble only on e.p. captures in\r
+ atomic, where the piece moves to an empty square and then\r
+ explodes. The old and new positions both had an empty square\r
+ at the destination, but animation has drawn a piece there and\r
+ we have to remember to erase it. [HGM] moved until after setting lastDrawn */\r
+ lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;\r
+ }\r
+ }\r
+\r
+ /* No clips? Make sure we have fullrepaint set to TRUE */\r
+ if (num_clips == 0)\r
+ fullrepaint = TRUE;\r
+\r
+ /* Set clipping on the memory DC */\r
+ if (!fullrepaint) {\r
+ SelectClipRgn(hdcmem, clips[0]);\r
+ for (x = 1; x < num_clips; x++) {\r
+ if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)\r
+ abort(); // this should never ever happen!\r
+ }\r
+ }\r
+\r
+ /* Do all the drawing to the memory DC */\r
+ if(explodeInfo.radius) { // [HGM] atomic\r
+ HBRUSH oldBrush;\r
+ int x, y, r=(explodeInfo.radius * squareSize)/100;\r
+ board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer\r
+ SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);\r
+ x += squareSize/2;\r
+ y += squareSize/2;\r
+ if(!fullrepaint) {\r
+ clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);\r
+ ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);\r
+ }\r
+ DrawGridOnDC(hdcmem);\r
+ DrawHighlightsOnDC(hdcmem);\r
+ DrawBoardOnDC(hdcmem, board, tmphdc);\r
+ oldBrush = SelectObject(hdcmem, explodeBrush);\r
+ Ellipse(hdcmem, x-r, y-r, x+r, y+r);\r
+ SelectObject(hdcmem, oldBrush);\r
+ } else {\r
+ DrawGridOnDC(hdcmem);\r
+ DrawHighlightsOnDC(hdcmem);\r
+ DrawBoardOnDC(hdcmem, board, tmphdc);\r
+ }\r
+ if(logoHeight) {\r
+ HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;\r
+ if(appData.autoLogo) {\r
+ \r
+ switch(gameMode) { // pick logos based on game mode\r
+ case IcsObserving:\r
+ whiteLogo = second.programLogo; // ICS logo\r
+ blackLogo = second.programLogo;\r
+ default:\r
+ break;\r
+ case IcsPlayingWhite:\r
+ if(!appData.zippyPlay) whiteLogo = userLogo;\r
+ blackLogo = second.programLogo; // ICS logo\r
+ break;\r
+ case IcsPlayingBlack:\r
+ whiteLogo = second.programLogo; // ICS logo\r
+ blackLogo = appData.zippyPlay ? first.programLogo : userLogo;\r
+ break;\r
+ case TwoMachinesPlay:\r
+ if(first.twoMachinesColor[0] == 'b') {\r
+ whiteLogo = second.programLogo;\r
+ blackLogo = first.programLogo;\r
+ }\r
+ break;\r
+ case MachinePlaysWhite:\r
+ blackLogo = userLogo;\r
+ break;\r
+ case MachinePlaysBlack:\r
+ whiteLogo = userLogo;\r
+ blackLogo = first.programLogo;\r
+ }\r
+ }\r
+ DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);\r
+ DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);\r
+ }\r
+\r
+ if( appData.highlightMoveWithArrow ) {\r
+ DrawArrowHighlight(hdcmem);\r
+ }\r
+\r
+ DrawCoordsOnDC(hdcmem);\r
+\r
+ CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */\r
+ /* to make sure lastDrawn contains what is actually drawn */\r
+\r
+ /* Put the dragged piece back into place and draw it (out of place!) */\r
+ if (dragged_piece != EmptySquare) {\r
+ /* [HGM] or restack */\r
+ if(dragInfo.from.x == BOARD_LEFT-2 )\r
+ board[dragInfo.from.y][dragInfo.from.x+1]++;\r
+ else\r
+ if(dragInfo.from.x == BOARD_RGHT+1 )\r
+ board[dragInfo.from.y][dragInfo.from.x-1]++;\r
+ board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;\r
+ x = dragInfo.pos.x - squareSize / 2;\r
+ y = dragInfo.pos.y - squareSize / 2;\r
+ DrawPieceOnDC(hdcmem, dragged_piece,\r
+ ((int) dragged_piece < (int) BlackPawn), \r
+ (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);\r
+ } \r
+ \r
+ /* Put the animated piece back into place and draw it */\r
+ if (animInfo.piece != EmptySquare) {\r
+ board[animInfo.from.y][animInfo.from.x] = animInfo.piece;\r
+ x = boardRect.left + animInfo.pos.x;\r
+ y = boardRect.top + animInfo.pos.y;\r
+ DrawPieceOnDC(hdcmem, animInfo.piece,\r
+ ((int) animInfo.piece < (int) BlackPawn),\r
+ (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);\r
+ }\r
+\r
+ /* Release the bufferBitmap by selecting in the old bitmap \r
+ * and delete the memory DC\r
+ */\r
+ SelectObject(hdcmem, oldBitmap);\r
+ DeleteDC(hdcmem);\r
+\r
+ /* Set clipping on the target DC */\r
+ if (!fullrepaint) {\r
+ SelectClipRgn(hdc, clips[0]);\r
+ for (x = 1; x < num_clips; x++) {\r
+ if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)\r
+ abort(); // this should never ever happen!\r
+ } \r
+ }\r
+\r
+ /* Copy the new bitmap onto the screen in one go.\r
+ * This way we avoid any flickering\r
+ */\r
+ oldBitmap = SelectObject(tmphdc, bufferBitmap);\r
+ BitBlt(hdc, boardRect.left, boardRect.top,\r
+ boardRect.right - boardRect.left,\r
+ boardRect.bottom - boardRect.top,\r
+ tmphdc, boardRect.left, boardRect.top, SRCCOPY);\r
+ if(saveDiagFlag) { \r
+ BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000]; \r
+ BITMAPINFOHEADER bih; int color[16], nrColors=0;\r
+\r
+ GetObject(bufferBitmap, sizeof(b), &b);\r
+ if(b.bmWidthBytes*b.bmHeight <= 990000) {\r
+ bih.biSize = sizeof(BITMAPINFOHEADER);\r
+ bih.biWidth = b.bmWidth;\r
+ bih.biHeight = b.bmHeight;\r
+ bih.biPlanes = 1;\r
+ bih.biBitCount = b.bmBitsPixel;\r
+ bih.biCompression = 0;\r
+ bih.biSizeImage = b.bmWidthBytes*b.bmHeight;\r
+ bih.biXPelsPerMeter = 0;\r
+ bih.biYPelsPerMeter = 0;\r
+ bih.biClrUsed = 0;\r
+ bih.biClrImportant = 0;\r
+// fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n", \r
+// b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);\r
+ GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);\r
+// fprintf(diagFile, "%8x\n", (int) pData);\r
+\r
+ wb = b.bmWidthBytes;\r
+ // count colors\r
+ for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {\r
+ int k = ((int*) pData)[i];\r
+ for(j=0; j<nrColors; j++) if(color[j] == k) break;\r
+ if(j >= 16) break;\r
+ color[j] = k;\r
+ if(j >= nrColors) nrColors = j+1;\r
+ }\r
+ if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel\r
+ INT p = 0;\r
+ for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {\r
+ for(w=0; w<(wb>>2); w+=2) {\r
+ int k = ((int*) pData)[(wb*i>>2) + w];\r
+ for(j=0; j<nrColors; j++) if(color[j] == k) break;\r
+ k = ((int*) pData)[(wb*i>>2) + w + 1];\r
+ for(m=0; m<nrColors; m++) if(color[m] == k) break;\r
+ pData[p++] = m | j<<4;\r
+ }\r
+ while(p&3) pData[p++] = 0;\r
+ }\r
+ fac = 3;\r
+ wb = ((wb+31)>>5)<<2;\r
+ }\r
+ // write BITMAPFILEHEADER\r
+ fprintf(diagFile, "BM");\r
+ fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));\r
+ fputDW(diagFile, 0);\r
+ fputDW(diagFile, 0x36 + (fac?64:0));\r
+ // write BITMAPINFOHEADER\r
+ fputDW(diagFile, 40);\r
+ fputDW(diagFile, b.bmWidth);\r
+ fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);\r
+ if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel\r
+ else fputDW(diagFile, 0x200001); // planes and bits/pixel\r
+ fputDW(diagFile, 0);\r
+ fputDW(diagFile, 0);\r
+ fputDW(diagFile, 0);\r
+ fputDW(diagFile, 0);\r
+ fputDW(diagFile, 0);\r
+ fputDW(diagFile, 0);\r
+ // write color table\r
+ if(fac)\r
+ for(i=0; i<16; i++) fputDW(diagFile, color[i]);\r
+ // write bitmap data\r
+ for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++) \r
+ fputc(pData[i], diagFile);\r
+ }\r
+ }\r
+\r
+ SelectObject(tmphdc, oldBitmap);\r
+\r
+ /* Massive cleanup */\r
+ for (x = 0; x < num_clips; x++)\r
+ DeleteObject(clips[x]);\r
+\r
+ DeleteDC(tmphdc);\r
+ DeleteObject(bufferBitmap);\r
+\r
+ if (releaseDC) \r
+ ReleaseDC(hwndMain, hdc);\r
+ \r
+ if (lastDrawnFlipView != flipView) {\r
+ if (flipView)\r
+ CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);\r
+ else\r
+ CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);\r
+ }\r
+\r
+/* CopyBoard(lastDrawn, board);*/\r
+ lastDrawnHighlight = highlightInfo;\r
+ lastDrawnPremove = premoveHighlightInfo;\r
+ lastDrawnFlipView = flipView;\r
+ lastDrawnValid = 1;\r
+}\r
+\r
+/* [HGM] diag: Save the current board display to the given open file and close the file */\r
+int\r
+SaveDiagram(f)\r
+ FILE *f;\r
+{\r
+ saveDiagFlag = 1; diagFile = f;\r
+ HDCDrawPosition(NULL, TRUE, NULL);\r
+\r
+ saveDiagFlag = 0;\r
+\r
+// if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");\r
+ \r
+ fclose(f);\r
+ return TRUE;\r
+}\r
+\r
+\r
+/*---------------------------------------------------------------------------*\\r
+| CLIENT PAINT PROCEDURE\r
+| This is the main event-handler for the WM_PAINT message.\r
+|\r
+\*---------------------------------------------------------------------------*/\r
+VOID\r
+PaintProc(HWND hwnd)\r
+{\r
+ HDC hdc;\r
+ PAINTSTRUCT ps;\r
+ HFONT oldFont;\r
+\r
+ if((hdc = BeginPaint(hwnd, &ps))) {\r
+ if (IsIconic(hwnd)) {\r
+ DrawIcon(hdc, 2, 2, iconCurrent);\r
+ } else {\r
+ if (!appData.monoMode) {\r
+ SelectPalette(hdc, hPal, FALSE);\r
+ RealizePalette(hdc);\r
+ }\r
+ HDCDrawPosition(hdc, 1, NULL);\r
+ oldFont =\r
+ SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
+ ExtTextOut(hdc, messageRect.left, messageRect.top,\r
+ ETO_CLIPPED|ETO_OPAQUE,\r
+ &messageRect, messageText, strlen(messageText), NULL);\r
+ SelectObject(hdc, oldFont);\r
+ DisplayBothClocks();\r
+ }\r
+ EndPaint(hwnd,&ps);\r
+ }\r
+\r
+ return;\r
+}\r
+\r
+\r
+/*\r
+ * If the user selects on a border boundary, return -1; if off the board,\r
+ * return -2. Otherwise map the event coordinate to the square.\r
+ * The offset boardRect.left or boardRect.top must already have been\r
+ * subtracted from x.\r
+ */\r
+int EventToSquare(x, limit)\r
+ int x, limit;\r
+{\r
+ if (x <= 0)\r
+ return -2;\r
+ if (x < lineGap)\r
+ return -1;\r
+ x -= lineGap;\r
+ if ((x % (squareSize + lineGap)) >= squareSize)\r
+ return -1;\r
+ x /= (squareSize + lineGap);\r
+ if (x >= limit)\r
+ return -2;\r
+ return x;\r
+}\r
+\r
+typedef struct {\r
+ char piece;\r
+ int command;\r
+ char* name;\r
+} DropEnable;\r
+\r
+DropEnable dropEnables[] = {\r
+ { 'P', DP_Pawn, "Pawn" },\r
+ { 'N', DP_Knight, "Knight" },\r
+ { 'B', DP_Bishop, "Bishop" },\r
+ { 'R', DP_Rook, "Rook" },\r
+ { 'Q', DP_Queen, "Queen" },\r
+};\r
+\r
+VOID\r
+SetupDropMenu(HMENU hmenu)\r
+{\r
+ int i, count, enable;\r
+ char *p;\r
+ extern char white_holding[], black_holding[];\r
+ char item[MSG_SIZ];\r
+\r
+ for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {\r
+ p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,\r
+ dropEnables[i].piece);\r
+ count = 0;\r
+ while (p && *p++ == dropEnables[i].piece) count++;\r
+ sprintf(item, "%s %d", dropEnables[i].name, count);\r
+ enable = count > 0 || !appData.testLegality\r
+ /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse\r
+ && !appData.icsActive);\r
+ ModifyMenu(hmenu, dropEnables[i].command,\r
+ MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,\r
+ dropEnables[i].command, item);\r
+ }\r
+}\r
+\r
+void DragPieceBegin(int x, int y)\r
+{\r
+ dragInfo.lastpos.x = boardRect.left + x;\r
+ dragInfo.lastpos.y = boardRect.top + y;\r
+ dragInfo.from.x = fromX;\r
+ dragInfo.from.y = fromY;\r
+ dragInfo.start = dragInfo.from;\r
+ SetCapture(hwndMain);\r
+}\r
+\r
+void DragPieceEnd(int x, int y)\r
+{\r
+ ReleaseCapture();\r
+ dragInfo.start.x = dragInfo.start.y = -1;\r
+ dragInfo.from = dragInfo.start;\r
+ dragInfo.pos = dragInfo.lastpos = dragInfo.start;\r
+}\r
+\r
+/* Event handler for mouse messages */\r
+VOID\r
+MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ int x, y;\r
+ POINT pt;\r
+ static int recursive = 0;\r
+ HMENU hmenu;\r
+ BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */\r
+\r
+ if (recursive) {\r
+ if (message == WM_MBUTTONUP) {\r
+ /* Hideous kludge to fool TrackPopupMenu into paying attention\r
+ to the middle button: we simulate pressing the left button too!\r
+ */\r
+ PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);\r
+ PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);\r
+ }\r
+ return;\r
+ }\r
+ recursive++;\r
+ \r
+ pt.x = LOWORD(lParam);\r
+ pt.y = HIWORD(lParam);\r
+ x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);\r
+ y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);\r
+ if (!flipView && y >= 0) {\r
+ y = BOARD_HEIGHT - 1 - y;\r
+ }\r
+ if (flipView && x >= 0) {\r
+ x = BOARD_WIDTH - 1 - x;\r
+ }\r
+\r
+ switch (message) {\r
+ case WM_LBUTTONDOWN:\r
+ if (PtInRect((LPRECT) &whiteRect, pt)) {\r
+ if (gameMode == EditPosition) {\r
+ SetWhiteToPlayEvent();\r
+ } else if (gameMode == IcsPlayingBlack ||\r
+ gameMode == MachinePlaysWhite) {\r
+ CallFlagEvent();\r
+ } else if (gameMode == EditGame) {\r
+ AdjustClock(flipClock, -1);\r
+ }\r
+ } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
+ if (gameMode == EditPosition) {\r
+ SetBlackToPlayEvent();\r
+ } else if (gameMode == IcsPlayingWhite ||\r
+ gameMode == MachinePlaysBlack) {\r
+ CallFlagEvent();\r
+ } else if (gameMode == EditGame) {\r
+ AdjustClock(!flipClock, -1);\r
+ }\r
+ }\r
+ dragInfo.start.x = dragInfo.start.y = -1;\r
+ dragInfo.from = dragInfo.start;\r
+ if(fromX == -1 && frozen) { // not sure where this is for\r
+ fromX = fromY = -1; \r
+ DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */\r
+ break;\r
+ }\r
+ LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);\r
+ DrawPosition(TRUE, NULL);\r
+ break;\r
+\r
+ case WM_LBUTTONUP:\r
+ LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);\r
+ DrawPosition(TRUE, NULL);\r
+ break;\r
+\r
+ case WM_MOUSEMOVE:\r
+ if ((appData.animateDragging || appData.highlightDragging)\r
+ && (wParam & MK_LBUTTON)\r
+ && dragInfo.from.x >= 0) \r
+ {\r
+ BOOL full_repaint = FALSE;\r
+\r
+ if (appData.animateDragging) {\r
+ dragInfo.pos = pt;\r
+ }\r
+ if (appData.highlightDragging) {\r
+ SetHighlights(fromX, fromY, x, y);\r
+ if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {\r
+ full_repaint = TRUE;\r
+ }\r
+ }\r
+ \r
+ DrawPosition( full_repaint, NULL);\r
+ \r
+ dragInfo.lastpos = dragInfo.pos;\r
+ }\r
+ break;\r
+\r
+ case WM_MOUSEWHEEL: // [DM]\r
+ { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events\r
+ /* Mouse Wheel is being rolled forward\r
+ * Play moves forward\r
+ */\r
+ if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove) \r
+ { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction\r
+ /* Mouse Wheel is being rolled backward\r
+ * Play moves backward\r
+ */\r
+ if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove) \r
+ { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }\r
+ }\r
+ break;\r
+\r
+ case WM_MBUTTONDOWN:\r
+ case WM_RBUTTONDOWN:\r
+ ErrorPopDown();\r
+ ReleaseCapture();\r
+ fromX = fromY = -1;\r
+ dragInfo.pos.x = dragInfo.pos.y = -1;\r
+ dragInfo.start.x = dragInfo.start.y = -1;\r
+ dragInfo.from = dragInfo.start;\r
+ dragInfo.lastpos = dragInfo.pos;\r
+ if (appData.highlightDragging) {\r
+ ClearHighlights();\r
+ }\r
+ if(y == -2) {\r
+ /* [HGM] right mouse button in clock area edit-game mode ups clock */\r
+ if (PtInRect((LPRECT) &whiteRect, pt)) {\r
+ if (gameMode == EditGame) AdjustClock(flipClock, 1);\r
+ } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
+ if (gameMode == EditGame) AdjustClock(!flipClock, 1);\r
+ }\r
+ }\r
+ DrawPosition(TRUE, NULL);\r
+\r
+ switch (gameMode) {\r
+ case EditPosition:\r
+ case IcsExamining:\r
+ if (x < 0 || y < 0) break;\r
+ fromX = x;\r
+ fromY = y;\r
+ if (message == WM_MBUTTONDOWN) {\r
+ buttonCount = 3; /* even if system didn't think so */\r
+ if (wParam & MK_SHIFT) \r
+ MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);\r
+ else\r
+ MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);\r
+ } else { /* message == WM_RBUTTONDOWN */\r
+ /* Just have one menu, on the right button. Windows users don't\r
+ think to try the middle one, and sometimes other software steals\r
+ it, or it doesn't really exist. */\r
+ if(gameInfo.variant != VariantShogi)\r
+ MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\r
+ else\r
+ MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);\r
+ }\r
+ break;\r
+ case IcsPlayingWhite:\r
+ case IcsPlayingBlack:\r
+ case EditGame:\r
+ case MachinePlaysWhite:\r
+ case MachinePlaysBlack:\r
+ if (appData.testLegality &&\r
+ gameInfo.variant != VariantBughouse &&\r
+ gameInfo.variant != VariantCrazyhouse) break;\r
+ if (x < 0 || y < 0) break;\r
+ fromX = x;\r
+ fromY = y;\r
+ hmenu = LoadMenu(hInst, "DropPieceMenu");\r
+ SetupDropMenu(hmenu);\r
+ MenuPopup(hwnd, pt, hmenu, -1);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ recursive--;\r
+}\r
+\r
+/* Preprocess messages for buttons in main window */\r
+LRESULT CALLBACK\r
+ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ int id = GetWindowLong(hwnd, GWL_ID);\r
+ int i, dir;\r
+\r
+ for (i=0; i<N_BUTTONS; i++) {\r
+ if (buttonDesc[i].id == id) break;\r
+ }\r
+ if (i == N_BUTTONS) return 0;\r
+ switch (message) {\r
+ case WM_KEYDOWN:\r
+ switch (wParam) {\r
+ case VK_LEFT:\r
+ case VK_RIGHT:\r
+ dir = (wParam == VK_LEFT) ? -1 : 1;\r
+ SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);\r
+ return TRUE;\r
+ }\r
+ break;\r
+ case WM_CHAR:\r
+ switch (wParam) {\r
+ case '\r':\r
+ SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);\r
+ return TRUE;\r
+ default:\r
+ if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {\r
+ // [HGM] movenum: only letters or leading zero should go to ICS input\r
+ HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+ if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
+ SetFocus(h);\r
+ SendMessage(h, WM_CHAR, wParam, lParam);\r
+ return TRUE;\r
+ } else if (isalpha((char)wParam) || isdigit((char)wParam)){\r
+ PopUpMoveDialog((char)wParam);\r
+ }\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);\r
+}\r
+\r
+/* Process messages for Promotion dialog box */\r
+LRESULT CALLBACK\r
+Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ char promoChar;\r
+\r
+ switch (message) {\r
+ case WM_INITDIALOG: /* message: initialize dialog box */\r
+ /* Center the dialog over the application window */\r
+ CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+ ShowWindow(GetDlgItem(hDlg, PB_King), \r
+ (!appData.testLegality || gameInfo.variant == VariantSuicide ||\r
+ gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?\r
+ SW_SHOW : SW_HIDE);\r
+ /* [HGM] Only allow C & A promotions if these pieces are defined */\r
+ ShowWindow(GetDlgItem(hDlg, PB_Archbishop),\r
+ ((PieceToChar(WhiteAngel) >= 'A' &&\r
+ PieceToChar(WhiteAngel) != '~') ||\r
+ (PieceToChar(BlackAngel) >= 'A' &&\r
+ PieceToChar(BlackAngel) != '~') ) ?\r
+ SW_SHOW : SW_HIDE);\r
+ ShowWindow(GetDlgItem(hDlg, PB_Chancellor), \r
+ ((PieceToChar(WhiteMarshall) >= 'A' &&\r
+ PieceToChar(WhiteMarshall) != '~') ||\r
+ (PieceToChar(BlackMarshall) >= 'A' &&\r
+ PieceToChar(BlackMarshall) != '~') ) ?\r
+ SW_SHOW : SW_HIDE);\r
+ /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */\r
+ ShowWindow(GetDlgItem(hDlg, PB_Rook),\r
+ gameInfo.variant != VariantShogi ?\r
+ SW_SHOW : SW_HIDE);\r
+ ShowWindow(GetDlgItem(hDlg, PB_Bishop), \r
+ gameInfo.variant != VariantShogi ?\r
+ SW_SHOW : SW_HIDE);\r
+ ShowWindow(GetDlgItem(hDlg, IDC_Yes), \r
+ gameInfo.variant == VariantShogi ?\r
+ SW_SHOW : SW_HIDE);\r
+ ShowWindow(GetDlgItem(hDlg, IDC_No), \r
+ gameInfo.variant == VariantShogi ?\r
+ SW_SHOW : SW_HIDE);\r
+ ShowWindow(GetDlgItem(hDlg, IDC_Centaur), \r
+ gameInfo.variant == VariantSuper ?\r
+ SW_SHOW : SW_HIDE);\r
+ return TRUE;\r
+\r
+ case WM_COMMAND: /* message: received a command */\r
+ switch (LOWORD(wParam)) {\r
+ case IDCANCEL:\r
+ EndDialog(hDlg, TRUE); /* Exit the dialog */\r
+ ClearHighlights();\r
+ DrawPosition(FALSE, NULL);\r
+ return TRUE;\r
+ case PB_King:\r
+ promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);\r
+ break;\r
+ case PB_Queen:\r
+ promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);\r
+ break;\r
+ case PB_Rook:\r
+ promoChar = PieceToChar(BlackRook);\r
+ break;\r
+ case PB_Bishop:\r
+ promoChar = PieceToChar(BlackBishop);\r
+ break;\r
+ case PB_Chancellor:\r
+ promoChar = PieceToChar(BlackMarshall);\r
+ break;\r
+ case PB_Archbishop:\r
+ promoChar = PieceToChar(BlackAngel);\r
+ break;\r
+ case PB_Knight:\r
+ promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);\r
+ break;\r
+ default:\r
+ return FALSE;\r
+ }\r
+ EndDialog(hDlg, TRUE); /* Exit the dialog */\r
+ /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we\r
+ only show the popup when we are already sure the move is valid or\r
+ legal. We pass a faulty move type, but the kludge is that FinishMove\r
+ will figure out it is a promotion from the promoChar. */\r
+ UserMoveEvent(fromX, fromY, toX, toY, promoChar);\r
+ fromX = fromY = -1;\r
+ if (!appData.highlightLastMove) {\r
+ ClearHighlights();\r
+ DrawPosition(FALSE, NULL);\r
+ }\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+/* Pop up promotion dialog */\r
+VOID\r
+PromotionPopup(HWND hwnd)\r
+{\r
+ FARPROC lpProc;\r
+\r
+ lpProc = MakeProcInstance((FARPROC)Promotion, hInst);\r
+ DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),\r
+ hwnd, (DLGPROC)lpProc);\r
+ FreeProcInstance(lpProc);\r
+}\r
+\r
+void\r
+PromotionPopUp()\r
+{\r
+ DrawPosition(TRUE, NULL);\r
+ PromotionPopup(hwndMain);\r
+}\r
+\r
+/* Toggle ShowThinking */\r
+VOID\r
+ToggleShowThinking()\r
+{\r
+ appData.showThinking = !appData.showThinking;\r
+ ShowThinkingEvent();\r
+}\r
+\r
+VOID\r
+LoadGameDialog(HWND hwnd, char* title)\r
+{\r
+ UINT number = 0;\r
+ FILE *f;\r
+ char fileTitle[MSG_SIZ];\r
+ f = OpenFileDialog(hwnd, "rb", "",\r
+ appData.oldSaveStyle ? "gam" : "pgn",\r
+ GAME_FILT,\r
+ title, &number, fileTitle, NULL);\r
+ if (f != NULL) {\r
+ cmailMsgLoaded = FALSE;\r
+ if (number == 0) {\r
+ int error = GameListBuild(f);\r
+ if (error) {\r
+ DisplayError("Cannot build game list", error);\r
+ } else if (!ListEmpty(&gameList) &&\r
+ ((ListGame *) gameList.tailPred)->number > 1) {\r
+ GameListPopUp(f, fileTitle);\r
+ return;\r
+ }\r
+ GameListDestroy();\r
+ number = 1;\r
+ }\r
+ LoadGame(f, number, fileTitle, FALSE);\r
+ }\r
+}\r
+\r
+int get_term_width()\r
+{\r
+ HDC hdc;\r
+ TEXTMETRIC tm;\r
+ RECT rc;\r
+ HFONT hfont, hold_font;\r
+ LOGFONT lf;\r
+ HWND hText;\r
+\r
+ if (hwndConsole)\r
+ hText = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
+ else\r
+ return 79;\r
+\r
+ // get the text metrics\r
+ hdc = GetDC(hText);\r
+ lf = font[boardSize][CONSOLE_FONT]->lf;\r
+ if (consoleCF.dwEffects & CFE_BOLD)\r
+ lf.lfWeight = FW_BOLD;\r
+ if (consoleCF.dwEffects & CFE_ITALIC)\r
+ lf.lfItalic = TRUE;\r
+ if (consoleCF.dwEffects & CFE_STRIKEOUT)\r
+ lf.lfStrikeOut = TRUE;\r
+ if (consoleCF.dwEffects & CFE_UNDERLINE)\r
+ lf.lfUnderline = TRUE;\r
+ hfont = CreateFontIndirect(&lf);\r
+ hold_font = SelectObject(hdc, hfont);\r
+ GetTextMetrics(hdc, &tm);\r
+ SelectObject(hdc, hold_font);\r
+ DeleteObject(hfont);\r
+ ReleaseDC(hText, hdc);\r
+\r
+ // get the rectangle\r
+ SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);\r
+\r
+ return (rc.right-rc.left) / tm.tmAveCharWidth;\r
+}\r
+\r
+void UpdateICSWidth(HWND hText)\r
+{\r
+ LONG old_width, new_width;\r
+\r
+ new_width = get_term_width(hText, FALSE);\r
+ old_width = GetWindowLong(hText, GWL_USERDATA);\r
+ if (new_width != old_width)\r
+ {\r
+ ics_update_width(new_width);\r
+ SetWindowLong(hText, GWL_USERDATA, new_width);\r
+ }\r
+}\r
+\r
+VOID\r
+ChangedConsoleFont()\r
+{\r
+ CHARFORMAT cfmt;\r
+ CHARRANGE tmpsel, sel;\r
+ MyFont *f = font[boardSize][CONSOLE_FONT];\r
+ HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
+ HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+ PARAFORMAT paraf;\r
+\r
+ cfmt.cbSize = sizeof(CHARFORMAT);\r
+ cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;\r
+ strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);\r
+ /* yHeight is expressed in twips. A twip is 1/20 of a font's point\r
+ * size. This was undocumented in the version of MSVC++ that I had\r
+ * when I wrote the code, but is apparently documented now.\r
+ */\r
+ cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);\r
+ cfmt.bCharSet = f->lf.lfCharSet;\r
+ cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;\r
+ SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt); \r
+ SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt); \r
+ /* Why are the following seemingly needed too? */\r
+ SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt); \r
+ SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt); \r
+ SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);\r
+ tmpsel.cpMin = 0;\r
+ tmpsel.cpMax = -1; /*999999?*/\r
+ SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);\r
+ SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt); \r
+ /* Trying putting this here too. It still seems to tickle a RichEdit\r
+ * bug: sometimes RichEdit indents the first line of a paragraph too.\r
+ */\r
+ paraf.cbSize = sizeof(paraf);\r
+ paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;\r
+ paraf.dxStartIndent = 0;\r
+ paraf.dxOffset = WRAP_INDENT;\r
+ SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);\r
+ SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ UpdateICSWidth(hText);\r
+}\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * Window Proc for main window\r
+ *\r
+\*---------------------------------------------------------------------------*/\r
+\r
+/* Process messages for main window, etc. */\r
+LRESULT CALLBACK\r
+WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ FARPROC lpProc;\r
+ int wmId, wmEvent;\r
+ char *defName;\r
+ FILE *f;\r
+ UINT number;\r
+ char fileTitle[MSG_SIZ];\r
+ char buf[MSG_SIZ];\r
+ static SnapData sd;\r
+\r
+ switch (message) {\r
+\r
+ case WM_PAINT: /* message: repaint portion of window */\r
+ PaintProc(hwnd);\r
+ break;\r
+\r
+ case WM_ERASEBKGND:\r
+ if (IsIconic(hwnd)) {\r
+ /* Cheat; change the message */\r
+ return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));\r
+ } else {\r
+ return (DefWindowProc(hwnd, message, wParam, lParam));\r
+ }\r
+ break;\r
+\r
+ case WM_LBUTTONDOWN:\r
+ case WM_MBUTTONDOWN:\r
+ case WM_RBUTTONDOWN:\r
+ case WM_LBUTTONUP:\r
+ case WM_MBUTTONUP:\r
+ case WM_RBUTTONUP:\r
+ case WM_MOUSEMOVE:\r
+ case WM_MOUSEWHEEL:\r
+ MouseEvent(hwnd, message, wParam, lParam);\r
+ break;\r
+\r
+ JAWS_KB_NAVIGATION\r
+\r
+ case WM_CHAR:\r
+ \r
+ JAWS_ALT_INTERCEPT\r
+\r
+ if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) { \r
+ // [HGM] movenum: for non-zero digits we always do type-in dialog\r
+ HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+ if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
+ SetFocus(h);\r
+ SendMessage(h, message, wParam, lParam);\r
+ } else if(lParam != KF_REPEAT) {\r
+ if (isalpha((char)wParam) || isdigit((char)wParam)) {\r
+ PopUpMoveDialog((char)wParam);\r
+ } else if((char)wParam == 003) CopyGameToClipboard();\r
+ else if((char)wParam == 026) PasteGameOrFENFromClipboard();\r
+ }\r
+\r
+ break;\r
+\r
+ case WM_PALETTECHANGED:\r
+ if (hwnd != (HWND)wParam && !appData.monoMode) {\r
+ int nnew;\r
+ HDC hdc = GetDC(hwndMain);\r
+ SelectPalette(hdc, hPal, TRUE);\r
+ nnew = RealizePalette(hdc);\r
+ if (nnew > 0) {\r
+ paletteChanged = TRUE;\r
+ InvalidateRect(hwnd, &boardRect, FALSE);\r
+ }\r
+ ReleaseDC(hwnd, hdc);\r
+ }\r
+ break;\r
+\r
+ case WM_QUERYNEWPALETTE:\r
+ if (!appData.monoMode /*&& paletteChanged*/) {\r
+ int nnew;\r
+ HDC hdc = GetDC(hwndMain);\r
+ paletteChanged = FALSE;\r
+ SelectPalette(hdc, hPal, FALSE);\r
+ nnew = RealizePalette(hdc);\r
+ if (nnew > 0) {\r
+ InvalidateRect(hwnd, &boardRect, FALSE);\r
+ }\r
+ ReleaseDC(hwnd, hdc);\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+\r
+ case WM_COMMAND: /* message: command from application menu */\r
+ wmId = LOWORD(wParam);\r
+ wmEvent = HIWORD(wParam);\r
+\r
+ switch (wmId) {\r
+ case IDM_NewGame:\r
+ ResetGameEvent();\r
+ SAY("new game enter a move to play against the computer with white");\r
+ break;\r
+\r
+ case IDM_NewGameFRC:\r
+ if( NewGameFRC() == 0 ) {\r
+ ResetGameEvent();\r
+ }\r
+ break;\r
+\r
+ case IDM_NewVariant:\r
+ NewVariantPopup(hwnd);\r
+ break;\r
+\r
+ case IDM_LoadGame:\r
+ LoadGameDialog(hwnd, "Load Game from File");\r
+ break;\r
+\r
+ case IDM_LoadNextGame:\r
+ ReloadGame(1);\r
+ break;\r
+\r
+ case IDM_LoadPrevGame:\r
+ ReloadGame(-1);\r
+ break;\r
+\r
+ case IDM_ReloadGame:\r
+ ReloadGame(0);\r
+ break;\r
+\r
+ case IDM_LoadPosition:\r
+ if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {\r
+ Reset(FALSE, TRUE);\r
+ }\r
+ number = 1;\r
+ f = OpenFileDialog(hwnd, "rb", "",\r
+ appData.oldSaveStyle ? "pos" : "fen",\r
+ POSITION_FILT,\r
+ "Load Position from File", &number, fileTitle, NULL);\r
+ if (f != NULL) {\r
+ LoadPosition(f, number, fileTitle);\r
+ }\r
+ break;\r
+\r
+ case IDM_LoadNextPosition:\r
+ ReloadPosition(1);\r
+ break;\r
+\r
+ case IDM_LoadPrevPosition:\r
+ ReloadPosition(-1);\r
+ break;\r
+\r
+ case IDM_ReloadPosition:\r
+ ReloadPosition(0);\r
+ break;\r
+\r
+ case IDM_SaveGame:\r
+ defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");\r
+ f = OpenFileDialog(hwnd, "a", defName,\r
+ appData.oldSaveStyle ? "gam" : "pgn",\r
+ GAME_FILT,\r
+ "Save Game to File", NULL, fileTitle, NULL);\r
+ if (f != NULL) {\r
+ SaveGame(f, 0, "");\r
+ }\r
+ break;\r
+\r
+ case IDM_SavePosition:\r
+ defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");\r
+ f = OpenFileDialog(hwnd, "a", defName,\r
+ appData.oldSaveStyle ? "pos" : "fen",\r
+ POSITION_FILT,\r
+ "Save Position to File", NULL, fileTitle, NULL);\r
+ if (f != NULL) {\r
+ SavePosition(f, 0, "");\r
+ }\r
+ break;\r
+\r
+ case IDM_SaveDiagram:\r
+ defName = "diagram";\r
+ f = OpenFileDialog(hwnd, "wb", defName,\r
+ "bmp",\r
+ DIAGRAM_FILT,\r
+ "Save Diagram to File", NULL, fileTitle, NULL);\r
+ if (f != NULL) {\r
+ SaveDiagram(f);\r
+ }\r
+ break;\r
+\r
+ case IDM_CopyGame:\r
+ CopyGameToClipboard();\r
+ break;\r
+\r
+ case IDM_PasteGame:\r
+ PasteGameFromClipboard();\r
+ break;\r
+\r
+ case IDM_CopyGameListToClipboard:\r
+ CopyGameListToClipboard();\r
+ break;\r
+\r
+ /* [AS] Autodetect FEN or PGN data */\r
+ case IDM_PasteAny:\r
+ PasteGameOrFENFromClipboard();\r
+ break;\r
+\r
+ /* [AS] Move history */\r
+ case IDM_ShowMoveHistory:\r
+ if( MoveHistoryIsUp() ) {\r
+ MoveHistoryPopDown();\r
+ }\r
+ else {\r
+ MoveHistoryPopUp();\r
+ }\r
+ break;\r
+\r
+ /* [AS] Eval graph */\r
+ case IDM_ShowEvalGraph:\r
+ if( EvalGraphIsUp() ) {\r
+ EvalGraphPopDown();\r
+ }\r
+ else {\r
+ EvalGraphPopUp();\r
+ SetFocus(hwndMain);\r
+ }\r
+ break;\r
+\r
+ /* [AS] Engine output */\r
+ case IDM_ShowEngineOutput:\r
+ if( EngineOutputIsUp() ) {\r
+ EngineOutputPopDown();\r
+ }\r
+ else {\r
+ EngineOutputPopUp();\r
+ }\r
+ break;\r
+\r
+ /* [AS] User adjudication */\r
+ case IDM_UserAdjudication_White:\r
+ UserAdjudicationEvent( +1 );\r
+ break;\r
+\r
+ case IDM_UserAdjudication_Black:\r
+ UserAdjudicationEvent( -1 );\r
+ break;\r
+\r
+ case IDM_UserAdjudication_Draw:\r
+ UserAdjudicationEvent( 0 );\r
+ break;\r
+\r
+ /* [AS] Game list options dialog */\r
+ case IDM_GameListOptions:\r
+ GameListOptions();\r
+ break;\r
+\r
+ case IDM_NewChat:\r
+ ChatPopUp();\r
+ break;\r
+\r
+ case IDM_CopyPosition:\r
+ CopyFENToClipboard();\r
+ break;\r
+\r
+ case IDM_PastePosition:\r
+ PasteFENFromClipboard();\r
+ break;\r
+\r
+ case IDM_MailMove:\r
+ MailMoveEvent();\r
+ break;\r
+\r
+ case IDM_ReloadCMailMsg:\r
+ Reset(TRUE, TRUE);\r
+ ReloadCmailMsgEvent(FALSE);\r
+ break;\r
+\r
+ case IDM_Minimize:\r
+ ShowWindow(hwnd, SW_MINIMIZE);\r
+ break;\r
+\r
+ case IDM_Exit:\r
+ ExitEvent(0);\r
+ break;\r
+\r
+ case IDM_MachineWhite:\r
+ MachineWhiteEvent();\r
+ /*\r
+ * refresh the tags dialog only if it's visible\r
+ */\r
+ if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {\r
+ char *tags;\r
+ tags = PGNTags(&gameInfo);\r
+ TagsPopUp(tags, CmailMsg());\r
+ free(tags);\r
+ }\r
+ SAY("computer starts playing white");\r
+ break;\r
+\r
+ case IDM_MachineBlack:\r
+ MachineBlackEvent();\r
+ /*\r
+ * refresh the tags dialog only if it's visible\r
+ */\r
+ if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {\r
+ char *tags;\r
+ tags = PGNTags(&gameInfo);\r
+ TagsPopUp(tags, CmailMsg());\r
+ free(tags);\r
+ }\r
+ SAY("computer starts playing black");\r
+ break;\r
+\r
+ case IDM_TwoMachines:\r
+ TwoMachinesEvent();\r
+ /*\r
+ * refresh the tags dialog only if it's visible\r
+ */\r
+ if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {\r
+ char *tags;\r
+ tags = PGNTags(&gameInfo);\r
+ TagsPopUp(tags, CmailMsg());\r
+ free(tags);\r
+ }\r
+ SAY("programs start playing each other");\r
+ break;\r
+\r
+ case IDM_AnalysisMode:\r
+ if (!first.analysisSupport) {\r
+ sprintf(buf, "%s does not support analysis", first.tidy);\r
+ DisplayError(buf, 0);\r
+ } else {\r
+ SAY("analyzing current position");\r
+ /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */\r
+ if (appData.icsActive) {\r
+ if (gameMode != IcsObserving) {\r
+ sprintf(buf, "You are not observing a game");\r
+ DisplayError(buf, 0);\r
+ /* secure check */\r
+ if (appData.icsEngineAnalyze) {\r
+ if (appData.debugMode) \r
+ fprintf(debugFP, "Found unexpected active ICS engine analyze \n");\r
+ ExitAnalyzeMode();\r
+ ModeHighlight();\r
+ break;\r
+ }\r
+ break;\r
+ } else {\r
+ /* if enable, user want disable icsEngineAnalyze */\r
+ if (appData.icsEngineAnalyze) {\r
+ ExitAnalyzeMode();\r
+ ModeHighlight();\r
+ break;\r
+ }\r
+ appData.icsEngineAnalyze = TRUE;\r
+ if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");\r
+ }\r
+ } \r
+ if (!appData.showThinking) ToggleShowThinking();\r
+ AnalyzeModeEvent();\r
+ }\r
+ break;\r
+\r
+ case IDM_AnalyzeFile:\r
+ if (!first.analysisSupport) {\r
+ char buf[MSG_SIZ];\r
+ sprintf(buf, "%s does not support analysis", first.tidy);\r
+ DisplayError(buf, 0);\r
+ } else {\r
+ if (!appData.showThinking) ToggleShowThinking();\r
+ AnalyzeFileEvent();\r
+ LoadGameDialog(hwnd, "Analyze Game from File");\r
+ AnalysisPeriodicEvent(1);\r
+ }\r
+ break;\r
+\r
+ case IDM_IcsClient:\r
+ IcsClientEvent();\r
+ break;\r
+\r
+ case IDM_EditGame:\r
+ EditGameEvent();\r
+ SAY("edit game");\r
+ break;\r
+\r
+ case IDM_EditPosition:\r
+ EditPositionEvent();\r
+ SAY("to set up a position type a FEN");\r
+ break;\r
+\r
+ case IDM_Training:\r
+ TrainingEvent();\r
+ break;\r
+\r
+ case IDM_ShowGameList:\r
+ ShowGameListProc();\r
+ break;\r
+\r
+ case IDM_EditTags:\r
+ EditTagsProc();\r
+ break;\r
+\r
+ case IDM_EditComment:\r
+ if (commentUp && editComment) {\r
+ CommentPopDown();\r
+ } else {\r
+ EditCommentEvent();\r
+ }\r
+ break;\r
+\r
+ case IDM_Pause:\r
+ PauseEvent();\r
+ break;\r
+\r
+ case IDM_Accept:\r
+ AcceptEvent();\r
+ break;\r
+\r
+ case IDM_Decline:\r
+ DeclineEvent();\r
+ break;\r
+\r
+ case IDM_Rematch:\r
+ RematchEvent();\r
+ break;\r
+\r
+ case IDM_CallFlag:\r
+ CallFlagEvent();\r
+ break;\r
+\r
+ case IDM_Draw:\r
+ DrawEvent();\r
+ break;\r
+\r
+ case IDM_Adjourn:\r
+ AdjournEvent();\r
+ break;\r
+\r
+ case IDM_Abort:\r
+ AbortEvent();\r
+ break;\r
+\r
+ case IDM_Resign:\r
+ ResignEvent();\r
+ break;\r
+\r
+ case IDM_StopObserving:\r
+ StopObservingEvent();\r
+ break;\r
+\r
+ case IDM_StopExamining:\r
+ StopExaminingEvent();\r
+ break;\r
+\r
+ case IDM_TypeInMove:\r
+ PopUpMoveDialog('\000');\r
+ break;\r
+\r
+ case IDM_TypeInName:\r
+ PopUpNameDialog('\000');\r
+ break;\r
+\r
+ case IDM_Backward:\r
+ BackwardEvent();\r
+ SetFocus(hwndMain);\r
+ break;\r
+\r
+ JAWS_MENU_ITEMS\r
+\r
+ case IDM_Forward:\r
+ ForwardEvent();\r
+ SetFocus(hwndMain);\r
+ break;\r
+\r
+ case IDM_ToStart:\r
+ ToStartEvent();\r
+ SetFocus(hwndMain);\r
+ break;\r
+\r
+ case IDM_ToEnd:\r
+ ToEndEvent();\r
+ SetFocus(hwndMain);\r
+ break;\r
+\r
+ case IDM_Revert:\r
+ RevertEvent();\r
+ break;\r
+\r
+ case IDM_TruncateGame:\r
+ TruncateGameEvent();\r
+ break;\r
+\r
+ case IDM_MoveNow:\r
+ MoveNowEvent();\r
+ break;\r
+\r
+ case IDM_RetractMove:\r
+ RetractMoveEvent();\r
+ break;\r
+\r
+ case IDM_FlipView:\r
+ flipView = !flipView;\r
+ DrawPosition(FALSE, NULL);\r
+ break;\r
+\r
+ case IDM_FlipClock:\r
+ flipClock = !flipClock;\r
+ DisplayBothClocks();\r
+ DrawPosition(FALSE, NULL);\r
+ break;\r
+\r
+ case IDM_MuteSounds:\r
+ mute = !mute; // [HGM] mute: keep track of global muting variable\r
+ CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds, \r
+ MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));\r
+ break;\r
+\r
+ case IDM_GeneralOptions:\r
+ GeneralOptionsPopup(hwnd);\r
+ DrawPosition(TRUE, NULL);\r
+ break;\r
+\r
+ case IDM_BoardOptions:\r
+ BoardOptionsPopup(hwnd);\r
+ break;\r
+\r
+ case IDM_EnginePlayOptions:\r
+ EnginePlayOptionsPopup(hwnd);\r
+ break;\r
+\r
+ case IDM_Engine1Options:\r
+ EngineOptionsPopup(hwnd, &first);\r
+ break;\r
+\r
+ case IDM_Engine2Options:\r
+ EngineOptionsPopup(hwnd, &second);\r
+ break;\r
+\r
+ case IDM_OptionsUCI:\r
+ UciOptionsPopup(hwnd);\r
+ break;\r
+\r
+ case IDM_IcsOptions:\r
+ IcsOptionsPopup(hwnd);\r
+ break;\r
+\r
+ case IDM_Fonts:\r
+ FontsOptionsPopup(hwnd);\r
+ break;\r
+\r
+ case IDM_Sounds:\r
+ SoundOptionsPopup(hwnd);\r
+ break;\r
+\r
+ case IDM_CommPort:\r
+ CommPortOptionsPopup(hwnd);\r
+ break;\r
+\r
+ case IDM_LoadOptions:\r
+ LoadOptionsPopup(hwnd);\r
+ break;\r
+\r
+ case IDM_SaveOptions:\r
+ SaveOptionsPopup(hwnd);\r
+ break;\r
+\r
+ case IDM_TimeControl:\r
+ TimeControlOptionsPopup(hwnd);\r
+ break;\r
+\r
+ case IDM_SaveSettings:\r
+ SaveSettings(settingsFileName);\r
+ break;\r
+\r
+ case IDM_SaveSettingsOnExit:\r
+ saveSettingsOnExit = !saveSettingsOnExit;\r
+ (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,\r
+ MF_BYCOMMAND|(saveSettingsOnExit ?\r
+ MF_CHECKED : MF_UNCHECKED));\r
+ break;\r
+\r
+ case IDM_Hint:\r
+ HintEvent();\r
+ break;\r
+\r
+ case IDM_Book:\r
+ BookEvent();\r
+ break;\r
+\r
+ case IDM_AboutGame:\r
+ AboutGameEvent();\r
+ break;\r
+\r
+ case IDM_Debug:\r
+ appData.debugMode = !appData.debugMode;\r
+ if (appData.debugMode) {\r
+ char dir[MSG_SIZ];\r
+ GetCurrentDirectory(MSG_SIZ, dir);\r
+ SetCurrentDirectory(installDir);\r
+ debugFP = fopen(appData.nameOfDebugFile, "w");\r
+ SetCurrentDirectory(dir);\r
+ setbuf(debugFP, NULL);\r
+ } else {\r
+ fclose(debugFP);\r
+ debugFP = NULL;\r
+ }\r
+ break;\r
+\r
+ case IDM_HELPCONTENTS:\r
+ if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&\r
+ !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {\r
+ MessageBox (GetFocus(),\r
+ "Unable to activate help",\r
+ szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
+ }\r
+ break;\r
+\r
+ case IDM_HELPSEARCH:\r
+ if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&\r
+ !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {\r
+ MessageBox (GetFocus(),\r
+ "Unable to activate help",\r
+ szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
+ }\r
+ break;\r
+\r
+ case IDM_HELPHELP:\r
+ if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {\r
+ MessageBox (GetFocus(),\r
+ "Unable to activate help",\r
+ szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
+ }\r
+ break;\r
+\r
+ case IDM_ABOUT:\r
+ lpProc = MakeProcInstance((FARPROC)About, hInst);\r
+ DialogBox(hInst, \r
+ (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?\r
+ "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);\r
+ FreeProcInstance(lpProc);\r
+ break;\r
+\r
+ case IDM_DirectCommand1:\r
+ AskQuestionEvent("Direct Command",\r
+ "Send to chess program:", "", "1");\r
+ break;\r
+ case IDM_DirectCommand2:\r
+ AskQuestionEvent("Direct Command",\r
+ "Send to second chess program:", "", "2");\r
+ break;\r
+\r
+ case EP_WhitePawn:\r
+ EditPositionMenuEvent(WhitePawn, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_WhiteKnight:\r
+ EditPositionMenuEvent(WhiteKnight, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_WhiteBishop:\r
+ EditPositionMenuEvent(WhiteBishop, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_WhiteRook:\r
+ EditPositionMenuEvent(WhiteRook, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_WhiteQueen:\r
+ EditPositionMenuEvent(WhiteQueen, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_WhiteFerz:\r
+ EditPositionMenuEvent(WhiteFerz, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_WhiteWazir:\r
+ EditPositionMenuEvent(WhiteWazir, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_WhiteAlfil:\r
+ EditPositionMenuEvent(WhiteAlfil, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_WhiteCannon:\r
+ EditPositionMenuEvent(WhiteCannon, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_WhiteCardinal:\r
+ EditPositionMenuEvent(WhiteAngel, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_WhiteMarshall:\r
+ EditPositionMenuEvent(WhiteMarshall, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_WhiteKing:\r
+ EditPositionMenuEvent(WhiteKing, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_BlackPawn:\r
+ EditPositionMenuEvent(BlackPawn, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_BlackKnight:\r
+ EditPositionMenuEvent(BlackKnight, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_BlackBishop:\r
+ EditPositionMenuEvent(BlackBishop, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_BlackRook:\r
+ EditPositionMenuEvent(BlackRook, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_BlackQueen:\r
+ EditPositionMenuEvent(BlackQueen, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_BlackFerz:\r
+ EditPositionMenuEvent(BlackFerz, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_BlackWazir:\r
+ EditPositionMenuEvent(BlackWazir, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_BlackAlfil:\r
+ EditPositionMenuEvent(BlackAlfil, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_BlackCannon:\r
+ EditPositionMenuEvent(BlackCannon, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_BlackCardinal:\r
+ EditPositionMenuEvent(BlackAngel, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_BlackMarshall:\r
+ EditPositionMenuEvent(BlackMarshall, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_BlackKing:\r
+ EditPositionMenuEvent(BlackKing, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_EmptySquare:\r
+ EditPositionMenuEvent(EmptySquare, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_ClearBoard:\r
+ EditPositionMenuEvent(ClearBoard, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_White:\r
+ EditPositionMenuEvent(WhitePlay, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_Black:\r
+ EditPositionMenuEvent(BlackPlay, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_Promote:\r
+ EditPositionMenuEvent(PromotePiece, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case EP_Demote:\r
+ EditPositionMenuEvent(DemotePiece, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case DP_Pawn:\r
+ DropMenuEvent(WhitePawn, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case DP_Knight:\r
+ DropMenuEvent(WhiteKnight, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case DP_Bishop:\r
+ DropMenuEvent(WhiteBishop, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case DP_Rook:\r
+ DropMenuEvent(WhiteRook, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ case DP_Queen:\r
+ DropMenuEvent(WhiteQueen, fromX, fromY);\r
+ fromX = fromY = -1;\r
+ break;\r
+\r
+ default:\r
+ return (DefWindowProc(hwnd, message, wParam, lParam));\r
+ }\r
+ break;\r
+\r
+ case WM_TIMER:\r
+ switch (wParam) {\r
+ case CLOCK_TIMER_ID:\r
+ KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */\r
+ clockTimerEvent = 0;\r
+ DecrementClocks(); /* call into back end */\r
+ break;\r
+ case LOAD_GAME_TIMER_ID:\r
+ KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/\r
+ loadGameTimerEvent = 0;\r
+ AutoPlayGameLoop(); /* call into back end */\r
+ break;\r
+ case ANALYSIS_TIMER_ID:\r
+ if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile\r
+ || appData.icsEngineAnalyze) && appData.periodicUpdates) {\r
+ AnalysisPeriodicEvent(0);\r
+ } else {\r
+ KillTimer(hwnd, analysisTimerEvent);\r
+ analysisTimerEvent = 0;\r
+ }\r
+ break;\r
+ case DELAYED_TIMER_ID:\r
+ KillTimer(hwnd, delayedTimerEvent);\r
+ delayedTimerEvent = 0;\r
+ delayedTimerCallback();\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case WM_USER_Input:\r
+ InputEvent(hwnd, message, wParam, lParam);\r
+ break;\r
+\r
+ /* [AS] Also move "attached" child windows */\r
+ case WM_WINDOWPOSCHANGING:\r
+\r
+ if( hwnd == hwndMain && appData.useStickyWindows ) {\r
+ LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;\r
+\r
+ if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {\r
+ /* Window is moving */\r
+ RECT rcMain;\r
+\r
+// GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old\r
+ rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect\r
+ rcMain.right = boardX + winWidth;\r
+ rcMain.top = boardY;\r
+ rcMain.bottom = boardY + winHeight;\r
+ \r
+ ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );\r
+ ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );\r
+ ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );\r
+ ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );\r
+ ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );\r
+ boardX = lpwp->x;\r
+ boardY = lpwp->y;\r
+ }\r
+ }\r
+ break;\r
+\r
+ /* [AS] Snapping */\r
+ case WM_ENTERSIZEMOVE:\r
+ if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }\r
+ if (hwnd == hwndMain) {\r
+ doingSizing = TRUE;\r
+ lastSizing = 0;\r
+ }\r
+ return OnEnterSizeMove( &sd, hwnd, wParam, lParam );\r
+ break;\r
+\r
+ case WM_SIZING:\r
+ if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }\r
+ if (hwnd == hwndMain) {\r
+ lastSizing = wParam;\r
+ }\r
+ break;\r
+\r
+ case WM_MOVING:\r
+ if(appData.debugMode) { fprintf(debugFP, "moving\n"); }\r
+ return OnMoving( &sd, hwnd, wParam, lParam );\r
+\r
+ case WM_EXITSIZEMOVE:\r
+ if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }\r
+ if (hwnd == hwndMain) {\r
+ RECT client;\r
+ doingSizing = FALSE;\r
+ InvalidateRect(hwnd, &boardRect, FALSE);\r
+ GetClientRect(hwnd, &client);\r
+ ResizeBoard(client.right, client.bottom, lastSizing);\r
+ lastSizing = 0;\r
+ if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }\r
+ }\r
+ return OnExitSizeMove( &sd, hwnd, wParam, lParam );\r
+ break;\r
+\r
+ case WM_DESTROY: /* message: window being destroyed */\r
+ PostQuitMessage(0);\r
+ break;\r
+\r
+ case WM_CLOSE:\r
+ if (hwnd == hwndMain) {\r
+ ExitEvent(0);\r
+ }\r
+ break;\r
+\r
+ default: /* Passes it on if unprocessed */\r
+ return (DefWindowProc(hwnd, message, wParam, lParam));\r
+ }\r
+ return 0;\r
+}\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * Misc utility routines\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
+\r
+BOOL\r
+ChangeColor(HWND hwnd, COLORREF *which)\r
+{\r
+ static BOOL firstTime = TRUE;\r
+ static DWORD customColors[16];\r
+ CHOOSECOLOR cc;\r
+ COLORREF newcolor;\r
+ int i;\r
+ ColorClass ccl;\r
+\r
+ if (firstTime) {\r
+ /* Make initial colors in use available as custom colors */\r
+ /* Should we put the compiled-in defaults here instead? */\r
+ i = 0;\r
+ customColors[i++] = lightSquareColor & 0xffffff;\r
+ customColors[i++] = darkSquareColor & 0xffffff;\r
+ customColors[i++] = whitePieceColor & 0xffffff;\r
+ customColors[i++] = blackPieceColor & 0xffffff;\r
+ customColors[i++] = highlightSquareColor & 0xffffff;\r
+ customColors[i++] = premoveHighlightColor & 0xffffff;\r
+\r
+ for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {\r
+ customColors[i++] = textAttribs[ccl].color;\r
+ }\r
+ while (i < 16) customColors[i++] = RGB(255, 255, 255);\r
+ firstTime = FALSE;\r
+ }\r
+\r
+ cc.lStructSize = sizeof(cc);\r
+ cc.hwndOwner = hwnd;\r
+ cc.hInstance = NULL;\r
+ cc.rgbResult = (DWORD) (*which & 0xffffff);\r
+ cc.lpCustColors = (LPDWORD) customColors;\r
+ cc.Flags = CC_RGBINIT|CC_FULLOPEN;\r
+\r
+ if (!ChooseColor(&cc)) return FALSE;\r
+\r
+ newcolor = (COLORREF) (0x2000000 | cc.rgbResult);\r
+ if (newcolor == *which) return FALSE;\r
+ *which = newcolor;\r
+ return TRUE;\r
+\r
+ /*\r
+ InitDrawingColors();\r
+ InvalidateRect(hwnd, &boardRect, FALSE);\r
+ */\r
+}\r
+\r
+BOOLEAN\r
+MyLoadSound(MySound *ms)\r
+{\r
+ BOOL ok = FALSE;\r
+ struct stat st;\r
+ FILE *f;\r
+\r
+ if (ms->data) free(ms->data);\r
+ ms->data = NULL;\r
+\r
+ switch (ms->name[0]) {\r
+ case NULLCHAR:\r
+ /* Silence */\r
+ ok = TRUE;\r
+ break;\r
+ case '$':\r
+ /* System sound from Control Panel. Don't preload here. */\r
+ ok = TRUE;\r
+ break;\r
+ case '!':\r
+ if (ms->name[1] == NULLCHAR) {\r
+ /* "!" alone = silence */\r
+ ok = TRUE;\r
+ } else {\r
+ /* Builtin wave resource. Error if not found. */\r
+ HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");\r
+ if (h == NULL) break;\r
+ ms->data = (void *)LoadResource(hInst, h);\r
+ if (h == NULL) break;\r
+ ok = TRUE;\r
+ }\r
+ break;\r
+ default:\r
+ /* .wav file. Error if not found. */\r
+ f = fopen(ms->name, "rb");\r
+ if (f == NULL) break;\r
+ if (fstat(fileno(f), &st) < 0) break;\r
+ ms->data = malloc(st.st_size);\r
+ if (fread(ms->data, st.st_size, 1, f) < 1) break;\r
+ fclose(f);\r
+ ok = TRUE;\r
+ break;\r
+ }\r
+ if (!ok) {\r
+ char buf[MSG_SIZ];\r
+ sprintf(buf, "Error loading sound %s", ms->name);\r
+ DisplayError(buf, GetLastError());\r
+ }\r
+ return ok;\r
+}\r
+\r
+BOOLEAN\r
+MyPlaySound(MySound *ms)\r
+{\r
+ BOOLEAN ok = FALSE;\r
+\r
+ if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted\r
+ switch (ms->name[0]) {\r
+ case NULLCHAR:\r
+ if(appData.debugMode) fprintf(debugFP, "silence\n");\r
+ /* Silence */\r
+ ok = TRUE;\r
+ break;\r
+ case '$':\r
+ /* System sound from Control Panel (deprecated feature).\r
+ "$" alone or an unset sound name gets default beep (still in use). */\r
+ if (ms->name[1]) {\r
+ ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);\r
+ }\r
+ if (!ok) ok = MessageBeep(MB_OK);\r
+ break; \r
+ case '!':\r
+ /* Builtin wave resource, or "!" alone for silence */\r
+ if (ms->name[1]) {\r
+ if (ms->data == NULL) return FALSE;\r
+ ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);\r
+ } else {\r
+ ok = TRUE;\r
+ }\r
+ break;\r
+ default:\r
+ /* .wav file. Error if not found. */\r
+ if (ms->data == NULL) return FALSE;\r
+ ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);\r
+ break;\r
+ }\r
+ /* Don't print an error: this can happen innocently if the sound driver\r
+ is busy; for instance, if another instance of WinBoard is playing\r
+ a sound at about the same time. */\r
+ return ok;\r
+}\r
+\r
+\r
+LRESULT CALLBACK\r
+OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ BOOL ok;\r
+ OPENFILENAME *ofn;\r
+ static UINT *number; /* gross that this is static */\r
+\r
+ switch (message) {\r
+ case WM_INITDIALOG: /* message: initialize dialog box */\r
+ /* Center the dialog over the application window */\r
+ ofn = (OPENFILENAME *) lParam;\r
+ if (ofn->Flags & OFN_ENABLETEMPLATE) {\r
+ number = (UINT *) ofn->lCustData;\r
+ SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");\r
+ } else {\r
+ number = NULL;\r
+ }\r
+ CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));\r
+ return FALSE; /* Allow for further processing */\r
+\r
+ case WM_COMMAND:\r
+ if ((LOWORD(wParam) == IDOK) && (number != NULL)) {\r
+ *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);\r
+ }\r
+ return FALSE; /* Allow for further processing */\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+UINT APIENTRY\r
+OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ static UINT *number;\r
+ OPENFILENAME *ofname;\r
+ OFNOTIFY *ofnot;\r
+ switch (uiMsg) {\r
+ case WM_INITDIALOG:\r
+ ofname = (OPENFILENAME *)lParam;\r
+ number = (UINT *)(ofname->lCustData);\r
+ break;\r
+ case WM_NOTIFY:\r
+ ofnot = (OFNOTIFY *)lParam;\r
+ if (ofnot->hdr.code == CDN_FILEOK) {\r
+ *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);\r
+ }\r
+ break;\r
+ }\r
+ return 0;\r
+}\r
+\r
+\r
+FILE *\r
+OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string\r
+ char *nameFilt, char *dlgTitle, UINT *number,\r
+ char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])\r
+{\r
+ OPENFILENAME openFileName;\r
+ char buf1[MSG_SIZ];\r
+ FILE *f;\r
+\r
+ if (fileName == NULL) fileName = buf1;\r
+ if (defName == NULL) {\r
+ strcpy(fileName, "*.");\r
+ strcat(fileName, defExt);\r
+ } else {\r
+ strcpy(fileName, defName);\r
+ }\r
+ if (fileTitle) strcpy(fileTitle, "");\r
+ if (number) *number = 0;\r
+\r
+ openFileName.lStructSize = sizeof(OPENFILENAME);\r
+ openFileName.hwndOwner = hwnd;\r
+ openFileName.hInstance = (HANDLE) hInst;\r
+ openFileName.lpstrFilter = nameFilt;\r
+ openFileName.lpstrCustomFilter = (LPSTR) NULL;\r
+ openFileName.nMaxCustFilter = 0L;\r
+ openFileName.nFilterIndex = 1L;\r
+ openFileName.lpstrFile = fileName;\r
+ openFileName.nMaxFile = MSG_SIZ;\r
+ openFileName.lpstrFileTitle = fileTitle;\r
+ openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;\r
+ openFileName.lpstrInitialDir = NULL;\r
+ openFileName.lpstrTitle = dlgTitle;\r
+ openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY \r
+ | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST) \r
+ | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)\r
+ | (oldDialog ? 0 : OFN_EXPLORER);\r
+ openFileName.nFileOffset = 0;\r
+ openFileName.nFileExtension = 0;\r
+ openFileName.lpstrDefExt = defExt;\r
+ openFileName.lCustData = (LONG) number;\r
+ openFileName.lpfnHook = oldDialog ?\r
+ (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;\r
+ openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);\r
+\r
+ if (write[0] != 'r' ? GetSaveFileName(&openFileName) : \r
+ GetOpenFileName(&openFileName)) {\r
+ /* open the file */\r
+ f = fopen(openFileName.lpstrFile, write);\r
+ if (f == NULL) {\r
+ MessageBox(hwnd, "File open failed", NULL,\r
+ MB_OK|MB_ICONEXCLAMATION);\r
+ return NULL;\r
+ }\r
+ } else {\r
+ int err = CommDlgExtendedError();\r
+ if (err != 0) DisplayError("Internal error in file dialog box", err);\r
+ return FALSE;\r
+ }\r
+ return f;\r
+}\r
+\r
+\r
+\r
+VOID APIENTRY\r
+MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)\r
+{\r
+ HMENU hmenuTrackPopup; /* floating pop-up menu */\r
+\r
+ /*\r
+ * Get the first pop-up menu in the menu template. This is the\r
+ * menu that TrackPopupMenu displays.\r
+ */\r
+ hmenuTrackPopup = GetSubMenu(hmenu, 0);\r
+\r
+ SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);\r
+\r
+ /*\r
+ * TrackPopup uses screen coordinates, so convert the\r
+ * coordinates of the mouse click to screen coordinates.\r
+ */\r
+ ClientToScreen(hwnd, (LPPOINT) &pt);\r
+\r
+ /* Draw and track the floating pop-up menu. */\r
+ TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,\r
+ pt.x, pt.y, 0, hwnd, NULL);\r
+\r
+ /* Destroy the menu.*/\r
+ DestroyMenu(hmenu);\r
+}\r
+ \r
+typedef struct {\r
+ HWND hDlg, hText;\r
+ int sizeX, sizeY, newSizeX, newSizeY;\r
+ HDWP hdwp;\r
+} ResizeEditPlusButtonsClosure;\r
+\r
+BOOL CALLBACK\r
+ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)\r
+{\r
+ ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;\r
+ RECT rect;\r
+ POINT pt;\r
+\r
+ if (hChild == cl->hText) return TRUE;\r
+ GetWindowRect(hChild, &rect); /* gives screen coords */\r
+ pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;\r
+ pt.y = rect.top + cl->newSizeY - cl->sizeY;\r
+ ScreenToClient(cl->hDlg, &pt);\r
+ cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL, \r
+ pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);\r
+ return TRUE;\r
+}\r
+\r
+/* Resize a dialog that has a (rich) edit field filling most of\r
+ the top, with a row of buttons below */\r
+VOID\r
+ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)\r
+{\r
+ RECT rectText;\r
+ int newTextHeight, newTextWidth;\r
+ ResizeEditPlusButtonsClosure cl;\r
+ \r
+ /*if (IsIconic(hDlg)) return;*/\r
+ if (newSizeX == sizeX && newSizeY == sizeY) return;\r
+ \r
+ cl.hdwp = BeginDeferWindowPos(8);\r
+\r
+ GetWindowRect(hText, &rectText); /* gives screen coords */\r
+ newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;\r
+ newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;\r
+ if (newTextHeight < 0) {\r
+ newSizeY += -newTextHeight;\r
+ newTextHeight = 0;\r
+ }\r
+ cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0, \r
+ newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);\r
+\r
+ cl.hDlg = hDlg;\r
+ cl.hText = hText;\r
+ cl.sizeX = sizeX;\r
+ cl.sizeY = sizeY;\r
+ cl.newSizeX = newSizeX;\r
+ cl.newSizeY = newSizeY;\r
+ EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);\r
+\r
+ EndDeferWindowPos(cl.hdwp);\r
+}\r
+\r
+BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)\r
+{\r
+ RECT rChild, rParent;\r
+ int wChild, hChild, wParent, hParent;\r
+ int wScreen, hScreen, xNew, yNew;\r
+ HDC hdc;\r
+\r
+ /* Get the Height and Width of the child window */\r
+ GetWindowRect (hwndChild, &rChild);\r
+ wChild = rChild.right - rChild.left;\r
+ hChild = rChild.bottom - rChild.top;\r
+\r
+ /* Get the Height and Width of the parent window */\r
+ GetWindowRect (hwndParent, &rParent);\r
+ wParent = rParent.right - rParent.left;\r
+ hParent = rParent.bottom - rParent.top;\r
+\r
+ /* Get the display limits */\r
+ hdc = GetDC (hwndChild);\r
+ wScreen = GetDeviceCaps (hdc, HORZRES);\r
+ hScreen = GetDeviceCaps (hdc, VERTRES);\r
+ ReleaseDC(hwndChild, hdc);\r
+\r
+ /* Calculate new X position, then adjust for screen */\r
+ xNew = rParent.left + ((wParent - wChild) /2);\r
+ if (xNew < 0) {\r
+ xNew = 0;\r
+ } else if ((xNew+wChild) > wScreen) {\r
+ xNew = wScreen - wChild;\r
+ }\r
+\r
+ /* Calculate new Y position, then adjust for screen */\r
+ if( mode == 0 ) {\r
+ yNew = rParent.top + ((hParent - hChild) /2);\r
+ }\r
+ else {\r
+ yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;\r
+ }\r
+\r
+ if (yNew < 0) {\r
+ yNew = 0;\r
+ } else if ((yNew+hChild) > hScreen) {\r
+ yNew = hScreen - hChild;\r
+ }\r
+\r
+ /* Set it, and return */\r
+ return SetWindowPos (hwndChild, NULL,\r
+ xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);\r
+}\r
+\r
+/* Center one window over another */\r
+BOOL CenterWindow (HWND hwndChild, HWND hwndParent)\r
+{\r
+ return CenterWindowEx( hwndChild, hwndParent, 0 );\r
+}\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * Startup Dialog functions\r
+ *\r
+\*---------------------------------------------------------------------------*/\r
+void\r
+InitComboStrings(HANDLE hwndCombo, char **cd)\r
+{\r
+ SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);\r
+\r
+ while (*cd != NULL) {\r
+ SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);\r
+ cd++;\r
+ }\r
+}\r
+\r
+void\r
+InitComboStringsFromOption(HANDLE hwndCombo, char *str)\r
+{\r
+ char buf1[ARG_MAX];\r
+ int len;\r
+\r
+ if (str[0] == '@') {\r
+ FILE* f = fopen(str + 1, "r");\r
+ if (f == NULL) {\r
+ DisplayFatalError(str + 1, errno, 2);\r
+ return;\r
+ }\r
+ len = fread(buf1, 1, sizeof(buf1)-1, f);\r
+ fclose(f);\r
+ buf1[len] = NULLCHAR;\r
+ str = buf1;\r
+ }\r
+\r
+ SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);\r
+\r
+ for (;;) {\r
+ char buf[MSG_SIZ];\r
+ char *end = strchr(str, '\n');\r
+ if (end == NULL) return;\r
+ memcpy(buf, str, end - str);\r
+ buf[end - str] = NULLCHAR;\r
+ SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);\r
+ str = end + 1;\r
+ }\r
+}\r
+\r
+void\r
+SetStartupDialogEnables(HWND hDlg)\r
+{\r
+ EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),\r
+ IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||\r
+ (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));\r
+ EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),\r
+ IsDlgButtonChecked(hDlg, OPT_ChessEngine));\r
+ EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),\r
+ IsDlgButtonChecked(hDlg, OPT_ChessServer));\r
+ EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),\r
+ IsDlgButtonChecked(hDlg, OPT_AnyAdditional));\r
+ EnableWindow(GetDlgItem(hDlg, IDOK),\r
+ IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||\r
+ IsDlgButtonChecked(hDlg, OPT_ChessServer) ||\r
+ IsDlgButtonChecked(hDlg, OPT_View));\r
+}\r
+\r
+char *\r
+QuoteForFilename(char *filename)\r
+{\r
+ int dquote, space;\r
+ dquote = strchr(filename, '"') != NULL;\r
+ space = strchr(filename, ' ') != NULL;\r
+ if (dquote || space) {\r
+ if (dquote) {\r
+ return "'";\r
+ } else {\r
+ return "\"";\r
+ }\r
+ } else {\r
+ return "";\r
+ }\r
+}\r
+\r
+VOID\r
+InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)\r
+{\r
+ char buf[MSG_SIZ];\r
+ char *q;\r
+\r
+ InitComboStringsFromOption(hwndCombo, nthnames);\r
+ q = QuoteForFilename(nthcp);\r
+ sprintf(buf, "%s%s%s", q, nthcp, q);\r
+ if (*nthdir != NULLCHAR) {\r
+ q = QuoteForFilename(nthdir);\r
+ sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);\r
+ }\r
+ if (*nthcp == NULLCHAR) {\r
+ SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);\r
+ } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {\r
+ SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);\r
+ SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);\r
+ }\r
+}\r
+\r
+LRESULT CALLBACK\r
+StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ char buf[MSG_SIZ];\r
+ HANDLE hwndCombo;\r
+ char *p;\r
+\r
+ switch (message) {\r
+ case WM_INITDIALOG:\r
+ /* Center the dialog */\r
+ CenterWindow (hDlg, GetDesktopWindow());\r
+ /* Initialize the dialog items */\r
+ InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),\r
+ appData.firstChessProgram, "fd", appData.firstDirectory,\r
+ firstChessProgramNames);\r
+ InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),\r
+ appData.secondChessProgram, "sd", appData.secondDirectory,\r
+ secondChessProgramNames);\r
+ hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);\r
+ InitComboStringsFromOption(hwndCombo, icsNames); \r
+ sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);\r
+ if (*appData.icsHelper != NULLCHAR) {\r
+ char *q = QuoteForFilename(appData.icsHelper);\r
+ sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);\r
+ }\r
+ if (*appData.icsHost == NULLCHAR) {\r
+ SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);\r
+ /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */\r
+ } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {\r
+ SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);\r
+ SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);\r
+ }\r
+\r
+ if (appData.icsActive) {\r
+ CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);\r
+ }\r
+ else if (appData.noChessProgram) {\r
+ CheckDlgButton(hDlg, OPT_View, BST_CHECKED);\r
+ }\r
+ else {\r
+ CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);\r
+ }\r
+\r
+ SetStartupDialogEnables(hDlg);\r
+ return TRUE;\r
+\r
+ case WM_COMMAND:\r
+ switch (LOWORD(wParam)) {\r
+ case IDOK:\r
+ if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {\r
+ strcpy(buf, "/fcp=");\r
+ GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
+ p = buf;\r
+ ParseArgs(StringGet, &p);\r
+ strcpy(buf, "/scp=");\r
+ GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
+ p = buf;\r
+ ParseArgs(StringGet, &p);\r
+ appData.noChessProgram = FALSE;\r
+ appData.icsActive = FALSE;\r
+ } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {\r
+ strcpy(buf, "/ics /icshost=");\r
+ GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
+ p = buf;\r
+ ParseArgs(StringGet, &p);\r
+ if (appData.zippyPlay) {\r
+ strcpy(buf, "/fcp=");\r
+ GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
+ p = buf;\r
+ ParseArgs(StringGet, &p);\r
+ }\r
+ } else if (IsDlgButtonChecked(hDlg, OPT_View)) {\r
+ appData.noChessProgram = TRUE;\r
+ appData.icsActive = FALSE;\r
+ } else {\r
+ MessageBox(hDlg, "Choose an option, or cancel to exit",\r
+ "Option Error", MB_OK|MB_ICONEXCLAMATION);\r
+ return TRUE;\r
+ }\r
+ if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {\r
+ GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));\r
+ p = buf;\r
+ ParseArgs(StringGet, &p);\r
+ }\r
+ EndDialog(hDlg, TRUE);\r
+ return TRUE;\r
+\r
+ case IDCANCEL:\r
+ ExitEvent(0);\r
+ return TRUE;\r
+\r
+ case IDM_HELPCONTENTS:\r
+ if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {\r
+ MessageBox (GetFocus(),\r
+ "Unable to activate help",\r
+ szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
+ }\r
+ break;\r
+\r
+ default:\r
+ SetStartupDialogEnables(hDlg);\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * About box dialog functions\r
+ *\r
+\*---------------------------------------------------------------------------*/\r
+\r
+/* Process messages for "About" dialog box */\r
+LRESULT CALLBACK\r
+About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ switch (message) {\r
+ case WM_INITDIALOG: /* message: initialize dialog box */\r
+ /* Center the dialog over the application window */\r
+ CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));\r
+ SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);\r
+ JAWS_COPYRIGHT\r
+ return (TRUE);\r
+\r
+ case WM_COMMAND: /* message: received a command */\r
+ if (LOWORD(wParam) == IDOK /* "OK" box selected? */\r
+ || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */\r
+ EndDialog(hDlg, TRUE); /* Exit the dialog */\r
+ return (TRUE);\r
+ }\r
+ break;\r
+ }\r
+ return (FALSE);\r
+}\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * Comment Dialog functions\r
+ *\r
+\*---------------------------------------------------------------------------*/\r
+\r
+LRESULT CALLBACK\r
+CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ static HANDLE hwndText = NULL;\r
+ int len, newSizeX, newSizeY, flags;\r
+ static int sizeX, sizeY;\r
+ char *str;\r
+ RECT rect;\r
+ MINMAXINFO *mmi;\r
+\r
+ switch (message) {\r
+ case WM_INITDIALOG: /* message: initialize dialog box */\r
+ /* Initialize the dialog items */\r
+ hwndText = GetDlgItem(hDlg, OPT_CommentText);\r
+ SetDlgItemText(hDlg, OPT_CommentText, commentText);\r
+ EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);\r
+ EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);\r
+ EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);\r
+ SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);\r
+ SetWindowText(hDlg, commentTitle);\r
+ if (editComment) {\r
+ SetFocus(hwndText);\r
+ } else {\r
+ SetFocus(GetDlgItem(hDlg, IDOK));\r
+ }\r
+ SendMessage(GetDlgItem(hDlg, OPT_CommentText),\r
+ WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,\r
+ MAKELPARAM(FALSE, 0));\r
+ /* Size and position the dialog */\r
+ if (!commentDialog) {\r
+ commentDialog = hDlg;\r
+ flags = SWP_NOZORDER;\r
+ GetClientRect(hDlg, &rect);\r
+ sizeX = rect.right;\r
+ sizeY = rect.bottom;\r
+ if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&\r
+ commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {\r
+ WINDOWPLACEMENT wp;\r
+ EnsureOnScreen(&commentX, &commentY, 0, 0);\r
+ wp.length = sizeof(WINDOWPLACEMENT);\r
+ wp.flags = 0;\r
+ wp.showCmd = SW_SHOW;\r
+ wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
+ wp.rcNormalPosition.left = commentX;\r
+ wp.rcNormalPosition.right = commentX + commentW;\r
+ wp.rcNormalPosition.top = commentY;\r
+ wp.rcNormalPosition.bottom = commentY + commentH;\r
+ SetWindowPlacement(hDlg, &wp);\r
+\r
+ GetClientRect(hDlg, &rect);\r
+ newSizeX = rect.right;\r
+ newSizeY = rect.bottom;\r
+ ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,\r
+ newSizeX, newSizeY);\r
+ sizeX = newSizeX;\r
+ sizeY = newSizeY;\r
+ }\r
+ }\r
+ return FALSE;\r
+\r
+ case WM_COMMAND: /* message: received a command */\r
+ switch (LOWORD(wParam)) {\r
+ case IDOK:\r
+ if (editComment) {\r
+ char *p, *q;\r
+ /* Read changed options from the dialog box */\r
+ hwndText = GetDlgItem(hDlg, OPT_CommentText);\r
+ len = GetWindowTextLength(hwndText);\r
+ str = (char *) malloc(len + 1);\r
+ GetWindowText(hwndText, str, len + 1);\r
+ p = q = str;\r
+ while (*q) {\r
+ if (*q == '\r')\r
+ q++;\r
+ else\r
+ *p++ = *q++;\r
+ }\r
+ *p = NULLCHAR;\r
+ ReplaceComment(commentIndex, str);\r
+ free(str);\r
+ }\r
+ CommentPopDown();\r
+ return TRUE;\r
+\r
+ case IDCANCEL:\r
+ case OPT_CancelComment:\r
+ CommentPopDown();\r
+ return TRUE;\r
+\r
+ case OPT_ClearComment:\r
+ SetDlgItemText(hDlg, OPT_CommentText, "");\r
+ break;\r
+\r
+ case OPT_EditComment:\r
+ EditCommentEvent();\r
+ return TRUE;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case WM_SIZE:\r
+ newSizeX = LOWORD(lParam);\r
+ newSizeY = HIWORD(lParam);\r
+ ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);\r
+ sizeX = newSizeX;\r
+ sizeY = newSizeY;\r
+ break;\r
+\r
+ case WM_GETMINMAXINFO:\r
+ /* Prevent resizing window too small */\r
+ mmi = (MINMAXINFO *) lParam;\r
+ mmi->ptMinTrackSize.x = 100;\r
+ mmi->ptMinTrackSize.y = 100;\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+VOID\r
+EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)\r
+{\r
+ FARPROC lpProc;\r
+ char *p, *q;\r
+\r
+ CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);\r
+\r
+ if (str == NULL) str = "";\r
+ p = (char *) malloc(2 * strlen(str) + 2);\r
+ q = p;\r
+ while (*str) {\r
+ if (*str == '\n') *q++ = '\r';\r
+ *q++ = *str++;\r
+ }\r
+ *q = NULLCHAR;\r
+ if (commentText != NULL) free(commentText);\r
+\r
+ commentIndex = index;\r
+ commentTitle = title;\r
+ commentText = p;\r
+ editComment = edit;\r
+\r
+ if (commentDialog) {\r
+ SendMessage(commentDialog, WM_INITDIALOG, 0, 0);\r
+ if (!commentUp) ShowWindow(commentDialog, SW_SHOW);\r
+ } else {\r
+ lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);\r
+ CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),\r
+ hwndMain, (DLGPROC)lpProc);\r
+ FreeProcInstance(lpProc);\r
+ }\r
+ commentUp = TRUE;\r
+}\r
+\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * Type-in move dialog functions\r
+ * \r
+\*---------------------------------------------------------------------------*/\r
+\r
+LRESULT CALLBACK\r
+TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ char move[MSG_SIZ];\r
+ HWND hInput;\r
+ ChessMove moveType;\r
+ int fromX, fromY, toX, toY;\r
+ char promoChar;\r
+\r
+ switch (message) {\r
+ case WM_INITDIALOG:\r
+ move[0] = (char) lParam;\r
+ move[1] = NULLCHAR;\r
+ CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );\r
+ hInput = GetDlgItem(hDlg, OPT_Move);\r
+ SetWindowText(hInput, move);\r
+ SetFocus(hInput);\r
+ SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);\r
+ return FALSE;\r
+\r
+ case WM_COMMAND:\r
+ switch (LOWORD(wParam)) {\r
+ case IDOK:\r
+ GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));\r
+ { int n; Board board;\r
+ // [HGM] FENedit\r
+ if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {\r
+ EditPositionPasteFEN(move);\r
+ EndDialog(hDlg, TRUE);\r
+ return TRUE;\r
+ }\r
+ // [HGM] movenum: allow move number to be typed in any mode\r
+ if(sscanf(move, "%d", &n) == 1 && n != 0 ) {\r
+ ToNrEvent(2*n-1);\r
+ EndDialog(hDlg, TRUE);\r
+ return TRUE;\r
+ }\r
+ }\r
+ if (gameMode != EditGame && currentMove != forwardMostMove && \r
+ gameMode != Training) {\r
+ DisplayMoveError("Displayed move is not current");\r
+ } else {\r
+// GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream\r
+ int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
+ &moveType, &fromX, &fromY, &toX, &toY, &promoChar);\r
+ if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized\r
+ if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
+ &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {\r
+ if (gameMode != Training)\r
+ forwardMostMove = currentMove;\r
+ UserMoveEvent(fromX, fromY, toX, toY, promoChar); \r
+ } else {\r
+ DisplayMoveError("Could not parse move");\r
+ }\r
+ }\r
+ EndDialog(hDlg, TRUE);\r
+ return TRUE;\r
+ case IDCANCEL:\r
+ EndDialog(hDlg, FALSE);\r
+ return TRUE;\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+VOID\r
+PopUpMoveDialog(char firstchar)\r
+{\r
+ FARPROC lpProc;\r
+ \r
+ if ((gameMode == BeginningOfGame && !appData.icsActive) || \r
+ gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||\r
+ gameMode == AnalyzeMode || gameMode == EditGame || \r
+ gameMode == EditPosition || gameMode == IcsExamining ||\r
+ gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||\r
+ isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes\r
+ ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||\r
+ gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||\r
+ gameMode == Training) {\r
+ lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);\r
+ DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),\r
+ hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);\r
+ FreeProcInstance(lpProc);\r
+ }\r
+}\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * Type-in name dialog functions\r
+ * \r
+\*---------------------------------------------------------------------------*/\r
+\r
+LRESULT CALLBACK\r
+TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ char move[MSG_SIZ];\r
+ HWND hInput;\r
+\r
+ switch (message) {\r
+ case WM_INITDIALOG:\r
+ move[0] = (char) lParam;\r
+ move[1] = NULLCHAR;\r
+ CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );\r
+ hInput = GetDlgItem(hDlg, OPT_Name);\r
+ SetWindowText(hInput, move);\r
+ SetFocus(hInput);\r
+ SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);\r
+ return FALSE;\r
+\r
+ case WM_COMMAND:\r
+ switch (LOWORD(wParam)) {\r
+ case IDOK:\r
+ GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));\r
+ appData.userName = strdup(move);\r
+ SetUserLogo();\r
+\r
+ EndDialog(hDlg, TRUE);\r
+ return TRUE;\r
+ case IDCANCEL:\r
+ EndDialog(hDlg, FALSE);\r
+ return TRUE;\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+VOID\r
+PopUpNameDialog(char firstchar)\r
+{\r
+ FARPROC lpProc;\r
+ \r
+ lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);\r
+ DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),\r
+ hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);\r
+ FreeProcInstance(lpProc);\r
+}\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * Error dialogs\r
+ * \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
+ if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");\r
+ if (errorDialog == NULL) return;\r
+ DestroyWindow(errorDialog);\r
+ errorDialog = NULL;\r
+}\r
+\r
+LRESULT CALLBACK\r
+ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ HANDLE hwndText;\r
+ RECT rChild;\r
+\r
+ switch (message) {\r
+ case WM_INITDIALOG:\r
+ GetWindowRect(hDlg, &rChild);\r
+\r
+ /*\r
+ SetWindowPos(hDlg, NULL, rChild.left,\r
+ rChild.top + boardRect.top - (rChild.bottom - rChild.top), \r
+ 0, 0, SWP_NOZORDER|SWP_NOSIZE);\r
+ */\r
+\r
+ /* \r
+ [AS] It seems that the above code wants to move the dialog up in the "caption\r
+ area" of the main window, but it uses the dialog height as an hard-coded constant,\r
+ and it doesn't work when you resize the dialog.\r
+ For now, just give it a default position.\r
+ */\r
+ SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);\r
+\r
+ errorDialog = hDlg;\r
+ SetWindowText(hDlg, errorTitle);\r
+ hwndText = GetDlgItem(hDlg, OPT_ErrorText);\r
+ SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);\r
+ return FALSE;\r
+\r
+ case WM_COMMAND:\r
+ switch (LOWORD(wParam)) {\r
+ case IDOK:\r
+ case IDCANCEL:\r
+ if (errorDialog == hDlg) errorDialog = NULL;\r
+ DestroyWindow(hDlg);\r
+ return TRUE;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+#ifdef GOTHIC\r
+HWND gothicDialog = NULL;\r
+\r
+LRESULT CALLBACK\r
+GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ HANDLE hwndText;\r
+ RECT rChild;\r
+ int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);\r
+\r
+ switch (message) {\r
+ case WM_INITDIALOG:\r
+ GetWindowRect(hDlg, &rChild);\r
+\r
+ SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,\r
+ SWP_NOZORDER);\r
+\r
+ /* \r
+ [AS] It seems that the above code wants to move the dialog up in the "caption\r
+ area" of the main window, but it uses the dialog height as an hard-coded constant,\r
+ and it doesn't work when you resize the dialog.\r
+ For now, just give it a default position.\r
+ */\r
+ gothicDialog = hDlg;\r
+ SetWindowText(hDlg, errorTitle);\r
+ hwndText = GetDlgItem(hDlg, OPT_ErrorText);\r
+ SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);\r
+ return FALSE;\r
+\r
+ case WM_COMMAND:\r
+ switch (LOWORD(wParam)) {\r
+ case IDOK:\r
+ case IDCANCEL:\r
+ if (errorDialog == hDlg) errorDialog = NULL;\r
+ DestroyWindow(hDlg);\r
+ return TRUE;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+VOID\r
+GothicPopUp(char *title, VariantClass variant)\r
+{\r
+ FARPROC lpProc;\r
+ static char *lastTitle;\r
+\r
+ strncpy(errorTitle, title, sizeof(errorTitle));\r
+ errorTitle[sizeof(errorTitle) - 1] = '\0';\r
+\r
+ if(lastTitle != title && gothicDialog != NULL) {\r
+ DestroyWindow(gothicDialog);\r
+ gothicDialog = NULL;\r
+ }\r
+ if(variant != VariantNormal && gothicDialog == NULL) {\r
+ title = lastTitle;\r
+ lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);\r
+ CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),\r
+ hwndMain, (DLGPROC)lpProc);\r
+ FreeProcInstance(lpProc);\r
+ }\r
+}\r
+#endif\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * Ics Interaction console functions\r
+ *\r
+\*---------------------------------------------------------------------------*/\r
+\r
+#define HISTORY_SIZE 64\r
+static char *history[HISTORY_SIZE];\r
+int histIn = 0, histP = 0;\r
+\r
+VOID\r
+SaveInHistory(char *cmd)\r
+{\r
+ if (history[histIn] != NULL) {\r
+ free(history[histIn]);\r
+ history[histIn] = NULL;\r
+ }\r
+ if (*cmd == NULLCHAR) return;\r
+ history[histIn] = StrSave(cmd);\r
+ histIn = (histIn + 1) % HISTORY_SIZE;\r
+ if (history[histIn] != NULL) {\r
+ free(history[histIn]);\r
+ history[histIn] = NULL;\r
+ }\r
+ histP = histIn;\r
+}\r
+\r
+char *\r
+PrevInHistory(char *cmd)\r
+{\r
+ int newhp;\r
+ if (histP == histIn) {\r
+ if (history[histIn] != NULL) free(history[histIn]);\r
+ history[histIn] = StrSave(cmd);\r
+ }\r
+ newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;\r
+ if (newhp == histIn || history[newhp] == NULL) return NULL;\r
+ histP = newhp;\r
+ return history[histP];\r
+}\r
+\r
+char *\r
+NextInHistory()\r
+{\r
+ if (histP == histIn) return NULL;\r
+ histP = (histP + 1) % HISTORY_SIZE;\r
+ return history[histP];\r
+}\r
+\r
+typedef struct {\r
+ char *item;\r
+ char *command;\r
+ BOOLEAN getname;\r
+ BOOLEAN immediate;\r
+} IcsTextMenuEntry;\r
+#define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)\r
+IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];\r
+\r
+void\r
+ParseIcsTextMenu(char *icsTextMenuString)\r
+{\r
+// int flags = 0;\r
+ IcsTextMenuEntry *e = icsTextMenuEntry;\r
+ char *p = icsTextMenuString;\r
+ while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {\r
+ free(e->item);\r
+ e->item = NULL;\r
+ if (e->command != NULL) {\r
+ free(e->command);\r
+ e->command = NULL;\r
+ }\r
+ e++;\r
+ }\r
+ e = icsTextMenuEntry;\r
+ while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {\r
+ if (*p == ';' || *p == '\n') {\r
+ e->item = strdup("-");\r
+ e->command = NULL;\r
+ p++;\r
+ } else if (*p == '-') {\r
+ e->item = strdup("-");\r
+ e->command = NULL;\r
+ p++;\r
+ if (*p) p++;\r
+ } else {\r
+ char *q, *r, *s, *t;\r
+ char c;\r
+ q = strchr(p, ',');\r
+ if (q == NULL) break;\r
+ *q = NULLCHAR;\r
+ r = strchr(q + 1, ',');\r
+ if (r == NULL) break;\r
+ *r = NULLCHAR;\r
+ s = strchr(r + 1, ',');\r
+ if (s == NULL) break;\r
+ *s = NULLCHAR;\r
+ c = ';';\r
+ t = strchr(s + 1, c);\r
+ if (t == NULL) {\r
+ c = '\n';\r
+ t = strchr(s + 1, c);\r
+ }\r
+ if (t != NULL) *t = NULLCHAR;\r
+ e->item = strdup(p);\r
+ e->command = strdup(q + 1);\r
+ e->getname = *(r + 1) != '0';\r
+ e->immediate = *(s + 1) != '0';\r
+ *q = ',';\r
+ *r = ',';\r
+ *s = ',';\r
+ if (t == NULL) break;\r
+ *t = c;\r
+ p = t + 1;\r
+ }\r
+ e++;\r
+ } \r
+}\r
+\r
+HMENU\r
+LoadIcsTextMenu(IcsTextMenuEntry *e)\r
+{\r
+ HMENU hmenu, h;\r
+ int i = 0;\r
+ hmenu = LoadMenu(hInst, "TextMenu");\r
+ h = GetSubMenu(hmenu, 0);\r
+ while (e->item) {\r
+ if (strcmp(e->item, "-") == 0) {\r
+ AppendMenu(h, MF_SEPARATOR, 0, 0);\r
+ } else {\r
+ if (e->item[0] == '|') {\r
+ AppendMenu(h, MF_STRING|MF_MENUBARBREAK,\r
+ IDM_CommandX + i, &e->item[1]);\r
+ } else {\r
+ AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);\r
+ }\r
+ }\r
+ e++;\r
+ i++;\r
+ } \r
+ return hmenu;\r
+}\r
+\r
+WNDPROC consoleTextWindowProc;\r
+\r
+void\r
+CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)\r
+{\r
+ char buf[MSG_SIZ], name[MSG_SIZ];\r
+ HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+ CHARRANGE sel;\r
+\r
+ if (!getname) {\r
+ SetWindowText(hInput, command);\r
+ if (immediate) {\r
+ SendMessage(hInput, WM_CHAR, '\r', 0);\r
+ } else {\r
+ sel.cpMin = 999999;\r
+ sel.cpMax = 999999;\r
+ SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ SetFocus(hInput);\r
+ }\r
+ return;\r
+ } \r
+ SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
+ if (sel.cpMin == sel.cpMax) {\r
+ /* Expand to surrounding word */\r
+ TEXTRANGE tr;\r
+ do {\r
+ tr.chrg.cpMax = sel.cpMin;\r
+ tr.chrg.cpMin = --sel.cpMin;\r
+ if (sel.cpMin < 0) break;\r
+ tr.lpstrText = name;\r
+ SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);\r
+ } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');\r
+ sel.cpMin++;\r
+\r
+ do {\r
+ tr.chrg.cpMin = sel.cpMax;\r
+ tr.chrg.cpMax = ++sel.cpMax;\r
+ tr.lpstrText = name;\r
+ if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;\r
+ } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');\r
+ sel.cpMax--;\r
+\r
+ if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {\r
+ MessageBeep(MB_ICONEXCLAMATION);\r
+ return;\r
+ }\r
+ tr.chrg = sel;\r
+ tr.lpstrText = name;\r
+ SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);\r
+ } else {\r
+ if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {\r
+ MessageBeep(MB_ICONEXCLAMATION);\r
+ return;\r
+ }\r
+ SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);\r
+ }\r
+ if (immediate) {\r
+ sprintf(buf, "%s %s", command, name);\r
+ SetWindowText(hInput, buf);\r
+ SendMessage(hInput, WM_CHAR, '\r', 0);\r
+ } else {\r
+ sprintf(buf, "%s %s ", command, name); /* trailing space */\r
+ SetWindowText(hInput, buf);\r
+ sel.cpMin = 999999;\r
+ sel.cpMax = 999999;\r
+ SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ SetFocus(hInput);\r
+ }\r
+}\r
+\r
+LRESULT CALLBACK \r
+ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ HWND hInput;\r
+ CHARRANGE sel;\r
+\r
+ switch (message) {\r
+ case WM_KEYDOWN:\r
+ if (!(GetKeyState(VK_CONTROL) & ~1)) break;\r
+ switch (wParam) {\r
+ case VK_PRIOR:\r
+ SendMessage(hwnd, EM_LINESCROLL, 0, -999999);\r
+ return 0;\r
+ case VK_NEXT:\r
+ sel.cpMin = 999999;\r
+ sel.cpMax = 999999;\r
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ SendMessage(hwnd, EM_SCROLLCARET, 0, 0);\r
+ return 0;\r
+ }\r
+ break;\r
+ case WM_CHAR:\r
+ if(wParam != '\022') {\r
+ if (wParam == '\t') {\r
+ if (GetKeyState(VK_SHIFT) < 0) {\r
+ /* shifted */\r
+ if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);\r
+ if (buttonDesc[0].hwnd) {\r
+ SetFocus(buttonDesc[0].hwnd);\r
+ } else {\r
+ SetFocus(hwndMain);\r
+ }\r
+ } else {\r
+ /* unshifted */\r
+ SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));\r
+ }\r
+ } else {\r
+ hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+ JAWS_DELETE( SetFocus(hInput); )\r
+ SendMessage(hInput, message, wParam, lParam);\r
+ }\r
+ return 0;\r
+ } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu\r
+ case WM_RBUTTONUP:\r
+ if (GetKeyState(VK_SHIFT) & ~1) {\r
+ SendDlgItemMessage(hwndConsole, OPT_ConsoleText, \r
+ WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
+ } else {\r
+ POINT pt;\r
+ HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);\r
+ SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
+ if (sel.cpMin == sel.cpMax) {\r
+ EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);\r
+ EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);\r
+ }\r
+ if (!IsClipboardFormatAvailable(CF_TEXT)) {\r
+ EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);\r
+ }\r
+ pt.x = LOWORD(lParam);\r
+ pt.y = HIWORD(lParam);\r
+ MenuPopup(hwnd, pt, hmenu, -1);\r
+ }\r
+ return 0;\r
+ case WM_PASTE:\r
+ hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+ SetFocus(hInput);\r
+ return SendMessage(hInput, message, wParam, lParam);\r
+ case WM_MBUTTONDOWN:\r
+ return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
+ case WM_RBUTTONDOWN:\r
+ if (!(GetKeyState(VK_SHIFT) & ~1)) {\r
+ /* Move selection here if it was empty */\r
+ POINT pt;\r
+ pt.x = LOWORD(lParam);\r
+ pt.y = HIWORD(lParam);\r
+ SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
+ if (sel.cpMin == sel.cpMax) {\r
+ sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/\r
+ sel.cpMax = sel.cpMin;\r
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ }\r
+ SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);\r
+ }\r
+ return 0;\r
+ case WM_COMMAND:\r
+ switch (LOWORD(wParam)) {\r
+ case IDM_QuickPaste:\r
+ {\r
+ SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
+ if (sel.cpMin == sel.cpMax) {\r
+ MessageBeep(MB_ICONEXCLAMATION);\r
+ return 0;\r
+ }\r
+ SendMessage(hwnd, WM_COPY, 0, 0);\r
+ hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+ SendMessage(hInput, WM_PASTE, 0, 0);\r
+ SetFocus(hInput);\r
+ return 0;\r
+ }\r
+ case IDM_Cut:\r
+ SendMessage(hwnd, WM_CUT, 0, 0);\r
+ return 0;\r
+ case IDM_Paste:\r
+ SendMessage(hwnd, WM_PASTE, 0, 0);\r
+ return 0;\r
+ case IDM_Copy:\r
+ SendMessage(hwnd, WM_COPY, 0, 0);\r
+ return 0;\r
+ default:\r
+ {\r
+ int i = LOWORD(wParam) - IDM_CommandX;\r
+ if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&\r
+ icsTextMenuEntry[i].command != NULL) {\r
+ CommandX(hwnd, icsTextMenuEntry[i].command,\r
+ icsTextMenuEntry[i].getname,\r
+ icsTextMenuEntry[i].immediate);\r
+ return 0;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);\r
+}\r
+\r
+WNDPROC consoleInputWindowProc;\r
+\r
+LRESULT CALLBACK\r
+ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ char buf[MSG_SIZ];\r
+ char *p;\r
+ static BOOL sendNextChar = FALSE;\r
+ static BOOL quoteNextChar = FALSE;\r
+ InputSource *is = consoleInputSource;\r
+ CHARFORMAT cf;\r
+ CHARRANGE sel;\r
+\r
+ switch (message) {\r
+ case WM_CHAR:\r
+ if (!appData.localLineEditing || sendNextChar) {\r
+ is->buf[0] = (CHAR) wParam;\r
+ is->count = 1;\r
+ SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
+ sendNextChar = FALSE;\r
+ return 0;\r
+ }\r
+ if (quoteNextChar) {\r
+ buf[0] = (char) wParam;\r
+ buf[1] = NULLCHAR;\r
+ SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);\r
+ quoteNextChar = FALSE;\r
+ return 0;\r
+ }\r
+ switch (wParam) {\r
+ case '\r': /* Enter key */\r
+ is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1); \r
+ if (consoleEcho) SaveInHistory(is->buf);\r
+ is->buf[is->count++] = '\n';\r
+ is->buf[is->count] = NULLCHAR;\r
+ SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
+ if (consoleEcho) {\r
+ ConsoleOutput(is->buf, is->count, TRUE);\r
+ } else if (appData.localLineEditing) {\r
+ ConsoleOutput("\n", 1, TRUE);\r
+ }\r
+ /* fall thru */\r
+ case '\033': /* Escape key */\r
+ SetWindowText(hwnd, "");\r
+ cf.cbSize = sizeof(CHARFORMAT);\r
+ cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;\r
+ if (consoleEcho) {\r
+ cf.crTextColor = textAttribs[ColorNormal].color;\r
+ } else {\r
+ cf.crTextColor = COLOR_ECHOOFF;\r
+ }\r
+ cf.dwEffects = textAttribs[ColorNormal].effects;\r
+ SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);\r
+ return 0;\r
+ case '\t': /* Tab key */\r
+ if (GetKeyState(VK_SHIFT) < 0) {\r
+ /* shifted */\r
+ SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));\r
+ } else {\r
+ /* unshifted */\r
+ if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);\r
+ if (buttonDesc[0].hwnd) {\r
+ SetFocus(buttonDesc[0].hwnd);\r
+ } else {\r
+ SetFocus(hwndMain);\r
+ }\r
+ }\r
+ return 0;\r
+ case '\023': /* Ctrl+S */\r
+ sendNextChar = TRUE;\r
+ return 0;\r
+ case '\021': /* Ctrl+Q */\r
+ quoteNextChar = TRUE;\r
+ return 0;\r
+ JAWS_REPLAY\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+ case WM_KEYDOWN:\r
+ switch (wParam) {\r
+ case VK_UP:\r
+ GetWindowText(hwnd, buf, MSG_SIZ);\r
+ p = PrevInHistory(buf);\r
+ if (p != NULL) {\r
+ SetWindowText(hwnd, p);\r
+ sel.cpMin = 999999;\r
+ sel.cpMax = 999999;\r
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ return 0;\r
+ }\r
+ break;\r
+ case VK_DOWN:\r
+ p = NextInHistory();\r
+ if (p != NULL) {\r
+ SetWindowText(hwnd, p);\r
+ sel.cpMin = 999999;\r
+ sel.cpMax = 999999;\r
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ return 0;\r
+ }\r
+ break;\r
+ case VK_HOME:\r
+ case VK_END:\r
+ if (!(GetKeyState(VK_CONTROL) & ~1)) break;\r
+ /* fall thru */\r
+ case VK_PRIOR:\r
+ case VK_NEXT:\r
+ SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);\r
+ return 0;\r
+ }\r
+ break;\r
+ case WM_MBUTTONDOWN:\r
+ SendDlgItemMessage(hwndConsole, OPT_ConsoleText, \r
+ WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
+ break;\r
+ case WM_RBUTTONUP:\r
+ if (GetKeyState(VK_SHIFT) & ~1) {\r
+ SendDlgItemMessage(hwndConsole, OPT_ConsoleText, \r
+ WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
+ } else {\r
+ POINT pt;\r
+ HMENU hmenu;\r
+ hmenu = LoadMenu(hInst, "InputMenu");\r
+ SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
+ if (sel.cpMin == sel.cpMax) {\r
+ EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);\r
+ EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);\r
+ }\r
+ if (!IsClipboardFormatAvailable(CF_TEXT)) {\r
+ EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);\r
+ }\r
+ pt.x = LOWORD(lParam);\r
+ pt.y = HIWORD(lParam);\r
+ MenuPopup(hwnd, pt, hmenu, -1);\r
+ }\r
+ return 0;\r
+ case WM_COMMAND:\r
+ switch (LOWORD(wParam)) { \r
+ case IDM_Undo:\r
+ SendMessage(hwnd, EM_UNDO, 0, 0);\r
+ return 0;\r
+ case IDM_SelectAll:\r
+ sel.cpMin = 0;\r
+ sel.cpMax = -1; /*999999?*/\r
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ return 0;\r
+ case IDM_Cut:\r
+ SendMessage(hwnd, WM_CUT, 0, 0);\r
+ return 0;\r
+ case IDM_Paste:\r
+ SendMessage(hwnd, WM_PASTE, 0, 0);\r
+ return 0;\r
+ case IDM_Copy:\r
+ SendMessage(hwnd, WM_COPY, 0, 0);\r
+ return 0;\r
+ }\r
+ break;\r
+ }\r
+ return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);\r
+}\r
+\r
+#define CO_MAX 100000\r
+#define CO_TRIM 1000\r
+\r
+LRESULT CALLBACK\r
+ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ static SnapData sd;\r
+ HWND hText, hInput;\r
+ RECT rect;\r
+ static int sizeX, sizeY;\r
+ int newSizeX, newSizeY;\r
+ MINMAXINFO *mmi;\r
+ WORD wMask;\r
+\r
+ hText = GetDlgItem(hDlg, OPT_ConsoleText);\r
+ hInput = GetDlgItem(hDlg, OPT_ConsoleInput);\r
+\r
+ switch (message) {\r
+ case WM_NOTIFY:\r
+ if (((NMHDR*)lParam)->code == EN_LINK)\r
+ {\r
+ ENLINK *pLink = (ENLINK*)lParam;\r
+ if (pLink->msg == WM_LBUTTONUP)\r
+ {\r
+ TEXTRANGE tr;\r
+\r
+ tr.chrg = pLink->chrg;\r
+ tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);\r
+ SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);\r
+ ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);\r
+ free(tr.lpstrText);\r
+ }\r
+ }\r
+ break;\r
+ case WM_INITDIALOG: /* message: initialize dialog box */\r
+ hwndConsole = hDlg;\r
+ SetFocus(hInput);\r
+ consoleTextWindowProc = (WNDPROC)\r
+ SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);\r
+ SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);\r
+ consoleInputWindowProc = (WNDPROC)\r
+ SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);\r
+ SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);\r
+ Colorize(ColorNormal, TRUE);\r
+ SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);\r
+ ChangedConsoleFont();\r
+ GetClientRect(hDlg, &rect);\r
+ sizeX = rect.right;\r
+ sizeY = rect.bottom;\r
+ if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&\r
+ wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {\r
+ WINDOWPLACEMENT wp;\r
+ EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);\r
+ wp.length = sizeof(WINDOWPLACEMENT);\r
+ wp.flags = 0;\r
+ wp.showCmd = SW_SHOW;\r
+ wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
+ wp.rcNormalPosition.left = wpConsole.x;\r
+ wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;\r
+ wp.rcNormalPosition.top = wpConsole.y;\r
+ wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;\r
+ SetWindowPlacement(hDlg, &wp);\r
+ }\r
+\r
+ // [HGM] Chessknight's change 2004-07-13\r
+ else { /* Determine Defaults */\r
+ WINDOWPLACEMENT wp;\r
+ wpConsole.x = winWidth + 1;\r
+ wpConsole.y = boardY;\r
+ wpConsole.width = screenWidth - winWidth;\r
+ wpConsole.height = winHeight;\r
+ EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);\r
+ wp.length = sizeof(WINDOWPLACEMENT);\r
+ wp.flags = 0;\r
+ wp.showCmd = SW_SHOW;\r
+ wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
+ wp.rcNormalPosition.left = wpConsole.x;\r
+ wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;\r
+ wp.rcNormalPosition.top = wpConsole.y;\r
+ wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;\r
+ SetWindowPlacement(hDlg, &wp);\r
+ }\r
+\r
+ // Allow hText to highlight URLs and send notifications on them\r
+ wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);\r
+ SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);\r
+ SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);\r
+ SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width\r
+\r
+ return FALSE;\r
+\r
+ case WM_SETFOCUS:\r
+ SetFocus(hInput);\r
+ return 0;\r
+\r
+ case WM_CLOSE:\r
+ ExitEvent(0);\r
+ /* not reached */\r
+ break;\r
+\r
+ case WM_SIZE:\r
+ if (IsIconic(hDlg)) break;\r
+ newSizeX = LOWORD(lParam);\r
+ newSizeY = HIWORD(lParam);\r
+ if (sizeX != newSizeX || sizeY != newSizeY) {\r
+ RECT rectText, rectInput;\r
+ POINT pt;\r
+ int newTextHeight, newTextWidth;\r
+ GetWindowRect(hText, &rectText);\r
+ newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;\r
+ newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;\r
+ if (newTextHeight < 0) {\r
+ newSizeY += -newTextHeight;\r
+ newTextHeight = 0;\r
+ }\r
+ SetWindowPos(hText, NULL, 0, 0,\r
+ newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);\r
+ GetWindowRect(hInput, &rectInput); /* gives screen coords */\r
+ pt.x = rectInput.left;\r
+ pt.y = rectInput.top + newSizeY - sizeY;\r
+ ScreenToClient(hDlg, &pt);\r
+ SetWindowPos(hInput, NULL, \r
+ pt.x, pt.y, /* needs client coords */ \r
+ rectInput.right - rectInput.left + newSizeX - sizeX,\r
+ rectInput.bottom - rectInput.top, SWP_NOZORDER);\r
+ }\r
+ sizeX = newSizeX;\r
+ sizeY = newSizeY;\r
+ break;\r
+\r
+ case WM_GETMINMAXINFO:\r
+ /* Prevent resizing window too small */\r
+ mmi = (MINMAXINFO *) lParam;\r
+ mmi->ptMinTrackSize.x = 100;\r
+ mmi->ptMinTrackSize.y = 100;\r
+ break;\r
+\r
+ /* [AS] Snapping */\r
+ case WM_ENTERSIZEMOVE:\r
+ return OnEnterSizeMove( &sd, hDlg, wParam, lParam );\r
+\r
+ case WM_SIZING:\r
+ return OnSizing( &sd, hDlg, wParam, lParam );\r
+\r
+ case WM_MOVING:\r
+ return OnMoving( &sd, hDlg, wParam, lParam );\r
+\r
+ case WM_EXITSIZEMOVE:\r
+ UpdateICSWidth(hText);\r
+ return OnExitSizeMove( &sd, hDlg, wParam, lParam );\r
+ }\r
+\r
+ return DefWindowProc(hDlg, message, wParam, lParam);\r
+}\r
+\r
+\r
+VOID\r
+ConsoleCreate()\r
+{\r
+ HWND hCons;\r
+ if (hwndConsole) return;\r
+ hCons = CreateDialog(hInst, szConsoleName, 0, NULL);\r
+ SendMessage(hCons, WM_INITDIALOG, 0, 0);\r
+}\r
+\r
+\r
+VOID\r
+ConsoleOutput(char* data, int length, int forceVisible)\r
+{\r
+ HWND hText;\r
+ int trim, exlen;\r
+ char *p, *q;\r
+ char buf[CO_MAX+1];\r
+ POINT pEnd;\r
+ RECT rect;\r
+ static int delayLF = 0;\r
+ CHARRANGE savesel, sel;\r
+\r
+ if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;\r
+ p = data;\r
+ q = buf;\r
+ if (delayLF) {\r
+ *q++ = '\r';\r
+ *q++ = '\n';\r
+ delayLF = 0;\r
+ }\r
+ while (length--) {\r
+ if (*p == '\n') {\r
+ if (*++p) {\r
+ *q++ = '\r';\r
+ *q++ = '\n';\r
+ } else {\r
+ delayLF = 1;\r
+ }\r
+ } else if (*p == '\007') {\r
+ MyPlaySound(&sounds[(int)SoundBell]);\r
+ p++;\r
+ } else {\r
+ *q++ = *p++;\r
+ }\r
+ }\r
+ *q = NULLCHAR;\r
+ hText = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
+ SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);\r
+ /* Save current selection */\r
+ SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);\r
+ exlen = GetWindowTextLength(hText);\r
+ /* Find out whether current end of text is visible */\r
+ SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);\r
+ SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);\r
+ /* Trim existing text if it's too long */\r
+ if (exlen + (q - buf) > CO_MAX) {\r
+ trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);\r
+ sel.cpMin = 0;\r
+ sel.cpMax = trim;\r
+ SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");\r
+ exlen -= trim;\r
+ savesel.cpMin -= trim;\r
+ savesel.cpMax -= trim;\r
+ if (exlen < 0) exlen = 0;\r
+ if (savesel.cpMin < 0) savesel.cpMin = 0;\r
+ if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;\r
+ }\r
+ /* Append the new text */\r
+ sel.cpMin = exlen;\r
+ sel.cpMax = exlen;\r
+ SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);\r
+ SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);\r
+ if (forceVisible || exlen == 0 ||\r
+ (rect.left <= pEnd.x && pEnd.x < rect.right &&\r
+ rect.top <= pEnd.y && pEnd.y < rect.bottom)) {\r
+ /* Scroll to make new end of text visible if old end of text\r
+ was visible or new text is an echo of user typein */\r
+ sel.cpMin = 9999999;\r
+ sel.cpMax = 9999999;\r
+ SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);\r
+ SendMessage(hText, EM_SCROLLCARET, 0, 0);\r
+ SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);\r
+ }\r
+ if (savesel.cpMax == exlen || forceVisible) {\r
+ /* Move insert point to new end of text if it was at the old\r
+ end of text or if the new text is an echo of user typein */\r
+ sel.cpMin = 9999999;\r
+ sel.cpMax = 9999999;\r
+ SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ } else {\r
+ /* Restore previous selection */\r
+ SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);\r
+ }\r
+ SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);\r
+}\r
+\r
+/*---------*/\r
+\r
+\r
+void\r
+DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)\r
+{\r
+ char buf[100];\r
+ char *str;\r
+ COLORREF oldFg, oldBg;\r
+ HFONT oldFont;\r
+ RECT rect;\r
+\r
+ if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;\r
+\r
+ oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */\r
+ oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */\r
+ oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
+\r
+ rect.left = x;\r
+ rect.right = x + squareSize;\r
+ rect.top = y;\r
+ rect.bottom = y + squareSize;\r
+ str = buf;\r
+\r
+ ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN\r
+ + (rightAlign ? (squareSize*2)/3 : 0),\r
+ y, ETO_CLIPPED|ETO_OPAQUE,\r
+ &rect, str, strlen(str), NULL);\r
+\r
+ (void) SetTextColor(hdc, oldFg);\r
+ (void) SetBkColor(hdc, oldBg);\r
+ (void) SelectObject(hdc, oldFont);\r
+}\r
+\r
+void\r
+DisplayAClock(HDC hdc, int timeRemaining, int highlight,\r
+ RECT *rect, char *color, char *flagFell)\r
+{\r
+ char buf[100];\r
+ char *str;\r
+ COLORREF oldFg, oldBg;\r
+ HFONT oldFont;\r
+\r
+ if (appData.clockMode) {\r
+ if (tinyLayout)\r
+ sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);\r
+ else\r
+ sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);\r
+ str = buf;\r
+ } else {\r
+ str = color;\r
+ }\r
+\r
+ if (highlight) {\r
+ oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */\r
+ oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */\r
+ } else {\r
+ oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */\r
+ oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */\r
+ }\r
+ oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
+\r
+ JAWS_SILENCE\r
+\r
+ ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,\r
+ rect->top, ETO_CLIPPED|ETO_OPAQUE,\r
+ rect, str, strlen(str), NULL);\r
+ if(logoHeight > 0 && appData.clockMode) {\r
+ RECT r;\r
+ sprintf(buf, "%s %s", buf+7, flagFell);\r
+ r.top = rect->top + logoHeight/2;\r
+ r.left = rect->left;\r
+ r.right = rect->right;\r
+ r.bottom = rect->bottom;\r
+ ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,\r
+ r.top, ETO_CLIPPED|ETO_OPAQUE,\r
+ &r, str, strlen(str), NULL);\r
+ }\r
+ (void) SetTextColor(hdc, oldFg);\r
+ (void) SetBkColor(hdc, oldBg);\r
+ (void) SelectObject(hdc, oldFont);\r
+}\r
+\r
+\r
+int\r
+DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,\r
+ OVERLAPPED *ovl)\r
+{\r
+ int ok, err;\r
+\r
+ /* [AS] */\r
+ if( count <= 0 ) {\r
+ if (appData.debugMode) {\r
+ fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );\r
+ }\r
+\r
+ return ERROR_INVALID_USER_BUFFER;\r
+ }\r
+\r
+ ResetEvent(ovl->hEvent);\r
+ ovl->Offset = ovl->OffsetHigh = 0;\r
+ ok = ReadFile(hFile, buf, count, outCount, ovl);\r
+ if (ok) {\r
+ err = NO_ERROR;\r
+ } else {\r
+ err = GetLastError();\r
+ if (err == ERROR_IO_PENDING) {\r
+ ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);\r
+ if (ok)\r
+ err = NO_ERROR;\r
+ else\r
+ err = GetLastError();\r
+ }\r
+ }\r
+ return err;\r
+}\r
+\r
+int\r
+DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,\r
+ OVERLAPPED *ovl)\r
+{\r
+ int ok, err;\r
+\r
+ ResetEvent(ovl->hEvent);\r
+ ovl->Offset = ovl->OffsetHigh = 0;\r
+ ok = WriteFile(hFile, buf, count, outCount, ovl);\r
+ if (ok) {\r
+ err = NO_ERROR;\r
+ } else {\r
+ err = GetLastError();\r
+ if (err == ERROR_IO_PENDING) {\r
+ ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);\r
+ if (ok)\r
+ err = NO_ERROR;\r
+ else\r
+ err = GetLastError();\r
+ }\r
+ }\r
+ return err;\r
+}\r
+\r
+/* [AS] If input is line by line and a line exceed the buffer size, force an error */\r
+void CheckForInputBufferFull( InputSource * is )\r
+{\r
+ if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {\r
+ /* Look for end of line */\r
+ char * p = is->buf;\r
+ \r
+ while( p < is->next && *p != '\n' ) {\r
+ p++;\r
+ }\r
+\r
+ if( p >= is->next ) {\r
+ if (appData.debugMode) {\r
+ fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );\r
+ }\r
+\r
+ is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */\r
+ is->count = (DWORD) -1;\r
+ is->next = is->buf;\r
+ }\r
+ }\r
+}\r
+\r
+DWORD\r
+InputThread(LPVOID arg)\r
+{\r
+ InputSource *is;\r
+ OVERLAPPED ovl;\r
+\r
+ is = (InputSource *) arg;\r
+ ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
+ ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;\r
+ while (is->hThread != NULL) {\r
+ is->error = DoReadFile(is->hFile, is->next,\r
+ INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),\r
+ &is->count, &ovl);\r
+ if (is->error == NO_ERROR) {\r
+ is->next += is->count;\r
+ } else {\r
+ if (is->error == ERROR_BROKEN_PIPE) {\r
+ /* Correct for MS brain damage. EOF reading a pipe is not an error. */\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! */\r
+ break; \r
+ }\r
+ }\r
+\r
+ CheckForInputBufferFull( is );\r
+\r
+ SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
+\r
+ if( is->count == ((DWORD) -1) ) break; /* [AS] */\r
+\r
+ if (is->count <= 0) break; /* Quit on EOF or error */\r
+ }\r
+\r
+ CloseHandle(ovl.hEvent);\r
+ CloseHandle(is->hFile);\r
+\r
+ if (appData.debugMode) {\r
+ fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */\r
+DWORD\r
+NonOvlInputThread(LPVOID arg)\r
+{\r
+ InputSource *is;\r
+ char *p, *q;\r
+ int i;\r
+ char prev;\r
+\r
+ is = (InputSource *) arg;\r
+ while (is->hThread != NULL) {\r
+ is->error = ReadFile(is->hFile, is->next,\r
+ INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),\r
+ &is->count, NULL) ? NO_ERROR : GetLastError();\r
+ if (is->error == NO_ERROR) {\r
+ /* Change CRLF to LF */\r
+ if (is->next > is->buf) {\r
+ p = is->next - 1;\r
+ i = is->count + 1;\r
+ } else {\r
+ p = is->next;\r
+ i = is->count;\r
+ }\r
+ q = p;\r
+ prev = NULLCHAR;\r
+ while (i > 0) {\r
+ if (prev == '\r' && *p == '\n') {\r
+ *(q-1) = '\n';\r
+ is->count--;\r
+ } else { \r
+ *q++ = *p;\r
+ }\r
+ prev = *p++;\r
+ i--;\r
+ }\r
+ *q = NULLCHAR;\r
+ is->next = q;\r
+ } else {\r
+ if (is->error == ERROR_BROKEN_PIPE) {\r
+ /* Correct for MS brain damage. EOF reading a pipe is not an error. */\r
+ is->count = 0; \r
+ } else {\r
+ is->count = (DWORD) -1;\r
+ }\r
+ }\r
+\r
+ CheckForInputBufferFull( is );\r
+\r
+ SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
+\r
+ if( is->count == ((DWORD) -1) ) break; /* [AS] */\r
+\r
+ if (is->count < 0) break; /* Quit on error */\r
+ }\r
+ CloseHandle(is->hFile);\r
+ return 0;\r
+}\r
+\r
+DWORD\r
+SocketInputThread(LPVOID arg)\r
+{\r
+ InputSource *is;\r
+\r
+ is = (InputSource *) arg;\r
+ while (is->hThread != NULL) {\r
+ is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);\r
+ if ((int)is->count == SOCKET_ERROR) {\r
+ is->count = (DWORD) -1;\r
+ is->error = WSAGetLastError();\r
+ } else {\r
+ is->error = NO_ERROR;\r
+ is->next += is->count;\r
+ if (is->count == 0 && is->second == is) {\r
+ /* End of file on stderr; quit with no message */\r
+ break;\r
+ }\r
+ }\r
+ SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
+\r
+ if( is->count == ((DWORD) -1) ) break; /* [AS] */\r
+\r
+ if (is->count <= 0) break; /* Quit on EOF or error */\r
+ }\r
+ return 0;\r
+}\r
+\r
+VOID\r
+InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ InputSource *is;\r
+\r
+ is = (InputSource *) lParam;\r
+ if (is->lineByLine) {\r
+ /* Feed in lines one by one */\r
+ char *p = is->buf;\r
+ char *q = p;\r
+ while (q < is->next) {\r
+ if (*q++ == '\n') {\r
+ (is->func)(is, is->closure, p, q - p, NO_ERROR);\r
+ p = q;\r
+ }\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
+\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
+ (is->func)(is, is->closure, is->buf, is->count, is->error); \r
+ }\r
+ } else {\r
+ /* Feed in the whole chunk of input at once */\r
+ (is->func)(is, is->closure, is->buf, is->count, is->error);\r
+ is->next = is->buf;\r
+ }\r
+}\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * Menu enables. Used when setting various modes.\r
+ *\r
+\*---------------------------------------------------------------------------*/\r
+\r
+typedef struct {\r
+ int item;\r
+ int flags;\r
+} Enables;\r
+\r
+VOID\r
+SetMenuEnables(HMENU hmenu, Enables *enab)\r
+{\r
+ while (enab->item > 0) {\r
+ (void) EnableMenuItem(hmenu, enab->item, enab->flags);\r
+ enab++;\r
+ }\r
+}\r
+\r
+Enables gnuEnables[] = {\r
+ { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },\r
+ { -1, -1 }\r
+};\r
+\r
+Enables icsEnables[] = {\r
+ { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Book, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },\r
+ { -1, -1 }\r
+};\r
+\r
+#ifdef ZIPPY\r
+Enables zippyEnables[] = {\r
+ { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_Book, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },\r
+ { -1, -1 }\r
+};\r
+#endif\r
+\r
+Enables ncpEnables[] = {\r
+ { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },\r
+ { ACTION_POS, MF_BYPOSITION|MF_GRAYED },\r
+ { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Book, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },\r
+ { -1, -1 }\r
+};\r
+\r
+Enables trainingOnEnables[] = {\r
+ { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },\r
+ { -1, -1 }\r
+};\r
+\r
+Enables trainingOffEnables[] = {\r
+ { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },\r
+ { -1, -1 }\r
+};\r
+\r
+/* These modify either ncpEnables or gnuEnables */\r
+Enables cmailEnables[] = {\r
+ { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },\r
+ { ACTION_POS, MF_BYPOSITION|MF_ENABLED },\r
+ { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },\r
+ { -1, -1 }\r
+};\r
+\r
+Enables machineThinkingEnables[] = {\r
+ { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },\r
+ { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },\r
+ { -1, -1 }\r
+};\r
+\r
+Enables userThinkingEnables[] = {\r
+ { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },\r
+ { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },\r
+ { -1, -1 }\r
+};\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * Front-end interface functions exported by XBoard.\r
+ * Functions appear in same order as prototypes in frontend.h.\r
+ * \r
+\*---------------------------------------------------------------------------*/\r
+VOID\r
+ModeHighlight()\r
+{\r
+ static UINT prevChecked = 0;\r
+ static int prevPausing = 0;\r
+ UINT nowChecked;\r
+\r
+ if (pausing != prevPausing) {\r
+ prevPausing = pausing;\r
+ (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,\r
+ MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));\r
+ if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");\r
+ }\r
+\r
+ switch (gameMode) {\r
+ case BeginningOfGame:\r
+ if (appData.icsActive)\r
+ nowChecked = IDM_IcsClient;\r
+ else if (appData.noChessProgram)\r
+ nowChecked = IDM_EditGame;\r
+ else\r
+ nowChecked = IDM_MachineBlack;\r
+ break;\r
+ case MachinePlaysBlack:\r
+ nowChecked = IDM_MachineBlack;\r
+ break;\r
+ case MachinePlaysWhite:\r
+ nowChecked = IDM_MachineWhite;\r
+ break;\r
+ case TwoMachinesPlay:\r
+ nowChecked = IDM_TwoMachines;\r
+ break;\r
+ case AnalyzeMode:\r
+ nowChecked = IDM_AnalysisMode;\r
+ break;\r
+ case AnalyzeFile:\r
+ nowChecked = IDM_AnalyzeFile;\r
+ break;\r
+ case EditGame:\r
+ nowChecked = IDM_EditGame;\r
+ break;\r
+ case PlayFromGameFile:\r
+ nowChecked = IDM_LoadGame;\r
+ break;\r
+ case EditPosition:\r
+ nowChecked = IDM_EditPosition;\r
+ break;\r
+ case Training:\r
+ nowChecked = IDM_Training;\r
+ break;\r
+ case IcsPlayingWhite:\r
+ case IcsPlayingBlack:\r
+ case IcsObserving:\r
+ case IcsIdle:\r
+ nowChecked = IDM_IcsClient;\r
+ break;\r
+ default:\r
+ case EndOfGame:\r
+ nowChecked = 0;\r
+ break;\r
+ }\r
+ if (prevChecked != 0)\r
+ (void) CheckMenuItem(GetMenu(hwndMain),\r
+ prevChecked, MF_BYCOMMAND|MF_UNCHECKED);\r
+ if (nowChecked != 0)\r
+ (void) CheckMenuItem(GetMenu(hwndMain),\r
+ nowChecked, MF_BYCOMMAND|MF_CHECKED);\r
+\r
+ if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {\r
+ (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training, \r
+ MF_BYCOMMAND|MF_ENABLED);\r
+ } else {\r
+ (void) EnableMenuItem(GetMenu(hwndMain), \r
+ IDM_Training, MF_BYCOMMAND|MF_GRAYED);\r
+ }\r
+\r
+ prevChecked = nowChecked;\r
+\r
+ /* [DM] icsEngineAnalyze - Do a sceure check too */\r
+ if (appData.icsActive) {\r
+ if (appData.icsEngineAnalyze) {\r
+ (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,\r
+ MF_BYCOMMAND|MF_CHECKED);\r
+ } else {\r
+ (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,\r
+ MF_BYCOMMAND|MF_UNCHECKED);\r
+ }\r
+ }\r
+}\r
+\r
+VOID\r
+SetICSMode()\r
+{\r
+ HMENU hmenu = GetMenu(hwndMain);\r
+ SetMenuEnables(hmenu, icsEnables);\r
+ EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,\r
+ MF_BYPOSITION|MF_ENABLED);\r
+#ifdef ZIPPY\r
+ if (appData.zippyPlay) {\r
+ SetMenuEnables(hmenu, zippyEnables);\r
+ if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */\r
+ (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,\r
+ MF_BYCOMMAND|MF_ENABLED);\r
+ }\r
+#endif\r
+}\r
+\r
+VOID\r
+SetGNUMode()\r
+{\r
+ SetMenuEnables(GetMenu(hwndMain), gnuEnables);\r
+}\r
+\r
+VOID\r
+SetNCPMode()\r
+{\r
+ HMENU hmenu = GetMenu(hwndMain);\r
+ SetMenuEnables(hmenu, ncpEnables);\r
+ EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,\r
+ MF_BYPOSITION|MF_GRAYED);\r
+ DrawMenuBar(hwndMain);\r
+}\r
+\r
+VOID\r
+SetCmailMode()\r
+{\r
+ SetMenuEnables(GetMenu(hwndMain), cmailEnables);\r
+}\r
+\r
+VOID \r
+SetTrainingModeOn()\r
+{\r
+ int i;\r
+ SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);\r
+ for (i = 0; i < N_BUTTONS; i++) {\r
+ if (buttonDesc[i].hwnd != NULL)\r
+ EnableWindow(buttonDesc[i].hwnd, FALSE);\r
+ }\r
+ CommentPopDown();\r
+}\r
+\r
+VOID SetTrainingModeOff()\r
+{\r
+ int i;\r
+ SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);\r
+ for (i = 0; i < N_BUTTONS; i++) {\r
+ if (buttonDesc[i].hwnd != NULL)\r
+ EnableWindow(buttonDesc[i].hwnd, TRUE);\r
+ }\r
+}\r
+\r
+\r
+VOID\r
+SetUserThinkingEnables()\r
+{\r
+ SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);\r
+}\r
+\r
+VOID\r
+SetMachineThinkingEnables()\r
+{\r
+ HMENU hMenu = GetMenu(hwndMain);\r
+ int flags = MF_BYCOMMAND|MF_ENABLED;\r
+\r
+ SetMenuEnables(hMenu, machineThinkingEnables);\r
+\r
+ if (gameMode == MachinePlaysBlack) {\r
+ (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);\r
+ } else if (gameMode == MachinePlaysWhite) {\r
+ (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);\r
+ } else if (gameMode == TwoMachinesPlay) {\r
+ (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);\r
+ }\r
+}\r
+\r
+\r
+VOID\r
+DisplayTitle(char *str)\r
+{\r
+ char title[MSG_SIZ], *host;\r
+ if (str[0] != NULLCHAR) {\r
+ strcpy(title, str);\r
+ } else if (appData.icsActive) {\r
+ if (appData.icsCommPort[0] != NULLCHAR)\r
+ host = "ICS";\r
+ else \r
+ host = appData.icsHost;\r
+ sprintf(title, "%s: %s", szTitle, host);\r
+ } else if (appData.noChessProgram) {\r
+ strcpy(title, szTitle);\r
+ } else {\r
+ strcpy(title, szTitle);\r
+ strcat(title, ": ");\r
+ strcat(title, first.tidy);\r
+ }\r
+ SetWindowText(hwndMain, title);\r
+}\r
+\r
+\r
+VOID\r
+DisplayMessage(char *str1, char *str2)\r
+{\r
+ HDC hdc;\r
+ HFONT oldFont;\r
+ int remain = MESSAGE_TEXT_MAX - 1;\r
+ int len;\r
+\r
+ moveErrorMessageUp = FALSE; /* turned on later by caller if needed */\r
+ messageText[0] = NULLCHAR;\r
+ if (*str1) {\r
+ len = strlen(str1);\r
+ if (len > remain) len = remain;\r
+ strncpy(messageText, str1, len);\r
+ messageText[len] = NULLCHAR;\r
+ remain -= len;\r
+ }\r
+ if (*str2 && remain >= 2) {\r
+ if (*str1) {\r
+ strcat(messageText, " ");\r
+ remain -= 2;\r
+ }\r
+ len = strlen(str2);\r
+ if (len > remain) len = remain;\r
+ strncat(messageText, str2, len);\r
+ }\r
+ messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;\r
+\r
+ if (hwndMain == NULL || IsIconic(hwndMain)) return;\r
+\r
+ SAYMACHINEMOVE();\r
+\r
+ hdc = GetDC(hwndMain);\r
+ oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
+ ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,\r
+ &messageRect, messageText, strlen(messageText), NULL);\r
+ (void) SelectObject(hdc, oldFont);\r
+ (void) ReleaseDC(hwndMain, hdc);\r
+}\r
+\r
+VOID\r
+DisplayError(char *str, int error)\r
+{\r
+ char buf[MSG_SIZ*2], buf2[MSG_SIZ];\r
+ int len;\r
+\r
+ if (error == 0) {\r
+ strcpy(buf, str);\r
+ } else {\r
+ len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,\r
+ NULL, error, LANG_NEUTRAL,\r
+ (LPSTR) buf2, MSG_SIZ, NULL);\r
+ if (len > 0) {\r
+ sprintf(buf, "%s:\n%s", str, buf2);\r
+ } else {\r
+ ErrorMap *em = errmap;\r
+ while (em->err != 0 && em->err != error) em++;\r
+ if (em->err != 0) {\r
+ sprintf(buf, "%s:\n%s", str, em->msg);\r
+ } else {\r
+ sprintf(buf, "%s:\nError code %d", str, error);\r
+ }\r
+ }\r
+ }\r
+ \r
+ ErrorPopUp("Error", buf);\r
+}\r
+\r
+\r
+VOID\r
+DisplayMoveError(char *str)\r
+{\r
+ fromX = fromY = -1;\r
+ ClearHighlights();\r
+ DrawPosition(FALSE, NULL);\r
+ if (appData.popupMoveErrors) {\r
+ ErrorPopUp("Error", str);\r
+ } else {\r
+ DisplayMessage(str, "");\r
+ moveErrorMessageUp = TRUE;\r
+ }\r
+}\r
+\r
+VOID\r
+DisplayFatalError(char *str, int error, int exitStatus)\r
+{\r
+ char buf[2*MSG_SIZ], buf2[MSG_SIZ];\r
+ int len;\r
+ char *label = exitStatus ? "Fatal Error" : "Exiting";\r
+\r
+ if (error != 0) {\r
+ len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,\r
+ NULL, error, LANG_NEUTRAL,\r
+ (LPSTR) buf2, MSG_SIZ, NULL);\r
+ if (len > 0) {\r
+ sprintf(buf, "%s:\n%s", str, buf2);\r
+ } else {\r
+ ErrorMap *em = errmap;\r
+ while (em->err != 0 && em->err != error) em++;\r
+ if (em->err != 0) {\r
+ sprintf(buf, "%s:\n%s", str, em->msg);\r
+ } else {\r
+ sprintf(buf, "%s:\nError code %d", str, error);\r
+ }\r
+ }\r
+ str = buf;\r
+ }\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "%s: %s\n", label, str);\r
+ }\r
+ if (appData.popupExitMessage) {\r
+ (void) MessageBox(hwndMain, str, label, MB_OK|\r
+ (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));\r
+ }\r
+ ExitEvent(exitStatus);\r
+}\r
+\r
+\r
+VOID\r
+DisplayInformation(char *str)\r
+{\r
+ (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);\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
+} QuestionParams;\r
+\r
+LRESULT CALLBACK\r
+QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ static QuestionParams *qp;\r
+ char reply[MSG_SIZ];\r
+ int len, err;\r
+\r
+ switch (message) {\r
+ case WM_INITDIALOG:\r
+ qp = (QuestionParams *) lParam;\r
+ CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+ SetWindowText(hDlg, qp->title);\r
+ SetDlgItemText(hDlg, OPT_QuestionText, qp->question);\r
+ SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));\r
+ return FALSE;\r
+\r
+ case WM_COMMAND:\r
+ switch (LOWORD(wParam)) {\r
+ case IDOK:\r
+ strcpy(reply, qp->replyPrefix);\r
+ if (*reply) strcat(reply, " ");\r
+ len = strlen(reply);\r
+ GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);\r
+ strcat(reply, "\n");\r
+ OutputToProcess(qp->pr, reply, strlen(reply), &err);\r
+ EndDialog(hDlg, TRUE);\r
+ if (err) DisplayFatalError("Error writing to chess program", err, 1);\r
+ return TRUE;\r
+ case IDCANCEL:\r
+ EndDialog(hDlg, FALSE);\r
+ return TRUE;\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+VOID\r
+AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)\r
+{\r
+ QuestionParams qp;\r
+ FARPROC lpProc;\r
+ \r
+ qp.title = title;\r
+ qp.question = question;\r
+ qp.replyPrefix = replyPrefix;\r
+ qp.pr = pr;\r
+ lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);\r
+ DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),\r
+ hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);\r
+ FreeProcInstance(lpProc);\r
+}\r
+\r
+/* [AS] Pick FRC position */\r
+LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ static int * lpIndexFRC;\r
+ BOOL index_is_ok;\r
+ char buf[16];\r
+\r
+ switch( message )\r
+ {\r
+ case WM_INITDIALOG:\r
+ lpIndexFRC = (int *) lParam;\r
+\r
+ CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+\r
+ SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );\r
+ SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );\r
+ SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );\r
+ SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));\r
+\r
+ break;\r
+\r
+ case WM_COMMAND:\r
+ switch( LOWORD(wParam) ) {\r
+ case IDOK:\r
+ *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );\r
+ EndDialog( hDlg, 0 );\r
+ shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */\r
+ return TRUE;\r
+ case IDCANCEL:\r
+ EndDialog( hDlg, 1 ); \r
+ return TRUE;\r
+ case IDC_NFG_Edit:\r
+ if( HIWORD(wParam) == EN_CHANGE ) {\r
+ GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );\r
+\r
+ EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );\r
+ }\r
+ return TRUE;\r
+ case IDC_NFG_Random:\r
+ sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */\r
+ SetDlgItemText(hDlg, IDC_NFG_Edit, buf );\r
+ return TRUE;\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+int NewGameFRC()\r
+{\r
+ int result;\r
+ int index = appData.defaultFrcPosition;\r
+ FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );\r
+\r
+ result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );\r
+\r
+ if( result == 0 ) {\r
+ appData.defaultFrcPosition = index;\r
+ }\r
+\r
+ return result;\r
+}\r
+\r
+/* [AS] Game list options */\r
+typedef struct {\r
+ char id;\r
+ char * name;\r
+} GLT_Item;\r
+\r
+static GLT_Item GLT_ItemInfo[] = {\r
+ { GLT_EVENT, "Event" },\r
+ { GLT_SITE, "Site" },\r
+ { GLT_DATE, "Date" },\r
+ { GLT_ROUND, "Round" },\r
+ { GLT_PLAYERS, "Players" },\r
+ { GLT_RESULT, "Result" },\r
+ { GLT_WHITE_ELO, "White Rating" },\r
+ { GLT_BLACK_ELO, "Black Rating" },\r
+ { GLT_TIME_CONTROL,"Time Control" },\r
+ { GLT_VARIANT, "Variant" },\r
+ { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },\r
+ { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom\r
+ { 0, 0 }\r
+};\r
+\r
+const char * GLT_FindItem( char id )\r
+{\r
+ const char * result = 0;\r
+\r
+ GLT_Item * list = GLT_ItemInfo;\r
+\r
+ while( list->id != 0 ) {\r
+ if( list->id == id ) {\r
+ result = list->name;\r
+ break;\r
+ }\r
+\r
+ list++;\r
+ }\r
+\r
+ return result;\r
+}\r
+\r
+void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )\r
+{\r
+ const char * name = GLT_FindItem( id );\r
+\r
+ if( name != 0 ) {\r
+ if( index >= 0 ) {\r
+ SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );\r
+ }\r
+ else {\r
+ SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );\r
+ }\r
+ }\r
+}\r
+\r
+void GLT_TagsToList( HWND hDlg, char * tags )\r
+{\r
+ char * pc = tags;\r
+\r
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );\r
+\r
+ while( *pc ) {\r
+ GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );\r
+ pc++;\r
+ }\r
+\r
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );\r
+\r
+ pc = GLT_ALL_TAGS;\r
+\r
+ while( *pc ) {\r
+ if( strchr( tags, *pc ) == 0 ) {\r
+ GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );\r
+ }\r
+ pc++;\r
+ }\r
+\r
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );\r
+}\r
+\r
+char GLT_ListItemToTag( HWND hDlg, int index )\r
+{\r
+ char result = '\0';\r
+ char name[128];\r
+\r
+ GLT_Item * list = GLT_ItemInfo;\r
+\r
+ if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {\r
+ while( list->id != 0 ) {\r
+ if( strcmp( list->name, name ) == 0 ) {\r
+ result = list->id;\r
+ break;\r
+ }\r
+\r
+ list++;\r
+ }\r
+ }\r
+\r
+ return result;\r
+}\r
+\r
+void GLT_MoveSelection( HWND hDlg, int delta )\r
+{\r
+ int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );\r
+ int idx2 = idx1 + delta;\r
+ int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );\r
+\r
+ if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {\r
+ char buf[128];\r
+\r
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );\r
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );\r
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );\r
+ SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );\r
+ }\r
+}\r
+\r
+LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ static char glt[64];\r
+ static char * lpUserGLT;\r
+\r
+ switch( message )\r
+ {\r
+ case WM_INITDIALOG:\r
+ lpUserGLT = (char *) lParam;\r
+ \r
+ strcpy( glt, lpUserGLT );\r
+\r
+ CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+\r
+ /* Initialize list */\r
+ GLT_TagsToList( hDlg, glt );\r
+\r
+ SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );\r
+\r
+ break;\r
+\r
+ case WM_COMMAND:\r
+ switch( LOWORD(wParam) ) {\r
+ case IDOK:\r
+ {\r
+ char * pc = lpUserGLT;\r
+ int idx = 0;\r
+// int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );\r
+ char id;\r
+\r
+ do {\r
+ id = GLT_ListItemToTag( hDlg, idx );\r
+\r
+ *pc++ = id;\r
+ idx++;\r
+ } while( id != '\0' );\r
+ }\r
+ EndDialog( hDlg, 0 );\r
+ return TRUE;\r
+ case IDCANCEL:\r
+ EndDialog( hDlg, 1 );\r
+ return TRUE;\r
+\r
+ case IDC_GLT_Default:\r
+ strcpy( glt, GLT_DEFAULT_TAGS );\r
+ GLT_TagsToList( hDlg, glt );\r
+ return TRUE;\r
+\r
+ case IDC_GLT_Restore:\r
+ strcpy( glt, lpUserGLT );\r
+ GLT_TagsToList( hDlg, glt );\r
+ return TRUE;\r
+\r
+ case IDC_GLT_Up:\r
+ GLT_MoveSelection( hDlg, -1 );\r
+ return TRUE;\r
+\r
+ case IDC_GLT_Down:\r
+ GLT_MoveSelection( hDlg, +1 );\r
+ return TRUE;\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+int GameListOptions()\r
+{\r
+ char glt[64];\r
+ int result;\r
+ FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );\r
+\r
+ strcpy( glt, appData.gameListTags );\r
+\r
+ result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );\r
+\r
+ if( result == 0 ) {\r
+ /* [AS] Memory leak here! */\r
+ appData.gameListTags = strdup( glt ); \r
+ }\r
+\r
+ return result;\r
+}\r
+\r
+\r
+VOID\r
+DisplayIcsInteractionTitle(char *str)\r
+{\r
+ char consoleTitle[MSG_SIZ];\r
+\r
+ sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);\r
+ SetWindowText(hwndConsole, consoleTitle);\r
+}\r
+\r
+void\r
+DrawPosition(int fullRedraw, Board board)\r
+{\r
+ HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board); \r
+}\r
+\r
+void NotifyFrontendLogin()\r
+{\r
+ if (hwndConsole)\r
+ UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));\r
+}\r
+\r
+VOID\r
+ResetFrontEnd()\r
+{\r
+ fromX = fromY = -1;\r
+ if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {\r
+ dragInfo.pos.x = dragInfo.pos.y = -1;\r
+ dragInfo.pos.x = dragInfo.pos.y = -1;\r
+ dragInfo.lastpos = dragInfo.pos;\r
+ dragInfo.start.x = dragInfo.start.y = -1;\r
+ dragInfo.from = dragInfo.start;\r
+ ReleaseCapture();\r
+ DrawPosition(TRUE, NULL);\r
+ }\r
+}\r
+\r
+\r
+VOID\r
+CommentPopUp(char *title, char *str)\r
+{\r
+ HWND hwnd = GetActiveWindow();\r
+ EitherCommentPopUp(0, title, str, FALSE);\r
+ SAY(str);\r
+ SetActiveWindow(hwnd);\r
+}\r
+\r
+VOID\r
+CommentPopDown(void)\r
+{\r
+ CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);\r
+ if (commentDialog) {\r
+ ShowWindow(commentDialog, SW_HIDE);\r
+ }\r
+ commentUp = FALSE;\r
+}\r
+\r
+VOID\r
+EditCommentPopUp(int index, char *title, char *str)\r
+{\r
+ EitherCommentPopUp(index, title, str, TRUE);\r
+}\r
+\r
+\r
+VOID\r
+RingBell()\r
+{\r
+ MyPlaySound(&sounds[(int)SoundMove]);\r
+}\r
+\r
+VOID PlayIcsWinSound()\r
+{\r
+ MyPlaySound(&sounds[(int)SoundIcsWin]);\r
+}\r
+\r
+VOID PlayIcsLossSound()\r
+{\r
+ MyPlaySound(&sounds[(int)SoundIcsLoss]);\r
+}\r
+\r
+VOID PlayIcsDrawSound()\r
+{\r
+ MyPlaySound(&sounds[(int)SoundIcsDraw]);\r
+}\r
+\r
+VOID PlayIcsUnfinishedSound()\r
+{\r
+ MyPlaySound(&sounds[(int)SoundIcsUnfinished]);\r
+}\r
+\r
+VOID\r
+PlayAlarmSound()\r
+{\r
+ MyPlaySound(&sounds[(int)SoundAlarm]);\r
+}\r
+\r
+\r
+VOID\r
+EchoOn()\r
+{\r
+ HWND hInput;\r
+ consoleEcho = TRUE;\r
+ hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+ SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);\r
+ SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);\r
+}\r
+\r
+\r
+VOID\r
+EchoOff()\r
+{\r
+ CHARFORMAT cf;\r
+ HWND hInput;\r
+ consoleEcho = FALSE;\r
+ hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+ /* This works OK: set text and background both to the same color */\r
+ cf = consoleCF;\r
+ cf.crTextColor = COLOR_ECHOOFF;\r
+ SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);\r
+ SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);\r
+}\r
+\r
+/* No Raw()...? */\r
+\r
+void Colorize(ColorClass cc, int continuation)\r
+{\r
+ currentColorClass = cc;\r
+ consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;\r
+ consoleCF.crTextColor = textAttribs[cc].color;\r
+ consoleCF.dwEffects = textAttribs[cc].effects;\r
+ if (!continuation) MyPlaySound(&textAttribs[cc].sound);\r
+}\r
+\r
+char *\r
+UserName()\r
+{\r
+ static char buf[MSG_SIZ];\r
+ DWORD bufsiz = MSG_SIZ;\r
+\r
+ if(appData.userName != NULL && appData.userName[0] != 0) { \r
+ return appData.userName; /* [HGM] username: prefer name selected by user over his system login */\r
+ }\r
+ if (!GetUserName(buf, &bufsiz)) {\r
+ /*DisplayError("Error getting user name", GetLastError());*/\r
+ strcpy(buf, "User");\r
+ }\r
+ return buf;\r
+}\r
+\r
+char *\r
+HostName()\r
+{\r
+ static char buf[MSG_SIZ];\r
+ DWORD bufsiz = MSG_SIZ;\r
+\r
+ if (!GetComputerName(buf, &bufsiz)) {\r
+ /*DisplayError("Error getting host name", GetLastError());*/\r
+ strcpy(buf, "Unknown");\r
+ }\r
+ return buf;\r
+}\r
+\r
+\r
+int\r
+ClockTimerRunning()\r
+{\r
+ return clockTimerEvent != 0;\r
+}\r
+\r
+int\r
+StopClockTimer()\r
+{\r
+ if (clockTimerEvent == 0) return FALSE;\r
+ KillTimer(hwndMain, clockTimerEvent);\r
+ clockTimerEvent = 0;\r
+ return TRUE;\r
+}\r
+\r
+void\r
+StartClockTimer(long millisec)\r
+{\r
+ clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,\r
+ (UINT) millisec, NULL);\r
+}\r
+\r
+void\r
+DisplayWhiteClock(long timeRemaining, int highlight)\r
+{\r
+ HDC hdc;\r
+ char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";\r
+\r
+ if(appData.noGUI) return;\r
+ hdc = GetDC(hwndMain);\r
+ if (!IsIconic(hwndMain)) {\r
+ DisplayAClock(hdc, timeRemaining, highlight, \r
+ flipClock ? &blackRect : &whiteRect, "White", flag);\r
+ }\r
+ if (highlight && iconCurrent == iconBlack) {\r
+ iconCurrent = iconWhite;\r
+ PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);\r
+ if (IsIconic(hwndMain)) {\r
+ DrawIcon(hdc, 2, 2, iconCurrent);\r
+ }\r
+ }\r
+ (void) ReleaseDC(hwndMain, hdc);\r
+ if (hwndConsole)\r
+ PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);\r
+}\r
+\r
+void\r
+DisplayBlackClock(long timeRemaining, int highlight)\r
+{\r
+ HDC hdc;\r
+ char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";\r
+\r
+ if(appData.noGUI) return;\r
+ hdc = GetDC(hwndMain);\r
+ if (!IsIconic(hwndMain)) {\r
+ DisplayAClock(hdc, timeRemaining, highlight, \r
+ flipClock ? &whiteRect : &blackRect, "Black", flag);\r
+ }\r
+ if (highlight && iconCurrent == iconWhite) {\r
+ iconCurrent = iconBlack;\r
+ PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);\r
+ if (IsIconic(hwndMain)) {\r
+ DrawIcon(hdc, 2, 2, iconCurrent);\r
+ }\r
+ }\r
+ (void) ReleaseDC(hwndMain, hdc);\r
+ if (hwndConsole)\r
+ PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);\r
+}\r
+\r
+\r
+int\r
+LoadGameTimerRunning()\r
+{\r
+ return loadGameTimerEvent != 0;\r
+}\r
+\r
+int\r
+StopLoadGameTimer()\r
+{\r
+ if (loadGameTimerEvent == 0) return FALSE;\r
+ KillTimer(hwndMain, loadGameTimerEvent);\r
+ loadGameTimerEvent = 0;\r
+ return TRUE;\r
+}\r
+\r
+void\r
+StartLoadGameTimer(long millisec)\r
+{\r
+ loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,\r
+ (UINT) millisec, NULL);\r
+}\r
+\r
+void\r
+AutoSaveGame()\r
+{\r
+ char *defName;\r
+ FILE *f;\r
+ char fileTitle[MSG_SIZ];\r
+\r
+ defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");\r
+ f = OpenFileDialog(hwndMain, "a", defName,\r
+ appData.oldSaveStyle ? "gam" : "pgn",\r
+ GAME_FILT, \r
+ "Save Game to File", NULL, fileTitle, NULL);\r
+ if (f != NULL) {\r
+ SaveGame(f, 0, "");\r
+ fclose(f);\r
+ }\r
+}\r
+\r
+\r
+void\r
+ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)\r
+{\r
+ if (delayedTimerEvent != 0) {\r
+ if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug\r
+ fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");\r
+ }\r
+ KillTimer(hwndMain, delayedTimerEvent);\r
+ delayedTimerEvent = 0;\r
+ if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it\r
+ delayedTimerCallback();\r
+ }\r
+ delayedTimerCallback = cb;\r
+ delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,\r
+ (UINT) millisec, NULL);\r
+}\r
+\r
+DelayedEventCallback\r
+GetDelayedEvent()\r
+{\r
+ if (delayedTimerEvent) {\r
+ return delayedTimerCallback;\r
+ } else {\r
+ return NULL;\r
+ }\r
+}\r
+\r
+void\r
+CancelDelayedEvent()\r
+{\r
+ if (delayedTimerEvent) {\r
+ KillTimer(hwndMain, delayedTimerEvent);\r
+ delayedTimerEvent = 0;\r
+ }\r
+}\r
+\r
+DWORD GetWin32Priority(int nice)\r
+{ // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)\r
+/*\r
+REALTIME_PRIORITY_CLASS 0x00000100\r
+HIGH_PRIORITY_CLASS 0x00000080\r
+ABOVE_NORMAL_PRIORITY_CLASS 0x00008000\r
+NORMAL_PRIORITY_CLASS 0x00000020\r
+BELOW_NORMAL_PRIORITY_CLASS 0x00004000\r
+IDLE_PRIORITY_CLASS 0x00000040\r
+*/\r
+ if (nice < -15) return 0x00000080;\r
+ if (nice < 0) return 0x00008000;\r
+ if (nice == 0) return 0x00000020;\r
+ if (nice < 15) return 0x00004000;\r
+ return 0x00000040;\r
+}\r
+\r
+/* Start a child process running the given program.\r
+ The process's standard output can be read from "from", and its\r
+ standard input can be written to "to".\r
+ Exit with fatal error if anything goes wrong.\r
+ Returns an opaque pointer that can be used to destroy the process\r
+ later.\r
+*/\r
+int\r
+StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)\r
+{\r
+#define BUFSIZE 4096\r
+\r
+ HANDLE hChildStdinRd, hChildStdinWr,\r
+ hChildStdoutRd, hChildStdoutWr;\r
+ HANDLE hChildStdinWrDup, hChildStdoutRdDup;\r
+ SECURITY_ATTRIBUTES saAttr;\r
+ BOOL fSuccess;\r
+ PROCESS_INFORMATION piProcInfo;\r
+ STARTUPINFO siStartInfo;\r
+ ChildProc *cp;\r
+ char buf[MSG_SIZ];\r
+ DWORD err;\r
+\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);\r
+ }\r
+\r
+ *pr = NoProc;\r
+\r
+ /* Set the bInheritHandle flag so pipe handles are inherited. */\r
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);\r
+ saAttr.bInheritHandle = TRUE;\r
+ saAttr.lpSecurityDescriptor = NULL;\r
+\r
+ /*\r
+ * The steps for redirecting child's STDOUT:\r
+ * 1. Create anonymous pipe to be STDOUT for child.\r
+ * 2. Create a noninheritable duplicate of read handle,\r
+ * and close the inheritable read handle.\r
+ */\r
+\r
+ /* Create a pipe for the child's STDOUT. */\r
+ if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {\r
+ return GetLastError();\r
+ }\r
+\r
+ /* Duplicate the read handle to the pipe, so it is not inherited. */\r
+ fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,\r
+ GetCurrentProcess(), &hChildStdoutRdDup, 0,\r
+ FALSE, /* not inherited */\r
+ DUPLICATE_SAME_ACCESS);\r
+ if (! fSuccess) {\r
+ return GetLastError();\r
+ }\r
+ CloseHandle(hChildStdoutRd);\r
+\r
+ /*\r
+ * The steps for redirecting child's STDIN:\r
+ * 1. Create anonymous pipe to be STDIN for child.\r
+ * 2. Create a noninheritable duplicate of write handle,\r
+ * and close the inheritable write handle.\r
+ */\r
+\r
+ /* Create a pipe for the child's STDIN. */\r
+ if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {\r
+ return GetLastError();\r
+ }\r
+\r
+ /* Duplicate the write handle to the pipe, so it is not inherited. */\r
+ fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,\r
+ GetCurrentProcess(), &hChildStdinWrDup, 0,\r
+ FALSE, /* not inherited */\r
+ DUPLICATE_SAME_ACCESS);\r
+ if (! fSuccess) {\r
+ return GetLastError();\r
+ }\r
+ CloseHandle(hChildStdinWr);\r
+\r
+ /* Arrange to (1) look in dir for the child .exe file, and\r
+ * (2) have dir be the child's working directory. Interpret\r
+ * dir relative to the directory WinBoard loaded from. */\r
+ GetCurrentDirectory(MSG_SIZ, buf);\r
+ SetCurrentDirectory(installDir);\r
+ SetCurrentDirectory(dir);\r
+\r
+ /* Now create the child process. */\r
+\r
+ siStartInfo.cb = sizeof(STARTUPINFO);\r
+ siStartInfo.lpReserved = NULL;\r
+ siStartInfo.lpDesktop = NULL;\r
+ siStartInfo.lpTitle = NULL;\r
+ siStartInfo.dwFlags = STARTF_USESTDHANDLES;\r
+ siStartInfo.cbReserved2 = 0;\r
+ siStartInfo.lpReserved2 = NULL;\r
+ siStartInfo.hStdInput = hChildStdinRd;\r
+ siStartInfo.hStdOutput = hChildStdoutWr;\r
+ siStartInfo.hStdError = hChildStdoutWr;\r
+\r
+ fSuccess = CreateProcess(NULL,\r
+ cmdLine, /* command line */\r
+ NULL, /* process security attributes */\r
+ NULL, /* primary thread security attrs */\r
+ TRUE, /* handles are inherited */\r
+ DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,\r
+ NULL, /* use parent's environment */\r
+ NULL,\r
+ &siStartInfo, /* STARTUPINFO pointer */\r
+ &piProcInfo); /* receives PROCESS_INFORMATION */\r
+\r
+ err = GetLastError();\r
+ SetCurrentDirectory(buf); /* return to prev directory */\r
+ if (! fSuccess) {\r
+ return err;\r
+ }\r
+\r
+ if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority\r
+ if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);\r
+ SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));\r
+ }\r
+\r
+ /* Close the handles we don't need in the parent */\r
+ CloseHandle(piProcInfo.hThread);\r
+ CloseHandle(hChildStdinRd);\r
+ CloseHandle(hChildStdoutWr);\r
+\r
+ /* Prepare return value */\r
+ cp = (ChildProc *) calloc(1, sizeof(ChildProc));\r
+ cp->kind = CPReal;\r
+ cp->hProcess = piProcInfo.hProcess;\r
+ cp->pid = piProcInfo.dwProcessId;\r
+ cp->hFrom = hChildStdoutRdDup;\r
+ cp->hTo = hChildStdinWrDup;\r
+\r
+ *pr = (void *) cp;\r
+\r
+ /* Klaus Friedel says that this Sleep solves a problem under Windows\r
+ 2000 where engines sometimes don't see the initial command(s)\r
+ from WinBoard and hang. I don't understand how that can happen,\r
+ but the Sleep is harmless, so I've put it in. Others have also\r
+ reported what may be the same problem, so hopefully this will fix\r
+ it for them too. */\r
+ Sleep(500);\r
+\r
+ return NO_ERROR;\r
+}\r
+\r
+\r
+void\r
+DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)\r
+{\r
+ ChildProc *cp; int result;\r
+\r
+ cp = (ChildProc *) pr;\r
+ if (cp == NULL) return;\r
+\r
+ switch (cp->kind) {\r
+ case CPReal:\r
+ /* TerminateProcess is considered harmful, so... */\r
+ CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */\r
+ if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */\r
+ /* The following doesn't work because the chess program\r
+ doesn't "have the same console" as WinBoard. Maybe\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
+\r
+ /* [AS] Special termination modes for misbehaving programs... */\r
+ if( signal == 9 ) { \r
+ result = TerminateProcess( cp->hProcess, 0 );\r
+\r
+ if ( appData.debugMode) {\r
+ fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );\r
+ }\r
+ }\r
+ else if( signal == 10 ) {\r
+ DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most\r
+\r
+ if( dw != WAIT_OBJECT_0 ) {\r
+ result = TerminateProcess( cp->hProcess, 0 );\r
+\r
+ if ( appData.debugMode) {\r
+ fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+ CloseHandle(cp->hProcess);\r
+ break;\r
+\r
+ case CPComm:\r
+ if (cp->hFrom) CloseHandle(cp->hFrom);\r
+ break;\r
+\r
+ case CPSock:\r
+ closesocket(cp->sock);\r
+ WSACleanup();\r
+ break;\r
+\r
+ case CPRcmd:\r
+ if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */\r
+ closesocket(cp->sock);\r
+ closesocket(cp->sock2);\r
+ WSACleanup();\r
+ break;\r
+ }\r
+ free(cp);\r
+}\r
+\r
+void\r
+InterruptChildProcess(ProcRef pr)\r
+{\r
+ ChildProc *cp;\r
+\r
+ cp = (ChildProc *) pr;\r
+ if (cp == NULL) return;\r
+ switch (cp->kind) {\r
+ case CPReal:\r
+ /* The following doesn't work because the chess program\r
+ doesn't "have the same console" as WinBoard. Maybe\r
+ we could arrange for this even though neither WinBoard\r
+ nor the chess program uses a console for stdio */\r
+ /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/\r
+ break;\r
+\r
+ case CPComm:\r
+ case CPSock:\r
+ /* Can't interrupt */\r
+ break;\r
+\r
+ case CPRcmd:\r
+ send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */\r
+ break;\r
+ }\r
+}\r
+\r
+\r
+int\r
+OpenTelnet(char *host, char *port, ProcRef *pr)\r
+{\r
+ char cmdLine[MSG_SIZ];\r
+\r
+ if (port[0] == NULLCHAR) {\r
+ sprintf(cmdLine, "%s %s", appData.telnetProgram, host);\r
+ } else {\r
+ sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);\r
+ }\r
+ return StartChildProcess(cmdLine, "", pr);\r
+}\r
+\r
+\r
+/* Code to open TCP sockets */\r
+\r
+int\r
+OpenTCP(char *host, char *port, ProcRef *pr)\r
+{\r
+ ChildProc *cp;\r
+ int err;\r
+ SOCKET s;\r
+ struct sockaddr_in sa, mysa;\r
+ struct hostent FAR *hp;\r
+ unsigned short uport;\r
+ WORD wVersionRequested;\r
+ WSADATA wsaData;\r
+\r
+ /* Initialize socket DLL */\r
+ wVersionRequested = MAKEWORD(1, 1);\r
+ err = WSAStartup(wVersionRequested, &wsaData);\r
+ if (err != 0) return err;\r
+\r
+ /* Make socket */\r
+ if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {\r
+ err = WSAGetLastError();\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+\r
+ /* Bind local address using (mostly) don't-care values.\r
+ */\r
+ memset((char *) &mysa, 0, sizeof(struct sockaddr_in));\r
+ mysa.sin_family = AF_INET;\r
+ mysa.sin_addr.s_addr = INADDR_ANY;\r
+ uport = (unsigned short) 0;\r
+ mysa.sin_port = htons(uport);\r
+ if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))\r
+ == SOCKET_ERROR) {\r
+ err = WSAGetLastError();\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+\r
+ /* Resolve remote host name */\r
+ memset((char *) &sa, 0, sizeof(struct sockaddr_in));\r
+ if (!(hp = gethostbyname(host))) {\r
+ unsigned int b0, b1, b2, b3;\r
+\r
+ err = WSAGetLastError();\r
+\r
+ if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {\r
+ hp = (struct hostent *) calloc(1, sizeof(struct hostent));\r
+ hp->h_addrtype = AF_INET;\r
+ hp->h_length = 4;\r
+ hp->h_addr_list = (char **) calloc(2, sizeof(char *));\r
+ hp->h_addr_list[0] = (char *) malloc(4);\r
+ hp->h_addr_list[0][0] = (char) b0;\r
+ hp->h_addr_list[0][1] = (char) b1;\r
+ hp->h_addr_list[0][2] = (char) b2;\r
+ hp->h_addr_list[0][3] = (char) b3;\r
+ } else {\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+ }\r
+ sa.sin_family = hp->h_addrtype;\r
+ uport = (unsigned short) atoi(port);\r
+ sa.sin_port = htons(uport);\r
+ memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);\r
+\r
+ /* Make connection */\r
+ if (connect(s, (struct sockaddr *) &sa,\r
+ sizeof(struct sockaddr_in)) == SOCKET_ERROR) {\r
+ err = WSAGetLastError();\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+\r
+ /* Prepare return value */\r
+ cp = (ChildProc *) calloc(1, sizeof(ChildProc));\r
+ cp->kind = CPSock;\r
+ cp->sock = s;\r
+ *pr = (ProcRef *) cp;\r
+\r
+ return NO_ERROR;\r
+}\r
+\r
+int\r
+OpenCommPort(char *name, ProcRef *pr)\r
+{\r
+ HANDLE h;\r
+ COMMTIMEOUTS ct;\r
+ ChildProc *cp;\r
+ char fullname[MSG_SIZ];\r
+\r
+ if (*name != '\\')\r
+ sprintf(fullname, "\\\\.\\%s", name);\r
+ else\r
+ strcpy(fullname, name);\r
+\r
+ h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,\r
+ 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);\r
+ if (h == (HANDLE) -1) {\r
+ return GetLastError();\r
+ }\r
+ hCommPort = h;\r
+\r
+ if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();\r
+\r
+ /* Accumulate characters until a 100ms pause, then parse */\r
+ ct.ReadIntervalTimeout = 100;\r
+ ct.ReadTotalTimeoutMultiplier = 0;\r
+ ct.ReadTotalTimeoutConstant = 0;\r
+ ct.WriteTotalTimeoutMultiplier = 0;\r
+ ct.WriteTotalTimeoutConstant = 0;\r
+ if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();\r
+\r
+ /* Prepare return value */\r
+ cp = (ChildProc *) calloc(1, sizeof(ChildProc));\r
+ cp->kind = CPComm;\r
+ cp->hFrom = h;\r
+ cp->hTo = h;\r
+ *pr = (ProcRef *) cp;\r
+\r
+ return NO_ERROR;\r
+}\r
+\r
+int\r
+OpenLoopback(ProcRef *pr)\r
+{\r
+ DisplayFatalError("Not implemented", 0, 1);\r
+ return NO_ERROR;\r
+}\r
+\r
+\r
+int\r
+OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)\r
+{\r
+ ChildProc *cp;\r
+ int err;\r
+ SOCKET s, s2, s3;\r
+ struct sockaddr_in sa, mysa;\r
+ struct hostent FAR *hp;\r
+ unsigned short uport;\r
+ WORD wVersionRequested;\r
+ WSADATA wsaData;\r
+ int fromPort;\r
+ char stderrPortStr[MSG_SIZ];\r
+\r
+ /* Initialize socket DLL */\r
+ wVersionRequested = MAKEWORD(1, 1);\r
+ err = WSAStartup(wVersionRequested, &wsaData);\r
+ if (err != 0) return err;\r
+\r
+ /* Resolve remote host name */\r
+ memset((char *) &sa, 0, sizeof(struct sockaddr_in));\r
+ if (!(hp = gethostbyname(host))) {\r
+ unsigned int b0, b1, b2, b3;\r
+\r
+ err = WSAGetLastError();\r
+\r
+ if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {\r
+ hp = (struct hostent *) calloc(1, sizeof(struct hostent));\r
+ hp->h_addrtype = AF_INET;\r
+ hp->h_length = 4;\r
+ hp->h_addr_list = (char **) calloc(2, sizeof(char *));\r
+ hp->h_addr_list[0] = (char *) malloc(4);\r
+ hp->h_addr_list[0][0] = (char) b0;\r
+ hp->h_addr_list[0][1] = (char) b1;\r
+ hp->h_addr_list[0][2] = (char) b2;\r
+ hp->h_addr_list[0][3] = (char) b3;\r
+ } else {\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+ }\r
+ sa.sin_family = hp->h_addrtype;\r
+ uport = (unsigned short) 514;\r
+ sa.sin_port = htons(uport);\r
+ memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);\r
+\r
+ /* Bind local socket to unused "privileged" port address\r
+ */\r
+ s = INVALID_SOCKET;\r
+ memset((char *) &mysa, 0, sizeof(struct sockaddr_in));\r
+ mysa.sin_family = AF_INET;\r
+ mysa.sin_addr.s_addr = INADDR_ANY;\r
+ for (fromPort = 1023;; fromPort--) {\r
+ if (fromPort < 0) {\r
+ WSACleanup();\r
+ return WSAEADDRINUSE;\r
+ }\r
+ if (s == INVALID_SOCKET) {\r
+ if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {\r
+ err = WSAGetLastError();\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+ }\r
+ uport = (unsigned short) fromPort;\r
+ mysa.sin_port = htons(uport);\r
+ if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))\r
+ == SOCKET_ERROR) {\r
+ err = WSAGetLastError();\r
+ if (err == WSAEADDRINUSE) continue;\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+ if (connect(s, (struct sockaddr *) &sa,\r
+ sizeof(struct sockaddr_in)) == SOCKET_ERROR) {\r
+ err = WSAGetLastError();\r
+ if (err == WSAEADDRINUSE) {\r
+ closesocket(s);\r
+ s = -1;\r
+ continue;\r
+ }\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+ break;\r
+ }\r
+\r
+ /* Bind stderr local socket to unused "privileged" port address\r
+ */\r
+ s2 = INVALID_SOCKET;\r
+ memset((char *) &mysa, 0, sizeof(struct sockaddr_in));\r
+ mysa.sin_family = AF_INET;\r
+ mysa.sin_addr.s_addr = INADDR_ANY;\r
+ for (fromPort = 1023;; fromPort--) {\r
+ if (fromPort == prevStderrPort) continue; // don't reuse port\r
+ if (fromPort < 0) {\r
+ (void) closesocket(s);\r
+ WSACleanup();\r
+ return WSAEADDRINUSE;\r
+ }\r
+ if (s2 == INVALID_SOCKET) {\r
+ if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {\r
+ err = WSAGetLastError();\r
+ closesocket(s);\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+ }\r
+ uport = (unsigned short) fromPort;\r
+ mysa.sin_port = htons(uport);\r
+ if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))\r
+ == SOCKET_ERROR) {\r
+ err = WSAGetLastError();\r
+ if (err == WSAEADDRINUSE) continue;\r
+ (void) closesocket(s);\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+ if (listen(s2, 1) == SOCKET_ERROR) {\r
+ err = WSAGetLastError();\r
+ if (err == WSAEADDRINUSE) {\r
+ closesocket(s2);\r
+ s2 = INVALID_SOCKET;\r
+ continue;\r
+ }\r
+ (void) closesocket(s);\r
+ (void) closesocket(s2);\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+ break;\r
+ }\r
+ prevStderrPort = fromPort; // remember port used\r
+ sprintf(stderrPortStr, "%d", fromPort);\r
+\r
+ if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {\r
+ err = WSAGetLastError();\r
+ (void) closesocket(s);\r
+ (void) closesocket(s2);\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+\r
+ if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {\r
+ err = WSAGetLastError();\r
+ (void) closesocket(s);\r
+ (void) closesocket(s2);\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+ if (*user == NULLCHAR) user = UserName();\r
+ if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {\r
+ err = WSAGetLastError();\r
+ (void) closesocket(s);\r
+ (void) closesocket(s2);\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+ if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {\r
+ err = WSAGetLastError();\r
+ (void) closesocket(s);\r
+ (void) closesocket(s2);\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+\r
+ if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {\r
+ err = WSAGetLastError();\r
+ (void) closesocket(s);\r
+ (void) closesocket(s2);\r
+ WSACleanup();\r
+ return err;\r
+ }\r
+ (void) closesocket(s2); /* Stop listening */\r
+\r
+ /* Prepare return value */\r
+ cp = (ChildProc *) calloc(1, sizeof(ChildProc));\r
+ cp->kind = CPRcmd;\r
+ cp->sock = s;\r
+ cp->sock2 = s3;\r
+ *pr = (ProcRef *) cp;\r
+\r
+ return NO_ERROR;\r
+}\r
+\r
+\r
+InputSourceRef\r
+AddInputSource(ProcRef pr, int lineByLine,\r
+ InputCallback func, VOIDSTAR closure)\r
+{\r
+ InputSource *is, *is2 = NULL;\r
+ ChildProc *cp = (ChildProc *) pr;\r
+\r
+ is = (InputSource *) calloc(1, sizeof(InputSource));\r
+ is->lineByLine = lineByLine;\r
+ is->func = func;\r
+ is->closure = closure;\r
+ is->second = NULL;\r
+ is->next = is->buf;\r
+ if (pr == NoProc) {\r
+ is->kind = CPReal;\r
+ consoleInputSource = is;\r
+ } else {\r
+ is->kind = cp->kind;\r
+ /* \r
+ [AS] Try to avoid a race condition if the thread is given control too early:\r
+ we create all threads suspended so that the is->hThread variable can be\r
+ safely assigned, then let the threads start with ResumeThread.\r
+ */\r
+ 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, CREATE_SUSPENDED, &is->id);\r
+ break;\r
+\r
+ case CPComm:\r
+ is->hFile = cp->hFrom;\r
+ cp->hFrom = NULL; /* now owned by InputThread */\r
+ is->hThread =\r
+ CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,\r
+ (LPVOID) is, CREATE_SUSPENDED, &is->id);\r
+ break;\r
+\r
+ case CPSock:\r
+ is->sock = cp->sock;\r
+ is->hThread =\r
+ CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
+ (LPVOID) is, CREATE_SUSPENDED, &is->id);\r
+ break;\r
+\r
+ case CPRcmd:\r
+ is2 = (InputSource *) calloc(1, sizeof(InputSource));\r
+ *is2 = *is;\r
+ is->sock = cp->sock;\r
+ is->second = is2;\r
+ is2->sock = cp->sock2;\r
+ is2->second = is2;\r
+ is->hThread =\r
+ CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
+ (LPVOID) is, CREATE_SUSPENDED, &is->id);\r
+ is2->hThread =\r
+ CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
+ (LPVOID) is2, CREATE_SUSPENDED, &is2->id);\r
+ break;\r
+ }\r
+\r
+ if( is->hThread != NULL ) {\r
+ ResumeThread( is->hThread );\r
+ }\r
+\r
+ if( is2 != NULL && is2->hThread != NULL ) {\r
+ ResumeThread( is2->hThread );\r
+ }\r
+ }\r
+\r
+ return (InputSourceRef) is;\r
+}\r
+\r
+void\r
+RemoveInputSource(InputSourceRef isr)\r
+{\r
+ InputSource *is;\r
+\r
+ is = (InputSource *) isr;\r
+ is->hThread = NULL; /* tell thread to stop */\r
+ CloseHandle(is->hThread);\r
+ if (is->second != NULL) {\r
+ is->second->hThread = NULL;\r
+ CloseHandle(is->second->hThread);\r
+ }\r
+}\r
+\r
+int no_wrap(char *message, int count)\r
+{\r
+ ConsoleOutput(message, count, FALSE);\r
+ return count;\r
+}\r
+\r
+int\r
+OutputToProcess(ProcRef pr, char *message, int count, int *outError)\r
+{\r
+ DWORD dOutCount;\r
+ int outCount = SOCKET_ERROR;\r
+ ChildProc *cp = (ChildProc *) pr;\r
+ static OVERLAPPED ovl;\r
+ static int line = 0;\r
+\r
+ if (pr == NoProc)\r
+ {\r
+ if (appData.noJoin || !appData.useInternalWrap)\r
+ return no_wrap(message, count);\r
+ else\r
+ {\r
+ int width = get_term_width();\r
+ int len = wrap(NULL, message, count, width, &line);\r
+ char *msg = malloc(len);\r
+ int dbgchk;\r
+\r
+ if (!msg)\r
+ return no_wrap(message, count);\r
+ else\r
+ {\r
+ dbgchk = wrap(msg, message, count, width, &line);\r
+ if (dbgchk != len && appData.debugMode)\r
+ fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);\r
+ ConsoleOutput(msg, len, FALSE);\r
+ free(msg);\r
+ return len;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (ovl.hEvent == NULL) {\r
+ ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
+ }\r
+ ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;\r
+\r
+ switch (cp->kind) {\r
+ case CPSock:\r
+ case CPRcmd:\r
+ outCount = send(cp->sock, message, count, 0);\r
+ if (outCount == SOCKET_ERROR) {\r
+ *outError = WSAGetLastError();\r
+ } else {\r
+ *outError = NO_ERROR;\r
+ }\r
+ break;\r
+\r
+ case CPReal:\r
+ if (WriteFile(((ChildProc *)pr)->hTo, message, count,\r
+ &dOutCount, NULL)) {\r
+ *outError = NO_ERROR;\r
+ outCount = (int) dOutCount;\r
+ } else {\r
+ *outError = GetLastError();\r
+ }\r
+ break;\r
+\r
+ case CPComm:\r
+ *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,\r
+ &dOutCount, &ovl);\r
+ if (*outError == NO_ERROR) {\r
+ outCount = (int) dOutCount;\r
+ }\r
+ break;\r
+ }\r
+ return outCount;\r
+}\r
+\r
+int\r
+OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,\r
+ long msdelay)\r
+{\r
+ /* Ignore delay, not implemented for WinBoard */\r
+ return OutputToProcess(pr, message, count, outError);\r
+}\r
+\r
+\r
+void\r
+CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,\r
+ char *buf, int count, int error)\r
+{\r
+ DisplayFatalError("Not implemented", 0, 1);\r
+}\r
+\r
+/* see wgamelist.c for Game List functions */\r
+/* see wedittags.c for Edit Tags functions */\r
+\r
+\r
+VOID\r
+ICSInitScript()\r
+{\r
+ FILE *f;\r
+ char buf[MSG_SIZ];\r
+ char *dummy;\r
+\r
+ if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {\r
+ f = fopen(buf, "r");\r
+ if (f != NULL) {\r
+ ProcessICSInitScript(f);\r
+ fclose(f);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+VOID\r
+StartAnalysisClock()\r
+{\r
+ if (analysisTimerEvent) return;\r
+ analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,\r
+ (UINT) 2000, NULL);\r
+}\r
+\r
+LRESULT CALLBACK\r
+AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ static HANDLE hwndText;\r
+ RECT rect;\r
+ static int sizeX, sizeY;\r
+ int newSizeX, newSizeY, flags;\r
+ MINMAXINFO *mmi;\r
+\r
+ switch (message) {\r
+ case WM_INITDIALOG: /* message: initialize dialog box */\r
+ /* Initialize the dialog items */\r
+ hwndText = GetDlgItem(hDlg, OPT_AnalysisText);\r
+ SetWindowText(hDlg, analysisTitle);\r
+ SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);\r
+ /* Size and position the dialog */\r
+ if (!analysisDialog) {\r
+ analysisDialog = hDlg;\r
+ flags = SWP_NOZORDER;\r
+ GetClientRect(hDlg, &rect);\r
+ sizeX = rect.right;\r
+ sizeY = rect.bottom;\r
+ if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&\r
+ analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {\r
+ WINDOWPLACEMENT wp;\r
+ EnsureOnScreen(&analysisX, &analysisY, 0, 0);\r
+ wp.length = sizeof(WINDOWPLACEMENT);\r
+ wp.flags = 0;\r
+ wp.showCmd = SW_SHOW;\r
+ wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
+ wp.rcNormalPosition.left = analysisX;\r
+ wp.rcNormalPosition.right = analysisX + analysisW;\r
+ wp.rcNormalPosition.top = analysisY;\r
+ wp.rcNormalPosition.bottom = analysisY + analysisH;\r
+ SetWindowPlacement(hDlg, &wp);\r
+\r
+ GetClientRect(hDlg, &rect);\r
+ newSizeX = rect.right;\r
+ newSizeY = rect.bottom;\r
+ ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,\r
+ newSizeX, newSizeY);\r
+ sizeX = newSizeX;\r
+ sizeY = newSizeY;\r
+ }\r
+ }\r
+ return FALSE;\r
+\r
+ case WM_COMMAND: /* message: received a command */\r
+ switch (LOWORD(wParam)) {\r
+ case IDCANCEL:\r
+ if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */\r
+ ExitAnalyzeMode();\r
+ ModeHighlight();\r
+ return TRUE;\r
+ }\r
+ EditGameEvent();\r
+ return TRUE;\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case WM_SIZE:\r
+ newSizeX = LOWORD(lParam);\r
+ newSizeY = HIWORD(lParam);\r
+ ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);\r
+ sizeX = newSizeX;\r
+ sizeY = newSizeY;\r
+ break;\r
+\r
+ case WM_GETMINMAXINFO:\r
+ /* Prevent resizing window too small */\r
+ mmi = (MINMAXINFO *) lParam;\r
+ mmi->ptMinTrackSize.x = 100;\r
+ mmi->ptMinTrackSize.y = 100;\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+VOID\r
+SetHighlights(int fromX, int fromY, int toX, int toY)\r
+{\r
+ highlightInfo.sq[0].x = fromX;\r
+ highlightInfo.sq[0].y = fromY;\r
+ highlightInfo.sq[1].x = toX;\r
+ highlightInfo.sq[1].y = toY;\r
+}\r
+\r
+VOID\r
+ClearHighlights()\r
+{\r
+ highlightInfo.sq[0].x = highlightInfo.sq[0].y = \r
+ highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;\r
+}\r
+\r
+VOID\r
+SetPremoveHighlights(int fromX, int fromY, int toX, int toY)\r
+{\r
+ premoveHighlightInfo.sq[0].x = fromX;\r
+ premoveHighlightInfo.sq[0].y = fromY;\r
+ premoveHighlightInfo.sq[1].x = toX;\r
+ premoveHighlightInfo.sq[1].y = toY;\r
+}\r
+\r
+VOID\r
+ClearPremoveHighlights()\r
+{\r
+ premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y = \r
+ premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;\r
+}\r
+\r
+VOID\r
+ShutDownFrontEnd()\r
+{\r
+ if (saveSettingsOnExit) SaveSettings(settingsFileName);\r
+ DeleteClipboardTempFiles();\r
+}\r
+\r
+void\r
+BoardToTop()\r
+{\r
+ if (IsIconic(hwndMain))\r
+ ShowWindow(hwndMain, SW_RESTORE);\r
+\r
+ SetActiveWindow(hwndMain);\r
+}\r
+\r
+/*\r
+ * Prototypes for animation support routines\r
+ */\r
+static void ScreenSquare(int column, int row, POINT * pt);\r
+static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,\r
+ POINT frames[], int * nFrames);\r
+\r
+\r
+void\r
+AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)\r
+{ // [HGM] atomic: animate blast wave\r
+ int i;\r
+if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);\r
+ explodeInfo.fromX = fromX;\r
+ explodeInfo.fromY = fromY;\r
+ explodeInfo.toX = toX;\r
+ explodeInfo.toY = toY;\r
+ for(i=1; i<nFrames; i++) {\r
+ explodeInfo.radius = (i*180)/(nFrames-1);\r
+ DrawPosition(FALSE, NULL);\r
+ Sleep(appData.animSpeed);\r
+ }\r
+ explodeInfo.radius = 0;\r
+ DrawPosition(TRUE, NULL);\r
+}\r
+\r
+#define kFactor 4\r
+\r
+void\r
+AnimateMove(board, fromX, fromY, toX, toY)\r
+ Board board;\r
+ int fromX;\r
+ int fromY;\r
+ int toX;\r
+ int toY;\r
+{\r
+ ChessSquare piece;\r
+ POINT start, finish, mid;\r
+ POINT frames[kFactor * 2 + 1];\r
+ int nFrames, n;\r
+\r
+ if (!appData.animate) return;\r
+ if (doingSizing) return;\r
+ if (fromY < 0 || fromX < 0) return;\r
+ piece = board[fromY][fromX];\r
+ if (piece >= EmptySquare) return;\r
+\r
+ ScreenSquare(fromX, fromY, &start);\r
+ ScreenSquare(toX, toY, &finish);\r
+\r
+ /* All pieces except knights move in straight line */\r
+ if (piece != WhiteKnight && piece != BlackKnight) {\r
+ mid.x = start.x + (finish.x - start.x) / 2;\r
+ mid.y = start.y + (finish.y - start.y) / 2;\r
+ } else {\r
+ /* Knight: make diagonal movement then straight */\r
+ if (abs(toY - fromY) < abs(toX - fromX)) {\r
+ mid.x = start.x + (finish.x - start.x) / 2;\r
+ mid.y = finish.y;\r
+ } else {\r
+ mid.x = finish.x;\r
+ mid.y = start.y + (finish.y - start.y) / 2;\r
+ }\r
+ }\r
+ \r
+ /* Don't use as many frames for very short moves */\r
+ if (abs(toY - fromY) + abs(toX - fromX) <= 2)\r
+ Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);\r
+ else\r
+ Tween(&start, &mid, &finish, kFactor, frames, &nFrames);\r
+\r
+ animInfo.from.x = fromX;\r
+ animInfo.from.y = fromY;\r
+ animInfo.to.x = toX;\r
+ animInfo.to.y = toY;\r
+ animInfo.lastpos = start;\r
+ animInfo.piece = piece;\r
+ for (n = 0; n < nFrames; n++) {\r
+ animInfo.pos = frames[n];\r
+ DrawPosition(FALSE, NULL);\r
+ animInfo.lastpos = animInfo.pos;\r
+ Sleep(appData.animSpeed);\r
+ }\r
+ animInfo.pos = finish;\r
+ DrawPosition(FALSE, NULL);\r
+ animInfo.piece = EmptySquare;\r
+ if(gameInfo.variant == VariantAtomic && \r
+ (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )\r
+ AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);\r
+}\r
+\r
+/* Convert board position to corner of screen rect and color */\r
+\r
+static void\r
+ScreenSquare(column, row, pt)\r
+ int column; int row; POINT * pt;\r
+{\r
+ if (flipView) {\r
+ pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);\r
+ pt->y = lineGap + row * (squareSize + lineGap);\r
+ } else {\r
+ pt->x = lineGap + column * (squareSize + lineGap);\r
+ pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);\r
+ }\r
+}\r
+\r
+/* Generate a series of frame coords from start->mid->finish.\r
+ The movement rate doubles until the half way point is\r
+ reached, then halves back down to the final destination,\r
+ which gives a nice slow in/out effect. The algorithmn\r
+ may seem to generate too many intermediates for short\r
+ moves, but remember that the purpose is to attract the\r
+ viewers attention to the piece about to be moved and\r
+ then to where it ends up. Too few frames would be less\r
+ noticeable. */\r
+\r
+static void\r
+Tween(start, mid, finish, factor, frames, nFrames)\r
+ POINT * start; POINT * mid;\r
+ POINT * finish; int factor;\r
+ POINT frames[]; int * nFrames;\r
+{\r
+ int n, fraction = 1, count = 0;\r
+\r
+ /* Slow in, stepping 1/16th, then 1/8th, ... */\r
+ for (n = 0; n < factor; n++)\r
+ fraction *= 2;\r
+ for (n = 0; n < factor; n++) {\r
+ frames[count].x = start->x + (mid->x - start->x) / fraction;\r
+ frames[count].y = start->y + (mid->y - start->y) / fraction;\r
+ count ++;\r
+ fraction = fraction / 2;\r
+ }\r
+ \r
+ /* Midpoint */\r
+ frames[count] = *mid;\r
+ count ++;\r
+ \r
+ /* Slow out, stepping 1/2, then 1/4, ... */\r
+ fraction = 2;\r
+ for (n = 0; n < factor; n++) {\r
+ frames[count].x = finish->x - (finish->x - mid->x) / fraction;\r
+ frames[count].y = finish->y - (finish->y - mid->y) / fraction;\r
+ count ++;\r
+ fraction = fraction * 2;\r
+ }\r
+ *nFrames = count;\r
+}\r
+\r
+void\r
+HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )\r
+{\r
+ MoveHistorySet( movelist, first, last, current, pvInfoList );\r
+\r
+ EvalGraphSet( first, last, current, pvInfoList );\r
+}\r
+\r
+void SetProgramStats( FrontEndProgramStats * stats )\r
+{\r
+ EngineOutputUpdate( stats );\r
+}\r