2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
\r
6 * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
\r
8 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
9 * which was written and is copyrighted by Wayne Christopher.
\r
11 * The following terms apply to Digital Equipment Corporation's copyright
\r
12 * interest in XBoard:
\r
13 * ------------------------------------------------------------------------
\r
14 * All Rights Reserved
\r
16 * Permission to use, copy, modify, and distribute this software and its
\r
17 * documentation for any purpose and without fee is hereby granted,
\r
18 * provided that the above copyright notice appear in all copies and that
\r
19 * both that copyright notice and this permission notice appear in
\r
20 * supporting documentation, and that the name of Digital not be
\r
21 * used in advertising or publicity pertaining to distribution of the
\r
22 * software without specific, written prior permission.
\r
24 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
25 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
26 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
27 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
28 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
29 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
31 * ------------------------------------------------------------------------
\r
33 * The following terms apply to the enhanced version of XBoard distributed
\r
34 * by the Free Software Foundation:
\r
35 * ------------------------------------------------------------------------
\r
36 * This program is free software; you can redistribute it and/or modify
\r
37 * it under the terms of the GNU General Public License as published by
\r
38 * the Free Software Foundation; either version 2 of the License, or
\r
39 * (at your option) any later version.
\r
41 * This program is distributed in the hope that it will be useful,
\r
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
44 * GNU General Public License for more details.
\r
46 * You should have received a copy of the GNU General Public License
\r
47 * along with this program; if not, write to the Free Software
\r
48 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
49 * ------------------------------------------------------------------------
\r
54 #include <windows.h>
\r
55 #include <winuser.h>
\r
56 #include <winsock.h>
\r
62 #include <sys/stat.h>
\r
65 #include <commdlg.h>
\r
67 #include <richedit.h>
\r
68 #include <mmsystem.h>
\r
76 #include "winboard.h"
\r
77 #include "frontend.h"
\r
78 #include "backend.h"
\r
80 #include "wclipbrd.h"
\r
81 #include "wgamelist.h"
\r
82 #include "wedittags.h"
\r
83 #include "woptions.h"
\r
84 #include "wsockerr.h"
\r
85 #include "defaults.h"
\r
89 void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
92 void mysrandom(unsigned int seed);
\r
94 extern int whiteFlag, blackFlag;
\r
98 POINT pos; /* window coordinates of current pos */
\r
99 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
100 POINT from; /* board coordinates of the piece's orig pos */
\r
101 POINT to; /* board coordinates of the piece's new pos */
\r
104 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
107 POINT start; /* window coordinates of start pos */
\r
108 POINT pos; /* window coordinates of current pos */
\r
109 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
110 POINT from; /* board coordinates of the piece's orig pos */
\r
113 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
116 POINT sq[2]; /* board coordinates of from, to squares */
\r
119 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
120 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
122 /* Window class names */
\r
123 char szAppName[] = "WinBoard";
\r
124 char szConsoleName[] = "WBConsole";
\r
126 /* Title bar text */
\r
127 char szTitle[] = "WinBoard";
\r
128 char szConsoleTitle[] = "ICS Interaction";
\r
131 char *settingsFileName;
\r
132 BOOLEAN saveSettingsOnExit;
\r
133 char installDir[MSG_SIZ];
\r
135 BoardSize boardSize;
\r
136 BOOLEAN chessProgram;
\r
137 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
138 static int squareSize, lineGap;
\r
139 static int winWidth, winHeight;
\r
140 static RECT messageRect, whiteRect, blackRect;
\r
141 static char messageText[MESSAGE_TEXT_MAX];
\r
142 static int clockTimerEvent = 0;
\r
143 static int loadGameTimerEvent = 0;
\r
144 static int analysisTimerEvent = 0;
\r
145 static DelayedEventCallback delayedTimerCallback;
\r
146 static int delayedTimerEvent = 0;
\r
147 static int buttonCount = 2;
\r
148 char *icsTextMenuString;
\r
150 char *firstChessProgramNames;
\r
151 char *secondChessProgramNames;
\r
153 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
155 #define PALETTESIZE 256
\r
157 HINSTANCE hInst; /* current instance */
\r
158 HWND hwndMain = NULL; /* root window*/
\r
159 HWND hwndConsole = NULL;
\r
160 BOOLEAN alwaysOnTop = FALSE;
\r
162 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
163 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
165 ColorClass currentColorClass;
\r
167 HWND hCommPort = NULL; /* currently open comm port */
\r
168 static HWND hwndPause; /* pause button */
\r
169 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
170 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
171 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
172 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
173 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
174 static HPEN gridPen = NULL;
\r
175 static HPEN highlightPen = NULL;
\r
176 static HPEN premovePen = NULL;
\r
177 static NPLOGPALETTE pLogPal;
\r
178 static BOOL paletteChanged = FALSE;
\r
179 static HICON iconWhite, iconBlack, iconCurrent;
\r
180 static int doingSizing = FALSE;
\r
181 static int lastSizing = 0;
\r
182 static int prevStderrPort;
\r
184 /* [AS] Support for background textures */
\r
185 #define BACK_TEXTURE_MODE_DISABLED 0
\r
186 #define BACK_TEXTURE_MODE_PLAIN 1
\r
187 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
189 static HBITMAP liteBackTexture = NULL;
\r
190 static HBITMAP darkBackTexture = NULL;
\r
191 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
192 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
193 static int backTextureSquareSize = 0;
\r
194 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
196 #if __GNUC__ && !defined(_winmajor)
\r
197 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
199 #define oldDialog (_winmajor < 4)
\r
202 char *defaultTextAttribs[] =
\r
204 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
205 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
215 int cliWidth, cliHeight;
\r
218 SizeInfo sizeInfo[] =
\r
220 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
221 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
222 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
223 { "petite", 33, 1, 1, 1, 0, 0 },
\r
224 { "slim", 37, 2, 1, 0, 0, 0 },
\r
225 { "small", 40, 2, 1, 0, 0, 0 },
\r
226 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
227 { "middling", 49, 2, 0, 0, 0, 0 },
\r
228 { "average", 54, 2, 0, 0, 0, 0 },
\r
229 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
230 { "medium", 64, 3, 0, 0, 0, 0 },
\r
231 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
232 { "large", 80, 3, 0, 0, 0, 0 },
\r
233 { "big", 87, 3, 0, 0, 0, 0 },
\r
234 { "huge", 95, 3, 0, 0, 0, 0 },
\r
235 { "giant", 108, 3, 0, 0, 0, 0 },
\r
236 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
237 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
238 { NULL, 0, 0, 0, 0, 0, 0 }
\r
241 #define MF(x) {x, {0, }, {0, }, 0}
\r
242 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
244 { 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
245 { 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
246 { 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
247 { 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
248 { 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
249 { 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
250 { 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
251 { 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
252 { 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
253 { 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
254 { 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
255 { 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
256 { 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
257 { 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
258 { 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
259 { 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
260 { 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
261 { 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
264 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
273 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
274 #define N_BUTTONS 5
\r
276 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
278 {"<<", IDM_ToStart, NULL, NULL},
\r
279 {"<", IDM_Backward, NULL, NULL},
\r
280 {"P", IDM_Pause, NULL, NULL},
\r
281 {">", IDM_Forward, NULL, NULL},
\r
282 {">>", IDM_ToEnd, NULL, NULL},
\r
285 int tinyLayout = 0, smallLayout = 0;
\r
286 #define MENU_BAR_ITEMS 6
\r
287 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
288 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
289 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
293 MySound sounds[(int)NSoundClasses];
\r
294 MyTextAttribs textAttribs[(int)NColorClasses];
\r
296 MyColorizeAttribs colorizeAttribs[] = {
\r
297 { (COLORREF)0, 0, "Shout Text" },
\r
298 { (COLORREF)0, 0, "SShout/CShout" },
\r
299 { (COLORREF)0, 0, "Channel 1 Text" },
\r
300 { (COLORREF)0, 0, "Channel Text" },
\r
301 { (COLORREF)0, 0, "Kibitz Text" },
\r
302 { (COLORREF)0, 0, "Tell Text" },
\r
303 { (COLORREF)0, 0, "Challenge Text" },
\r
304 { (COLORREF)0, 0, "Request Text" },
\r
305 { (COLORREF)0, 0, "Seek Text" },
\r
306 { (COLORREF)0, 0, "Normal Text" },
\r
307 { (COLORREF)0, 0, "None" }
\r
312 static char *commentTitle;
\r
313 static char *commentText;
\r
314 static int commentIndex;
\r
315 static Boolean editComment = FALSE;
\r
316 HWND commentDialog = NULL;
\r
317 BOOLEAN commentDialogUp = FALSE;
\r
318 static int commentX, commentY, commentH, commentW;
\r
320 static char *analysisTitle;
\r
321 static char *analysisText;
\r
322 HWND analysisDialog = NULL;
\r
323 BOOLEAN analysisDialogUp = FALSE;
\r
324 static int analysisX, analysisY, analysisH, analysisW;
\r
326 char errorTitle[MSG_SIZ];
\r
327 char errorMessage[2*MSG_SIZ];
\r
328 HWND errorDialog = NULL;
\r
329 BOOLEAN moveErrorMessageUp = FALSE;
\r
330 BOOLEAN consoleEcho = TRUE;
\r
331 CHARFORMAT consoleCF;
\r
332 COLORREF consoleBackgroundColor;
\r
334 char *programVersion;
\r
340 typedef int CPKind;
\r
349 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
352 #define INPUT_SOURCE_BUF_SIZE 4096
\r
354 typedef struct _InputSource {
\r
361 char buf[INPUT_SOURCE_BUF_SIZE];
\r
365 InputCallback func;
\r
366 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
370 InputSource *consoleInputSource;
\r
375 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
376 VOID ConsoleCreate();
\r
378 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
379 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
380 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
381 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
383 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
384 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
385 void ParseIcsTextMenu(char *icsTextMenuString);
\r
386 VOID PopUpMoveDialog(char firstchar);
\r
387 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
391 int GameListOptions();
\r
393 HWND moveHistoryDialog = NULL;
\r
394 BOOLEAN moveHistoryDialogUp = FALSE;
\r
396 WindowPlacement wpMoveHistory;
\r
398 HWND evalGraphDialog = NULL;
\r
399 BOOLEAN evalGraphDialogUp = FALSE;
\r
401 WindowPlacement wpEvalGraph;
\r
403 HWND engineOutputDialog = NULL;
\r
404 BOOLEAN engineOutputDialogUp = FALSE;
\r
406 WindowPlacement wpEngineOutput;
\r
408 VOID MoveHistoryPopUp();
\r
409 VOID MoveHistoryPopDown();
\r
410 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
411 BOOL MoveHistoryIsUp();
\r
413 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
414 VOID EvalGraphPopUp();
\r
415 VOID EvalGraphPopDown();
\r
416 BOOL EvalGraphIsUp();
\r
418 VOID EngineOutputPopUp();
\r
419 VOID EngineOutputPopDown();
\r
420 BOOL EngineOutputIsUp();
\r
421 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
423 VOID GothicPopUp(char *title);
\r
425 * Setting "frozen" should disable all user input other than deleting
\r
426 * the window. We do this while engines are initializing themselves.
\r
428 static int frozen = 0;
\r
429 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
435 if (frozen) return;
\r
437 hmenu = GetMenu(hwndMain);
\r
438 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
439 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
441 DrawMenuBar(hwndMain);
\r
444 /* Undo a FreezeUI */
\r
450 if (!frozen) return;
\r
452 hmenu = GetMenu(hwndMain);
\r
453 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
454 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
456 DrawMenuBar(hwndMain);
\r
459 /*---------------------------------------------------------------------------*\
\r
463 \*---------------------------------------------------------------------------*/
\r
466 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
467 LPSTR lpCmdLine, int nCmdShow)
\r
470 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
474 LoadLibrary("RICHED32.DLL");
\r
475 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
477 if (!InitApplication(hInstance)) {
\r
480 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
484 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
485 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
486 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
488 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
490 while (GetMessage(&msg, /* message structure */
\r
491 NULL, /* handle of window receiving the message */
\r
492 0, /* lowest message to examine */
\r
493 0)) /* highest message to examine */
\r
495 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
496 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
497 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
498 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
499 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
500 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
501 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
502 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
503 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
504 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
505 TranslateMessage(&msg); /* Translates virtual key codes */
\r
506 DispatchMessage(&msg); /* Dispatches message to window */
\r
511 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
514 /*---------------------------------------------------------------------------*\
\r
516 * Initialization functions
\r
518 \*---------------------------------------------------------------------------*/
\r
521 InitApplication(HINSTANCE hInstance)
\r
525 /* Fill in window class structure with parameters that describe the */
\r
528 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
529 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
530 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
531 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
532 wc.hInstance = hInstance; /* Owner of this class */
\r
533 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
534 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
535 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
536 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
537 wc.lpszClassName = szAppName; /* Name to register as */
\r
539 /* Register the window class and return success/failure code. */
\r
540 if (!RegisterClass(&wc)) return FALSE;
\r
542 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
543 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
545 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
546 wc.hInstance = hInstance;
\r
547 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
548 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
549 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
550 wc.lpszMenuName = NULL;
\r
551 wc.lpszClassName = szConsoleName;
\r
553 if (!RegisterClass(&wc)) return FALSE;
\r
558 /* Set by InitInstance, used by EnsureOnScreen */
\r
559 int screenHeight, screenWidth;
\r
562 EnsureOnScreen(int *x, int *y)
\r
564 int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
565 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
566 if (*x > screenWidth - 32) *x = 0;
\r
567 if (*y > screenHeight - 32) *y = 0;
\r
568 if (*x < 10) *x = 10;
\r
569 if (*y < gap) *y = gap;
\r
573 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
575 HWND hwnd; /* Main window handle. */
\r
577 WINDOWPLACEMENT wp;
\r
580 hInst = hInstance; /* Store instance handle in our global variable */
\r
582 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
583 *filepart = NULLCHAR;
\r
585 GetCurrentDirectory(MSG_SIZ, installDir);
\r
587 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
588 if (appData.debugMode) {
\r
589 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
590 setbuf(debugFP, NULL);
\r
595 InitEngineUCI( installDir, &first );
\r
596 InitEngineUCI( installDir, &second );
\r
598 /* Create a main window for this application instance. */
\r
599 hwnd = CreateWindow(szAppName, szTitle,
\r
600 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
601 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
602 NULL, NULL, hInstance, NULL);
\r
605 /* If window could not be created, return "failure" */
\r
610 iconWhite = LoadIcon(hInstance, "icon_white");
\r
611 iconBlack = LoadIcon(hInstance, "icon_black");
\r
612 iconCurrent = iconWhite;
\r
613 InitDrawingColors();
\r
614 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
615 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
616 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
617 /* Compute window size for each board size, and use the largest
\r
618 size that fits on this screen as the default. */
\r
619 InitDrawingSizes((BoardSize)ibs, 0);
\r
620 if (boardSize == (BoardSize)-1 &&
\r
621 winHeight <= screenHeight
\r
622 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
623 && winWidth <= screenWidth) {
\r
624 boardSize = (BoardSize)ibs;
\r
627 InitDrawingSizes(boardSize, 0);
\r
629 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
631 /* [AS] Load textures if specified */
\r
632 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
634 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
635 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
636 liteBackTextureMode = appData.liteBackTextureMode;
\r
638 if (liteBackTexture == NULL && appData.debugMode) {
\r
639 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
643 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
644 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
645 darkBackTextureMode = appData.darkBackTextureMode;
\r
647 if (darkBackTexture == NULL && appData.debugMode) {
\r
648 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
652 mysrandom( (unsigned) time(NULL) );
\r
654 /* Make a console window if needed */
\r
655 if (appData.icsActive) {
\r
659 /* [AS] Restore layout */
\r
660 if( wpMoveHistory.visible ) {
\r
661 MoveHistoryPopUp();
\r
664 if( wpEvalGraph.visible ) {
\r
668 if( wpEngineOutput.visible ) {
\r
669 EngineOutputPopUp();
\r
674 /* Make the window visible; update its client area; and return "success" */
\r
675 EnsureOnScreen(&boardX, &boardY);
\r
676 wp.length = sizeof(WINDOWPLACEMENT);
\r
678 wp.showCmd = nCmdShow;
\r
679 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
680 wp.rcNormalPosition.left = boardX;
\r
681 wp.rcNormalPosition.right = boardX + winWidth;
\r
682 wp.rcNormalPosition.top = boardY;
\r
683 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
684 SetWindowPlacement(hwndMain, &wp);
\r
686 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
687 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
689 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
690 if( gameInfo.variant != VariantFischeRandom ) {
\r
691 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
695 /* [HGM] Gothic licensing requirement */
\r
696 if(gameInfo.variant == VariantGothic)
\r
697 GothicPopUp(GOTHIC);
\r
702 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
703 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
705 ShowWindow(hwndConsole, nCmdShow);
\r
707 UpdateWindow(hwnd);
\r
715 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
716 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
717 ArgSettingsFilename
\r
725 String *pString; // ArgString
\r
726 int *pInt; // ArgInt
\r
727 float *pFloat; // ArgFloat
\r
728 Boolean *pBoolean; // ArgBoolean
\r
729 COLORREF *pColor; // ArgColor
\r
730 ColorClass cc; // ArgAttribs
\r
731 String *pFilename; // ArgFilename
\r
732 BoardSize *pBoardSize; // ArgBoardSize
\r
733 int whichFont; // ArgFont
\r
734 DCB *pDCB; // ArgCommSettings
\r
735 String *pFilename; // ArgSettingsFilename
\r
743 ArgDescriptor argDescriptors[] = {
\r
744 /* positional arguments */
\r
745 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
746 { "", ArgNone, NULL },
\r
747 /* keyword arguments */
\r
748 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
749 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
750 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
751 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
752 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
753 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
754 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
755 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
756 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
757 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
758 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
759 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
760 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
761 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
762 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
763 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
764 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
765 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
767 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
769 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
771 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
772 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
774 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
775 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
776 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
777 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
778 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
779 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
780 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
781 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
782 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
783 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
784 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
785 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
786 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
787 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
788 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
789 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
790 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
791 /*!!bitmapDirectory?*/
\r
792 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
793 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
794 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
795 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
796 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
797 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
798 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
799 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
800 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
801 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
802 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
803 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
804 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
805 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
806 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
807 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
808 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
809 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
810 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
811 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
812 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
813 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
814 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
815 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
816 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
817 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
818 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
819 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
820 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
821 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
822 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
823 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
824 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
825 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
826 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
827 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
828 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
829 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
830 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
831 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
832 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
833 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
834 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
835 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
836 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
837 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
838 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
839 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
840 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
841 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
842 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
843 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
844 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
845 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
846 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
847 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
848 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
849 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
850 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
851 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
852 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
853 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
854 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
855 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
856 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
857 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
858 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
859 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
860 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
861 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
862 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
863 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
864 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
865 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
866 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
867 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
868 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
869 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
870 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
871 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
872 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
873 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
874 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
875 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
876 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
877 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
878 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
879 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
880 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
881 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
882 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
883 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
884 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
885 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
886 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
887 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
888 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
889 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
890 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
891 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
892 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
893 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
894 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
895 TRUE }, /* must come after all fonts */
\r
896 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
897 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
898 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
899 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
900 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
901 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
902 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
903 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
904 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
905 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
906 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
907 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
908 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
909 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
910 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
911 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
912 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
913 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
914 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
915 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
916 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
917 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
918 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
919 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
920 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
921 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
922 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
923 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
924 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
925 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
926 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
928 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
929 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
931 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
932 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
933 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
934 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
935 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
936 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
937 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
938 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
939 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
940 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
941 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
942 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
943 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
944 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
945 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
946 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
947 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
948 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
949 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
950 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
951 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
952 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
953 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
954 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
955 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
956 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
957 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
958 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
959 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
960 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
961 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
962 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
963 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
964 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
965 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
966 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
967 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
968 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
969 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
970 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
971 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
972 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
973 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
974 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
975 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
976 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
977 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
978 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
979 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
980 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
981 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
982 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
983 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
984 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
985 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
986 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
987 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
988 { "highlightLastMove", ArgBoolean,
\r
989 (LPVOID) &appData.highlightLastMove, TRUE },
\r
990 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
991 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
992 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
993 { "highlightDragging", ArgBoolean,
\r
994 (LPVOID) &appData.highlightDragging, TRUE },
\r
995 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
996 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
997 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
998 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
999 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1000 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1001 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1002 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1003 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1004 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1005 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1006 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1007 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1008 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1009 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1010 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1011 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1012 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1013 { "soundShout", ArgFilename,
\r
1014 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1015 { "soundSShout", ArgFilename,
\r
1016 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1017 { "soundChannel1", ArgFilename,
\r
1018 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1019 { "soundChannel", ArgFilename,
\r
1020 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1021 { "soundKibitz", ArgFilename,
\r
1022 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1023 { "soundTell", ArgFilename,
\r
1024 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1025 { "soundChallenge", ArgFilename,
\r
1026 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1027 { "soundRequest", ArgFilename,
\r
1028 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1029 { "soundSeek", ArgFilename,
\r
1030 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1031 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1032 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1033 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1034 { "soundIcsLoss", ArgFilename,
\r
1035 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1036 { "soundIcsDraw", ArgFilename,
\r
1037 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1038 { "soundIcsUnfinished", ArgFilename,
\r
1039 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1040 { "soundIcsAlarm", ArgFilename,
\r
1041 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1042 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1043 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1044 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1045 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1046 { "reuseChessPrograms", ArgBoolean,
\r
1047 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1048 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1049 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1050 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1051 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1052 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1053 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1054 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1055 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1056 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1057 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1058 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1059 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1060 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1061 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1062 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1063 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1064 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1065 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1066 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1067 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1068 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1069 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1070 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1071 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1072 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1073 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1074 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1075 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1076 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1077 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1078 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1079 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1080 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1081 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1082 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1083 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1084 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1086 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1088 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1089 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1090 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1091 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1092 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1093 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1094 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1095 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1096 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1097 /* [AS] New features */
\r
1098 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1099 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1100 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1101 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1102 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1103 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1104 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1105 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1106 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1107 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1108 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1109 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1110 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1111 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1112 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1113 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1114 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1115 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1116 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1117 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1118 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1119 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1120 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1121 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1122 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1123 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1124 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1125 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1126 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1127 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1128 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1129 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1130 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1131 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1132 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1133 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1134 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1135 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1136 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1137 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1138 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1139 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1140 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1141 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1142 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1143 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1144 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1145 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1147 /* [AS] Layout stuff */
\r
1148 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1149 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1150 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1151 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1152 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1154 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1155 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1156 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1157 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1158 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1160 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1161 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1162 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1163 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1164 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1166 /* [HGM] User-selectable board size */
\r
1167 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1168 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1169 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, FALSE },
\r
1170 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1171 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1172 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1175 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1176 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1177 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1178 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1179 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1180 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1181 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1182 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1183 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1184 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1185 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1186 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1187 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1189 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1190 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1191 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1192 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1193 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1194 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1195 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1197 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1198 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1199 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1200 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1201 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1202 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1203 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1204 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1205 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1206 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1207 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1208 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1209 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1210 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1211 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1212 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1213 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1214 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1216 { NULL, ArgNone, NULL, FALSE }
\r
1220 /* Kludge for indirection files on command line */
\r
1221 char* lastIndirectionFilename;
\r
1222 ArgDescriptor argDescriptorIndirection =
\r
1223 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1227 ExitArgError(char *msg, char *badArg)
\r
1229 char buf[MSG_SIZ];
\r
1231 sprintf(buf, "%s %s", msg, badArg);
\r
1232 DisplayFatalError(buf, 0, 2);
\r
1236 /* Command line font name parser. NULL name means do nothing.
\r
1237 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1238 For backward compatibility, syntax without the colon is also
\r
1239 accepted, but font names with digits in them won't work in that case.
\r
1242 ParseFontName(char *name, MyFontParams *mfp)
\r
1245 if (name == NULL) return;
\r
1247 q = strchr(p, ':');
\r
1249 if (q - p >= sizeof(mfp->faceName))
\r
1250 ExitArgError("Font name too long:", name);
\r
1251 memcpy(mfp->faceName, p, q - p);
\r
1252 mfp->faceName[q - p] = NULLCHAR;
\r
1255 q = mfp->faceName;
\r
1256 while (*p && !isdigit(*p)) {
\r
1258 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1259 ExitArgError("Font name too long:", name);
\r
1261 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1264 if (!*p) ExitArgError("Font point size missing:", name);
\r
1265 mfp->pointSize = (float) atof(p);
\r
1266 mfp->bold = (strchr(p, 'b') != NULL);
\r
1267 mfp->italic = (strchr(p, 'i') != NULL);
\r
1268 mfp->underline = (strchr(p, 'u') != NULL);
\r
1269 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1272 /* Color name parser.
\r
1273 X version accepts X color names, but this one
\r
1274 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1276 ParseColorName(char *name)
\r
1278 int red, green, blue, count;
\r
1279 char buf[MSG_SIZ];
\r
1281 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1283 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1284 &red, &green, &blue);
\r
1287 sprintf(buf, "Can't parse color name %s", name);
\r
1288 DisplayError(buf, 0);
\r
1289 return RGB(0, 0, 0);
\r
1291 return PALETTERGB(red, green, blue);
\r
1295 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1297 char *e = argValue;
\r
1301 if (*e == 'b') eff |= CFE_BOLD;
\r
1302 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1303 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1304 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1305 else if (*e == '#' || isdigit(*e)) break;
\r
1309 *color = ParseColorName(e);
\r
1314 ParseBoardSize(char *name)
\r
1316 BoardSize bs = SizeTiny;
\r
1317 while (sizeInfo[bs].name != NULL) {
\r
1318 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1321 ExitArgError("Unrecognized board size value", name);
\r
1322 return bs; /* not reached */
\r
1327 StringGet(void *getClosure)
\r
1329 char **p = (char **) getClosure;
\r
1334 FileGet(void *getClosure)
\r
1337 FILE* f = (FILE*) getClosure;
\r
1346 /* Parse settings file named "name". If file found, return the
\r
1347 full name in fullname and return TRUE; else return FALSE */
\r
1349 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1354 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1355 f = fopen(fullname, "r");
\r
1357 ParseArgs(FileGet, f);
\r
1366 ParseArgs(GetFunc get, void *cl)
\r
1368 char argName[ARG_MAX];
\r
1369 char argValue[ARG_MAX];
\r
1370 ArgDescriptor *ad;
\r
1379 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1380 if (ch == NULLCHAR) break;
\r
1382 /* Comment to end of line */
\r
1384 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1386 } else if (ch == '/' || ch == '-') {
\r
1389 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1390 ch != '\n' && ch != '\t') {
\r
1396 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1397 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1399 if (ad->argName == NULL)
\r
1400 ExitArgError("Unrecognized argument", argName);
\r
1402 } else if (ch == '@') {
\r
1403 /* Indirection file */
\r
1404 ad = &argDescriptorIndirection;
\r
1407 /* Positional argument */
\r
1408 ad = &argDescriptors[posarg++];
\r
1409 strcpy(argName, ad->argName);
\r
1412 if (ad->argType == ArgTrue) {
\r
1413 *(Boolean *) ad->argLoc = TRUE;
\r
1416 if (ad->argType == ArgFalse) {
\r
1417 *(Boolean *) ad->argLoc = FALSE;
\r
1421 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1422 if (ch == NULLCHAR || ch == '\n') {
\r
1423 ExitArgError("No value provided for argument", argName);
\r
1427 // Quoting with { }. No characters have to (or can) be escaped.
\r
1428 // Thus the string cannot contain a '}' character.
\r
1448 } else if (ch == '\'' || ch == '"') {
\r
1449 // Quoting with ' ' or " ", with \ as escape character.
\r
1450 // Inconvenient for long strings that may contain Windows filenames.
\r
1467 if (ch == start) {
\r
1476 if (ad->argType == ArgFilename
\r
1477 || ad->argType == ArgSettingsFilename) {
\r
1483 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1507 for (i = 0; i < 3; i++) {
\r
1508 if (ch >= '0' && ch <= '7') {
\r
1509 octval = octval*8 + (ch - '0');
\r
1516 *q++ = (char) octval;
\r
1527 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1534 switch (ad->argType) {
\r
1536 *(int *) ad->argLoc = atoi(argValue);
\r
1540 *(float *) ad->argLoc = (float) atof(argValue);
\r
1545 *(char **) ad->argLoc = strdup(argValue);
\r
1548 case ArgSettingsFilename:
\r
1550 char fullname[MSG_SIZ];
\r
1551 if (ParseSettingsFile(argValue, fullname)) {
\r
1552 if (ad->argLoc != NULL) {
\r
1553 *(char **) ad->argLoc = strdup(fullname);
\r
1556 if (ad->argLoc != NULL) {
\r
1558 ExitArgError("Failed to open indirection file", argValue);
\r
1565 switch (argValue[0]) {
\r
1568 *(Boolean *) ad->argLoc = TRUE;
\r
1572 *(Boolean *) ad->argLoc = FALSE;
\r
1575 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1581 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1584 case ArgAttribs: {
\r
1585 ColorClass cc = (ColorClass)ad->argLoc;
\r
1586 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1590 case ArgBoardSize:
\r
1591 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1595 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1598 case ArgCommSettings:
\r
1599 ParseCommSettings(argValue, &dcb);
\r
1603 ExitArgError("Unrecognized argument", argValue);
\r
1610 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1612 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1613 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1616 lf->lfEscapement = 0;
\r
1617 lf->lfOrientation = 0;
\r
1618 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1619 lf->lfItalic = mfp->italic;
\r
1620 lf->lfUnderline = mfp->underline;
\r
1621 lf->lfStrikeOut = mfp->strikeout;
\r
1622 lf->lfCharSet = DEFAULT_CHARSET;
\r
1623 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1624 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1625 lf->lfQuality = DEFAULT_QUALITY;
\r
1626 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1627 strcpy(lf->lfFaceName, mfp->faceName);
\r
1631 CreateFontInMF(MyFont *mf)
\r
1633 LFfromMFP(&mf->lf, &mf->mfp);
\r
1634 if (mf->hf) DeleteObject(mf->hf);
\r
1635 mf->hf = CreateFontIndirect(&mf->lf);
\r
1639 SetDefaultTextAttribs()
\r
1642 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1643 ParseAttribs(&textAttribs[cc].color,
\r
1644 &textAttribs[cc].effects,
\r
1645 defaultTextAttribs[cc]);
\r
1650 SetDefaultSounds()
\r
1654 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1655 textAttribs[cc].sound.name = strdup("");
\r
1656 textAttribs[cc].sound.data = NULL;
\r
1658 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1659 sounds[sc].name = strdup("");
\r
1660 sounds[sc].data = NULL;
\r
1662 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1670 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1671 MyLoadSound(&textAttribs[cc].sound);
\r
1673 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1674 MyLoadSound(&sounds[sc]);
\r
1679 InitAppData(LPSTR lpCmdLine)
\r
1682 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1685 programName = szAppName;
\r
1687 /* Initialize to defaults */
\r
1688 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1689 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1690 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1691 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1692 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1693 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1694 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1695 SetDefaultTextAttribs();
\r
1696 SetDefaultSounds();
\r
1697 appData.movesPerSession = MOVES_PER_SESSION;
\r
1698 appData.initString = INIT_STRING;
\r
1699 appData.secondInitString = INIT_STRING;
\r
1700 appData.firstComputerString = COMPUTER_STRING;
\r
1701 appData.secondComputerString = COMPUTER_STRING;
\r
1702 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1703 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1704 appData.firstPlaysBlack = FALSE;
\r
1705 appData.noChessProgram = FALSE;
\r
1706 chessProgram = FALSE;
\r
1707 appData.firstHost = FIRST_HOST;
\r
1708 appData.secondHost = SECOND_HOST;
\r
1709 appData.firstDirectory = FIRST_DIRECTORY;
\r
1710 appData.secondDirectory = SECOND_DIRECTORY;
\r
1711 appData.bitmapDirectory = "";
\r
1712 appData.remoteShell = REMOTE_SHELL;
\r
1713 appData.remoteUser = "";
\r
1714 appData.timeDelay = TIME_DELAY;
\r
1715 appData.timeControl = TIME_CONTROL;
\r
1716 appData.timeIncrement = TIME_INCREMENT;
\r
1717 appData.icsActive = FALSE;
\r
1718 appData.icsHost = "";
\r
1719 appData.icsPort = ICS_PORT;
\r
1720 appData.icsCommPort = ICS_COMM_PORT;
\r
1721 appData.icsLogon = ICS_LOGON;
\r
1722 appData.icsHelper = "";
\r
1723 appData.useTelnet = FALSE;
\r
1724 appData.telnetProgram = TELNET_PROGRAM;
\r
1725 appData.gateway = "";
\r
1726 appData.loadGameFile = "";
\r
1727 appData.loadGameIndex = 0;
\r
1728 appData.saveGameFile = "";
\r
1729 appData.autoSaveGames = FALSE;
\r
1730 appData.loadPositionFile = "";
\r
1731 appData.loadPositionIndex = 1;
\r
1732 appData.savePositionFile = "";
\r
1733 appData.matchMode = FALSE;
\r
1734 appData.matchGames = 0;
\r
1735 appData.monoMode = FALSE;
\r
1736 appData.debugMode = FALSE;
\r
1737 appData.clockMode = TRUE;
\r
1738 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1739 appData.Iconic = FALSE; /*unused*/
\r
1740 appData.searchTime = "";
\r
1741 appData.searchDepth = 0;
\r
1742 appData.showCoords = FALSE;
\r
1743 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1744 appData.autoCallFlag = FALSE;
\r
1745 appData.flipView = FALSE;
\r
1746 appData.autoFlipView = TRUE;
\r
1747 appData.cmailGameName = "";
\r
1748 appData.alwaysPromoteToQueen = FALSE;
\r
1749 appData.oldSaveStyle = FALSE;
\r
1750 appData.quietPlay = FALSE;
\r
1751 appData.showThinking = FALSE;
\r
1752 appData.ponderNextMove = TRUE;
\r
1753 appData.periodicUpdates = TRUE;
\r
1754 appData.popupExitMessage = TRUE;
\r
1755 appData.popupMoveErrors = FALSE;
\r
1756 appData.autoObserve = FALSE;
\r
1757 appData.autoComment = FALSE;
\r
1758 appData.animate = TRUE;
\r
1759 appData.animSpeed = 10;
\r
1760 appData.animateDragging = TRUE;
\r
1761 appData.highlightLastMove = TRUE;
\r
1762 appData.getMoveList = TRUE;
\r
1763 appData.testLegality = TRUE;
\r
1764 appData.premove = TRUE;
\r
1765 appData.premoveWhite = FALSE;
\r
1766 appData.premoveWhiteText = "";
\r
1767 appData.premoveBlack = FALSE;
\r
1768 appData.premoveBlackText = "";
\r
1769 appData.icsAlarm = TRUE;
\r
1770 appData.icsAlarmTime = 5000;
\r
1771 appData.autoRaiseBoard = TRUE;
\r
1772 appData.localLineEditing = TRUE;
\r
1773 appData.colorize = TRUE;
\r
1774 appData.reuseFirst = TRUE;
\r
1775 appData.reuseSecond = TRUE;
\r
1776 appData.blindfold = FALSE;
\r
1777 dcb.DCBlength = sizeof(DCB);
\r
1778 dcb.BaudRate = 9600;
\r
1779 dcb.fBinary = TRUE;
\r
1780 dcb.fParity = FALSE;
\r
1781 dcb.fOutxCtsFlow = FALSE;
\r
1782 dcb.fOutxDsrFlow = FALSE;
\r
1783 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1784 dcb.fDsrSensitivity = FALSE;
\r
1785 dcb.fTXContinueOnXoff = TRUE;
\r
1786 dcb.fOutX = FALSE;
\r
1788 dcb.fNull = FALSE;
\r
1789 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1790 dcb.fAbortOnError = FALSE;
\r
1791 dcb.wReserved = 0;
\r
1793 dcb.Parity = SPACEPARITY;
\r
1794 dcb.StopBits = ONESTOPBIT;
\r
1795 settingsFileName = SETTINGS_FILE;
\r
1796 saveSettingsOnExit = TRUE;
\r
1797 boardX = CW_USEDEFAULT;
\r
1798 boardY = CW_USEDEFAULT;
\r
1799 consoleX = CW_USEDEFAULT;
\r
1800 consoleY = CW_USEDEFAULT;
\r
1801 consoleW = CW_USEDEFAULT;
\r
1802 consoleH = CW_USEDEFAULT;
\r
1803 analysisX = CW_USEDEFAULT;
\r
1804 analysisY = CW_USEDEFAULT;
\r
1805 analysisW = CW_USEDEFAULT;
\r
1806 analysisH = CW_USEDEFAULT;
\r
1807 commentX = CW_USEDEFAULT;
\r
1808 commentY = CW_USEDEFAULT;
\r
1809 commentW = CW_USEDEFAULT;
\r
1810 commentH = CW_USEDEFAULT;
\r
1811 editTagsX = CW_USEDEFAULT;
\r
1812 editTagsY = CW_USEDEFAULT;
\r
1813 editTagsW = CW_USEDEFAULT;
\r
1814 editTagsH = CW_USEDEFAULT;
\r
1815 gameListX = CW_USEDEFAULT;
\r
1816 gameListY = CW_USEDEFAULT;
\r
1817 gameListW = CW_USEDEFAULT;
\r
1818 gameListH = CW_USEDEFAULT;
\r
1819 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1820 icsNames = ICS_NAMES;
\r
1821 firstChessProgramNames = FCP_NAMES;
\r
1822 secondChessProgramNames = SCP_NAMES;
\r
1823 appData.initialMode = "";
\r
1824 appData.variant = "normal";
\r
1825 appData.firstProtocolVersion = PROTOVER;
\r
1826 appData.secondProtocolVersion = PROTOVER;
\r
1827 appData.showButtonBar = TRUE;
\r
1829 /* [AS] New properties (see comments in header file) */
\r
1830 appData.firstScoreIsAbsolute = FALSE;
\r
1831 appData.secondScoreIsAbsolute = FALSE;
\r
1832 appData.saveExtendedInfoInPGN = FALSE;
\r
1833 appData.hideThinkingFromHuman = FALSE;
\r
1834 appData.liteBackTextureFile = "";
\r
1835 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1836 appData.darkBackTextureFile = "";
\r
1837 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1838 appData.renderPiecesWithFont = "";
\r
1839 appData.fontToPieceTable = "";
\r
1840 appData.fontBackColorWhite = 0;
\r
1841 appData.fontForeColorWhite = 0;
\r
1842 appData.fontBackColorBlack = 0;
\r
1843 appData.fontForeColorBlack = 0;
\r
1844 appData.fontPieceSize = 80;
\r
1845 appData.overrideLineGap = 1;
\r
1846 appData.adjudicateLossThreshold = 0;
\r
1847 appData.delayBeforeQuit = 0;
\r
1848 appData.delayAfterQuit = 0;
\r
1849 appData.nameOfDebugFile = "winboard.debug";
\r
1850 appData.pgnEventHeader = "Computer Chess Game";
\r
1851 appData.defaultFrcPosition = -1;
\r
1852 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1853 appData.saveOutOfBookInfo = TRUE;
\r
1854 appData.showEvalInMoveHistory = TRUE;
\r
1855 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1856 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1857 appData.highlightMoveWithArrow = FALSE;
\r
1858 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1859 appData.useStickyWindows = TRUE;
\r
1860 appData.adjudicateDrawMoves = 0;
\r
1861 appData.autoDisplayComment = TRUE;
\r
1862 appData.autoDisplayTags = TRUE;
\r
1863 appData.firstIsUCI = FALSE;
\r
1864 appData.secondIsUCI = FALSE;
\r
1865 appData.firstHasOwnBookUCI = TRUE;
\r
1866 appData.secondHasOwnBookUCI = TRUE;
\r
1867 appData.polyglotDir = "";
\r
1868 appData.usePolyglotBook = FALSE;
\r
1869 appData.polyglotBook = "";
\r
1870 appData.defaultHashSize = 64;
\r
1871 appData.defaultCacheSizeEGTB = 4;
\r
1872 appData.defaultPathEGTB = "c:\\egtb";
\r
1874 InitWindowPlacement( &wpMoveHistory );
\r
1875 InitWindowPlacement( &wpEvalGraph );
\r
1876 InitWindowPlacement( &wpEngineOutput );
\r
1878 /* [HGM] User-selectable board size */
\r
1879 appData.NrFiles = 8;
\r
1880 appData.NrRanks = 8;
\r
1881 appData.matchPause = 10000;
\r
1882 appData.testClaims = FALSE;
\r
1883 appData.ruleMoves = 51;
\r
1884 appData.drawRepeats = 6;
\r
1887 appData.zippyTalk = ZIPPY_TALK;
\r
1888 appData.zippyPlay = ZIPPY_PLAY;
\r
1889 appData.zippyLines = ZIPPY_LINES;
\r
1890 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1891 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1892 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1893 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1894 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1895 appData.zippyUseI = ZIPPY_USE_I;
\r
1896 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1897 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1898 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1899 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1900 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1901 appData.zippyAbort = ZIPPY_ABORT;
\r
1902 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1903 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1904 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1907 /* Point font array elements to structures and
\r
1908 parse default font names */
\r
1909 for (i=0; i<NUM_FONTS; i++) {
\r
1910 for (j=0; j<NUM_SIZES; j++) {
\r
1911 font[j][i] = &fontRec[j][i];
\r
1912 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1916 /* Parse default settings file if any */
\r
1917 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1918 settingsFileName = strdup(buf);
\r
1921 /* Parse command line */
\r
1922 ParseArgs(StringGet, &lpCmdLine);
\r
1924 /* [HGM] make sure board size is acceptable */
\r
1925 if(appData.NrFiles > BOARD_SIZE ||
\r
1926 appData.NrRanks > BOARD_SIZE )
\r
1927 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
1929 /* Propagate options that affect others */
\r
1930 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1931 if (appData.icsActive || appData.noChessProgram) {
\r
1932 chessProgram = FALSE; /* not local chess program mode */
\r
1935 /* Open startup dialog if needed */
\r
1936 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1937 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1938 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1939 *appData.secondChessProgram == NULLCHAR))) {
\r
1942 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1943 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1944 FreeProcInstance(lpProc);
\r
1947 /* Make sure save files land in the right (?) directory */
\r
1948 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1949 appData.saveGameFile = strdup(buf);
\r
1951 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1952 appData.savePositionFile = strdup(buf);
\r
1955 /* Finish initialization for fonts and sounds */
\r
1956 for (i=0; i<NUM_FONTS; i++) {
\r
1957 for (j=0; j<NUM_SIZES; j++) {
\r
1958 CreateFontInMF(font[j][i]);
\r
1961 /* xboard, and older WinBoards, controlled the move sound with the
\r
1962 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1963 always turn the option on (so that the backend will call us),
\r
1964 then let the user turn the sound off by setting it to silence if
\r
1965 desired. To accommodate old winboard.ini files saved by old
\r
1966 versions of WinBoard, we also turn off the sound if the option
\r
1967 was initially set to false. */
\r
1968 if (!appData.ringBellAfterMoves) {
\r
1969 sounds[(int)SoundMove].name = strdup("");
\r
1970 appData.ringBellAfterMoves = TRUE;
\r
1972 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1973 SetCurrentDirectory(installDir);
\r
1975 SetCurrentDirectory(currDir);
\r
1977 p = icsTextMenuString;
\r
1978 if (p[0] == '@') {
\r
1979 FILE* f = fopen(p + 1, "r");
\r
1981 DisplayFatalError(p + 1, errno, 2);
\r
1984 i = fread(buf, 1, sizeof(buf)-1, f);
\r
1986 buf[i] = NULLCHAR;
\r
1989 ParseIcsTextMenu(strdup(p));
\r
1996 HMENU hmenu = GetMenu(hwndMain);
\r
1998 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1999 MF_BYCOMMAND|((appData.icsActive &&
\r
2000 *appData.icsCommPort != NULLCHAR) ?
\r
2001 MF_ENABLED : MF_GRAYED));
\r
2002 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2003 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2004 MF_CHECKED : MF_UNCHECKED));
\r
2009 SaveSettings(char* name)
\r
2012 ArgDescriptor *ad;
\r
2013 WINDOWPLACEMENT wp;
\r
2014 char dir[MSG_SIZ];
\r
2016 if (!hwndMain) return;
\r
2018 GetCurrentDirectory(MSG_SIZ, dir);
\r
2019 SetCurrentDirectory(installDir);
\r
2020 f = fopen(name, "w");
\r
2021 SetCurrentDirectory(dir);
\r
2023 DisplayError(name, errno);
\r
2026 fprintf(f, ";\n");
\r
2027 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2028 fprintf(f, ";\n");
\r
2029 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2030 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2031 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2032 fprintf(f, ";\n");
\r
2034 wp.length = sizeof(WINDOWPLACEMENT);
\r
2035 GetWindowPlacement(hwndMain, &wp);
\r
2036 boardX = wp.rcNormalPosition.left;
\r
2037 boardY = wp.rcNormalPosition.top;
\r
2039 if (hwndConsole) {
\r
2040 GetWindowPlacement(hwndConsole, &wp);
\r
2041 consoleX = wp.rcNormalPosition.left;
\r
2042 consoleY = wp.rcNormalPosition.top;
\r
2043 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2044 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2047 if (analysisDialog) {
\r
2048 GetWindowPlacement(analysisDialog, &wp);
\r
2049 analysisX = wp.rcNormalPosition.left;
\r
2050 analysisY = wp.rcNormalPosition.top;
\r
2051 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2052 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2055 if (commentDialog) {
\r
2056 GetWindowPlacement(commentDialog, &wp);
\r
2057 commentX = wp.rcNormalPosition.left;
\r
2058 commentY = wp.rcNormalPosition.top;
\r
2059 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2060 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2063 if (editTagsDialog) {
\r
2064 GetWindowPlacement(editTagsDialog, &wp);
\r
2065 editTagsX = wp.rcNormalPosition.left;
\r
2066 editTagsY = wp.rcNormalPosition.top;
\r
2067 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2068 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2071 if (gameListDialog) {
\r
2072 GetWindowPlacement(gameListDialog, &wp);
\r
2073 gameListX = wp.rcNormalPosition.left;
\r
2074 gameListY = wp.rcNormalPosition.top;
\r
2075 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2076 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2079 /* [AS] Move history */
\r
2080 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2082 if( moveHistoryDialog ) {
\r
2083 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2084 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2085 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2086 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2087 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2090 /* [AS] Eval graph */
\r
2091 wpEvalGraph.visible = EvalGraphIsUp();
\r
2093 if( evalGraphDialog ) {
\r
2094 GetWindowPlacement(evalGraphDialog, &wp);
\r
2095 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2096 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2097 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2098 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2101 /* [AS] Engine output */
\r
2102 wpEngineOutput.visible = EngineOutputIsUp();
\r
2104 if( engineOutputDialog ) {
\r
2105 GetWindowPlacement(engineOutputDialog, &wp);
\r
2106 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2107 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2108 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2109 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2112 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2113 if (!ad->save) continue;
\r
2114 switch (ad->argType) {
\r
2117 char *p = *(char **)ad->argLoc;
\r
2118 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2119 /* Quote multiline values or \-containing values
\r
2120 with { } if possible */
\r
2121 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2123 /* Else quote with " " */
\r
2124 fprintf(f, "/%s=\"", ad->argName);
\r
2126 if (*p == '\n') fprintf(f, "\n");
\r
2127 else if (*p == '\r') fprintf(f, "\\r");
\r
2128 else if (*p == '\t') fprintf(f, "\\t");
\r
2129 else if (*p == '\b') fprintf(f, "\\b");
\r
2130 else if (*p == '\f') fprintf(f, "\\f");
\r
2131 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2132 else if (*p == '\"') fprintf(f, "\\\"");
\r
2133 else if (*p == '\\') fprintf(f, "\\\\");
\r
2137 fprintf(f, "\"\n");
\r
2142 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2145 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2148 fprintf(f, "/%s=%s\n", ad->argName,
\r
2149 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2152 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2155 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2159 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2160 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2161 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2166 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2167 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2168 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2169 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2170 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2171 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2172 (ta->effects) ? " " : "",
\r
2173 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2177 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2178 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2180 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2183 case ArgBoardSize:
\r
2184 fprintf(f, "/%s=%s\n", ad->argName,
\r
2185 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2190 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2191 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2192 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2193 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2194 ad->argName, mfp->faceName, mfp->pointSize,
\r
2195 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2196 mfp->bold ? "b" : "",
\r
2197 mfp->italic ? "i" : "",
\r
2198 mfp->underline ? "u" : "",
\r
2199 mfp->strikeout ? "s" : "");
\r
2203 case ArgCommSettings:
\r
2204 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2212 /*---------------------------------------------------------------------------*\
\r
2214 * GDI board drawing routines
\r
2216 \*---------------------------------------------------------------------------*/
\r
2218 /* [AS] Draw square using background texture */
\r
2219 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2224 return; /* Should never happen! */
\r
2227 SetGraphicsMode( dst, GM_ADVANCED );
\r
2234 /* X reflection */
\r
2239 x.eDx = (FLOAT) dw + dx - 1;
\r
2242 SetWorldTransform( dst, &x );
\r
2245 /* Y reflection */
\r
2251 x.eDy = (FLOAT) dh + dy - 1;
\r
2253 SetWorldTransform( dst, &x );
\r
2261 x.eDx = (FLOAT) dx;
\r
2262 x.eDy = (FLOAT) dy;
\r
2265 SetWorldTransform( dst, &x );
\r
2269 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2277 SetWorldTransform( dst, &x );
\r
2279 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2282 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2284 PM_WP = (int) WhitePawn,
\r
2285 PM_WN = (int) WhiteKnight,
\r
2286 PM_WB = (int) WhiteBishop,
\r
2287 PM_WR = (int) WhiteRook,
\r
2289 PM_WA = (int) WhiteCardinal,
\r
2290 PM_WC = (int) WhiteMarshall,
\r
2291 PM_WFP = (int) WhiteFairyPawn,
\r
2292 PM_WFN = (int) WhiteFairyKnight,
\r
2293 PM_WFB = (int) WhiteFairyBishop,
\r
2294 PM_WFR = (int) WhiteFairyRook,
\r
2295 PM_WFA = (int) WhiteFairyCardinal,
\r
2296 PM_WFC = (int) WhiteFairyMarshall,
\r
2297 PM_WFQ = (int) WhiteFairyQueen,
\r
2298 PM_WFK = (int) WhiteFairyKing,
\r
2300 PM_WQ = (int) WhiteQueen,
\r
2301 PM_WK = (int) WhiteKing,
\r
2302 PM_BP = (int) BlackPawn,
\r
2303 PM_BN = (int) BlackKnight,
\r
2304 PM_BB = (int) BlackBishop,
\r
2305 PM_BR = (int) BlackRook,
\r
2307 PM_BA = (int) BlackCardinal,
\r
2308 PM_BC = (int) BlackMarshall,
\r
2309 PM_BFP = (int) BlackFairyPawn,
\r
2310 PM_BFN = (int) BlackFairyKnight,
\r
2311 PM_BFB = (int) BlackFairyBishop,
\r
2312 PM_BFR = (int) BlackFairyRook,
\r
2313 PM_BFA = (int) BlackFairyCardinal,
\r
2314 PM_BFC = (int) BlackFairyMarshall,
\r
2315 PM_BFQ = (int) BlackFairyQueen,
\r
2316 PM_BFK = (int) BlackFairyKing,
\r
2318 PM_BQ = (int) BlackQueen,
\r
2319 PM_BK = (int) BlackKing
\r
2322 static HFONT hPieceFont = NULL;
\r
2323 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2324 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2325 static int fontBitmapSquareSize = 0;
\r
2326 static char pieceToFontChar[(int) EmptySquare] =
\r
2327 { 'p', 'n', 'b', 'r',
\r
2329 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2331 'q', 'k', 'o', 'm', 'v', 't',
\r
2333 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2337 static BOOL SetPieceToFontCharTable( const char * map )
\r
2339 BOOL result = FALSE; int NrPieces;
\r
2341 if( map != NULL && (NrPieces=strlen(map)) <= (int) EmptySquare
\r
2342 && NrPieces >= 12 && !(NrPieces&1)) {
\r
2343 int i; /* [HGM] Accept even length from 12 to 32 */
\r
2345 for( i=0; i<(int) EmptySquare; i++ ) pieceToFontChar[i] = 0;
\r
2346 for( i=0; i<NrPieces/2-2; i++ ) {
\r
2347 pieceToFontChar[i] = map[i];
\r
2348 pieceToFontChar[i + (int)BlackPawn - (int) WhitePawn] = map[i+NrPieces/2];
\r
2350 pieceToFontChar[(int) WhiteQueen] = map[NrPieces/2-2];
\r
2351 pieceToFontChar[(int) WhiteKing] = map[NrPieces/2-1];
\r
2352 pieceToFontChar[(int) BlackQueen] = map[NrPieces-2];
\r
2353 pieceToFontChar[(int) BlackKing] = map[NrPieces-1];
\r
2361 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2364 BYTE r1 = GetRValue( color );
\r
2365 BYTE g1 = GetGValue( color );
\r
2366 BYTE b1 = GetBValue( color );
\r
2372 /* Create a uniform background first */
\r
2373 hbrush = CreateSolidBrush( color );
\r
2374 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2375 FillRect( hdc, &rc, hbrush );
\r
2376 DeleteObject( hbrush );
\r
2379 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2380 int steps = squareSize / 2;
\r
2383 for( i=0; i<steps; i++ ) {
\r
2384 BYTE r = r1 - (r1-r2) * i / steps;
\r
2385 BYTE g = g1 - (g1-g2) * i / steps;
\r
2386 BYTE b = b1 - (b1-b2) * i / steps;
\r
2388 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2389 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2390 FillRect( hdc, &rc, hbrush );
\r
2391 DeleteObject(hbrush);
\r
2394 else if( mode == 2 ) {
\r
2395 /* Diagonal gradient, good more or less for every piece */
\r
2396 POINT triangle[3];
\r
2397 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2398 HBRUSH hbrush_old;
\r
2399 int steps = squareSize;
\r
2402 triangle[0].x = squareSize - steps;
\r
2403 triangle[0].y = squareSize;
\r
2404 triangle[1].x = squareSize;
\r
2405 triangle[1].y = squareSize;
\r
2406 triangle[2].x = squareSize;
\r
2407 triangle[2].y = squareSize - steps;
\r
2409 for( i=0; i<steps; i++ ) {
\r
2410 BYTE r = r1 - (r1-r2) * i / steps;
\r
2411 BYTE g = g1 - (g1-g2) * i / steps;
\r
2412 BYTE b = b1 - (b1-b2) * i / steps;
\r
2414 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2415 hbrush_old = SelectObject( hdc, hbrush );
\r
2416 Polygon( hdc, triangle, 3 );
\r
2417 SelectObject( hdc, hbrush_old );
\r
2418 DeleteObject(hbrush);
\r
2423 SelectObject( hdc, hpen );
\r
2428 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2429 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2430 piece: follow the steps as explained below.
\r
2432 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2436 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2440 int backColor = whitePieceColor;
\r
2441 int foreColor = blackPieceColor;
\r
2442 int shapeIndex = index < 6 ? index+6 : index;
\r
2444 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2445 backColor = appData.fontBackColorWhite;
\r
2446 foreColor = appData.fontForeColorWhite;
\r
2448 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2449 backColor = appData.fontBackColorBlack;
\r
2450 foreColor = appData.fontForeColorBlack;
\r
2454 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2456 hbm_old = SelectObject( hdc, hbm );
\r
2460 rc.right = squareSize;
\r
2461 rc.bottom = squareSize;
\r
2463 /* Step 1: background is now black */
\r
2464 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2466 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2468 pt.x = (squareSize - sz.cx) / 2;
\r
2469 pt.y = (squareSize - sz.cy) / 2;
\r
2471 SetBkMode( hdc, TRANSPARENT );
\r
2472 SetTextColor( hdc, chroma );
\r
2473 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2474 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2476 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2477 /* Step 3: the area outside the piece is filled with white */
\r
2478 FloodFill( hdc, 0, 0, chroma );
\r
2479 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2481 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2482 but if the start point is not inside the piece we're lost!
\r
2483 There should be a better way to do this... if we could create a region or path
\r
2484 from the fill operation we would be fine for example.
\r
2486 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2488 SetTextColor( hdc, 0 );
\r
2490 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2491 draw the piece again in black for safety.
\r
2493 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2495 SelectObject( hdc, hbm_old );
\r
2497 if( hPieceMask[index] != NULL ) {
\r
2498 DeleteObject( hPieceMask[index] );
\r
2501 hPieceMask[index] = hbm;
\r
2504 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2506 SelectObject( hdc, hbm );
\r
2509 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2510 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2511 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2513 SelectObject( dc1, hPieceMask[index] );
\r
2514 SelectObject( dc2, bm2 );
\r
2515 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2516 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2519 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2520 the piece background and deletes (makes transparent) the rest.
\r
2521 Thanks to that mask, we are free to paint the background with the greates
\r
2522 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2523 We use this, to make gradients and give the pieces a "roundish" look.
\r
2525 SetPieceBackground( hdc, backColor, 2 );
\r
2526 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2530 DeleteObject( bm2 );
\r
2533 SetTextColor( hdc, foreColor );
\r
2534 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2536 SelectObject( hdc, hbm_old );
\r
2538 if( hPieceFace[index] != NULL ) {
\r
2539 DeleteObject( hPieceFace[index] );
\r
2542 hPieceFace[index] = hbm;
\r
2545 static int TranslatePieceToFontPiece( int piece )
\r
2573 case BlackCardinal:
\r
2575 case BlackMarshall:
\r
2577 case BlackFairyPawn:
\r
2579 case BlackFairyKnight:
\r
2581 case BlackFairyBishop:
\r
2583 case BlackFairyRook:
\r
2585 case BlackFairyCardinal:
\r
2587 case BlackFairyMarshall:
\r
2589 case BlackFairyQueen:
\r
2591 case BlackFairyKing:
\r
2593 case WhiteCardinal:
\r
2595 case WhiteMarshall:
\r
2597 case WhiteFairyPawn:
\r
2599 case WhiteFairyKnight:
\r
2601 case WhiteFairyBishop:
\r
2603 case WhiteFairyRook:
\r
2605 case WhiteFairyCardinal:
\r
2607 case WhiteFairyMarshall:
\r
2609 case WhiteFairyQueen:
\r
2611 case WhiteFairyKing:
\r
2619 void CreatePiecesFromFont()
\r
2622 HDC hdc_window = NULL;
\r
2628 if( fontBitmapSquareSize < 0 ) {
\r
2629 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2633 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2634 fontBitmapSquareSize = -1;
\r
2638 if( fontBitmapSquareSize != squareSize ) {
\r
2639 hdc_window = GetDC( hwndMain );
\r
2640 hdc = CreateCompatibleDC( hdc_window );
\r
2642 if( hPieceFont != NULL ) {
\r
2643 DeleteObject( hPieceFont );
\r
2646 for( i=0; i<12; i++ ) {
\r
2647 hPieceMask[i] = NULL;
\r
2648 hPieceFace[i] = NULL;
\r
2654 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2655 fontHeight = appData.fontPieceSize;
\r
2658 fontHeight = (fontHeight * squareSize) / 100;
\r
2660 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2662 lf.lfEscapement = 0;
\r
2663 lf.lfOrientation = 0;
\r
2664 lf.lfWeight = FW_NORMAL;
\r
2666 lf.lfUnderline = 0;
\r
2667 lf.lfStrikeOut = 0;
\r
2668 lf.lfCharSet = DEFAULT_CHARSET;
\r
2669 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2670 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2671 lf.lfQuality = PROOF_QUALITY;
\r
2672 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2673 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2674 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2676 hPieceFont = CreateFontIndirect( &lf );
\r
2678 if( hPieceFont == NULL ) {
\r
2679 fontBitmapSquareSize = -2;
\r
2682 /* Setup font-to-piece character table */
\r
2683 if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) {
\r
2684 /* No (or wrong) global settings, try to detect the font */
\r
2685 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2687 SetPieceToFontCharTable("phbrqkojntwl");
\r
2689 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2690 /* DiagramTT* family */
\r
2691 SetPieceToFontCharTable("PNLRQKpnlrqk");
\r
2694 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2695 /* Fairy symbols */
\r
2696 SetPieceToFontCharTable("PNBRACFHEWUOGMQKpnbracfewuogmqk");
\r
2699 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2700 /* Good Companion (Some characters get warped as literal :-( */
\r
2701 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2702 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2703 SetPieceToFontCharTable(s);
\r
2706 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2707 SetPieceToFontCharTable("pnbrqkomvtwl");
\r
2711 /* Create bitmaps */
\r
2712 hfont_old = SelectObject( hdc, hPieceFont );
\r
2714 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2715 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2716 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2717 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2718 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2719 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2720 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2721 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2722 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2723 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2724 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2725 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2727 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2728 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2729 CreatePieceMaskFromFont( hdc_window, hdc, PM_WFP );
\r
2730 CreatePieceMaskFromFont( hdc_window, hdc, PM_WFN );
\r
2731 CreatePieceMaskFromFont( hdc_window, hdc, PM_WFB );
\r
2732 CreatePieceMaskFromFont( hdc_window, hdc, PM_WFR );
\r
2733 CreatePieceMaskFromFont( hdc_window, hdc, PM_WFA );
\r
2734 CreatePieceMaskFromFont( hdc_window, hdc, PM_WFC );
\r
2735 CreatePieceMaskFromFont( hdc_window, hdc, PM_WFQ );
\r
2736 CreatePieceMaskFromFont( hdc_window, hdc, PM_WFK );
\r
2737 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2738 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2739 CreatePieceMaskFromFont( hdc_window, hdc, PM_BFP );
\r
2740 CreatePieceMaskFromFont( hdc_window, hdc, PM_BFN );
\r
2741 CreatePieceMaskFromFont( hdc_window, hdc, PM_BFB );
\r
2742 CreatePieceMaskFromFont( hdc_window, hdc, PM_BFR );
\r
2743 CreatePieceMaskFromFont( hdc_window, hdc, PM_BFA );
\r
2744 CreatePieceMaskFromFont( hdc_window, hdc, PM_BFC );
\r
2745 CreatePieceMaskFromFont( hdc_window, hdc, PM_BFQ );
\r
2746 CreatePieceMaskFromFont( hdc_window, hdc, PM_BFK );
\r
2749 SelectObject( hdc, hfont_old );
\r
2751 fontBitmapSquareSize = squareSize;
\r
2755 if( hdc != NULL ) {
\r
2759 if( hdc_window != NULL ) {
\r
2760 ReleaseDC( hwndMain, hdc_window );
\r
2765 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2769 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2770 if (gameInfo.event &&
\r
2771 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2772 strcmp(name, "k80s") == 0) {
\r
2773 strcpy(name, "tim");
\r
2775 return LoadBitmap(hinst, name);
\r
2779 /* Insert a color into the program's logical palette
\r
2780 structure. This code assumes the given color is
\r
2781 the result of the RGB or PALETTERGB macro, and it
\r
2782 knows how those macros work (which is documented).
\r
2785 InsertInPalette(COLORREF color)
\r
2787 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2789 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2790 DisplayFatalError("Too many colors", 0, 1);
\r
2791 pLogPal->palNumEntries--;
\r
2795 pe->peFlags = (char) 0;
\r
2796 pe->peRed = (char) (0xFF & color);
\r
2797 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2798 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2804 InitDrawingColors()
\r
2806 if (pLogPal == NULL) {
\r
2807 /* Allocate enough memory for a logical palette with
\r
2808 * PALETTESIZE entries and set the size and version fields
\r
2809 * of the logical palette structure.
\r
2811 pLogPal = (NPLOGPALETTE)
\r
2812 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2813 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2814 pLogPal->palVersion = 0x300;
\r
2816 pLogPal->palNumEntries = 0;
\r
2818 InsertInPalette(lightSquareColor);
\r
2819 InsertInPalette(darkSquareColor);
\r
2820 InsertInPalette(whitePieceColor);
\r
2821 InsertInPalette(blackPieceColor);
\r
2822 InsertInPalette(highlightSquareColor);
\r
2823 InsertInPalette(premoveHighlightColor);
\r
2825 /* create a logical color palette according the information
\r
2826 * in the LOGPALETTE structure.
\r
2828 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2830 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2831 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2832 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2833 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2834 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2836 /* [AS] Force rendering of the font-based pieces */
\r
2837 if( fontBitmapSquareSize > 0 ) {
\r
2838 fontBitmapSquareSize = 0;
\r
2844 BoardWidth(int boardSize, int n)
\r
2845 { /* [HGM] argument n added to allow different width and height */
\r
2846 int lineGap = sizeInfo[boardSize].lineGap;
\r
2848 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2849 lineGap = appData.overrideLineGap;
\r
2852 return (n + 1) * lineGap +
\r
2853 n * sizeInfo[boardSize].squareSize;
\r
2856 /* Respond to board resize by dragging edge */
\r
2858 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2860 BoardSize newSize = NUM_SIZES - 1;
\r
2861 static int recurse = 0;
\r
2862 if (IsIconic(hwndMain)) return;
\r
2863 if (recurse > 0) return;
\r
2865 while (newSize > 0 &&
\r
2866 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2867 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2870 boardSize = newSize;
\r
2871 InitDrawingSizes(boardSize, flags);
\r
2878 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2880 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2881 ChessSquare piece;
\r
2882 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2884 SIZE clockSize, messageSize;
\r
2886 char buf[MSG_SIZ];
\r
2888 HMENU hmenu = GetMenu(hwndMain);
\r
2889 RECT crect, wrect;
\r
2891 LOGBRUSH logbrush;
\r
2893 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2894 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2895 squareSize = sizeInfo[boardSize].squareSize;
\r
2896 lineGap = sizeInfo[boardSize].lineGap;
\r
2898 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2899 lineGap = appData.overrideLineGap;
\r
2902 if (tinyLayout != oldTinyLayout) {
\r
2903 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2905 style &= ~WS_SYSMENU;
\r
2906 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2907 "&Minimize\tCtrl+F4");
\r
2909 style |= WS_SYSMENU;
\r
2910 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2912 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2914 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2915 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2916 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2918 DrawMenuBar(hwndMain);
\r
2921 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
2922 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
2924 /* Get text area sizes */
\r
2925 hdc = GetDC(hwndMain);
\r
2926 if (appData.clockMode) {
\r
2927 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2929 sprintf(buf, "White");
\r
2931 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2932 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2933 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2934 str = "We only care about the height here";
\r
2935 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2936 SelectObject(hdc, oldFont);
\r
2937 ReleaseDC(hwndMain, hdc);
\r
2939 /* Compute where everything goes */
\r
2940 whiteRect.left = OUTER_MARGIN;
\r
2941 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2942 whiteRect.top = OUTER_MARGIN;
\r
2943 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2945 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2946 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2947 blackRect.top = whiteRect.top;
\r
2948 blackRect.bottom = whiteRect.bottom;
\r
2950 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2951 if (appData.showButtonBar) {
\r
2952 messageRect.right = blackRect.right
\r
2953 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2955 messageRect.right = blackRect.right;
\r
2957 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2958 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2960 boardRect.left = whiteRect.left;
\r
2961 boardRect.right = boardRect.left + boardWidth;
\r
2962 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2963 boardRect.bottom = boardRect.top + boardHeight;
\r
2965 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2966 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2967 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2968 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2969 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2970 GetWindowRect(hwndMain, &wrect);
\r
2971 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2972 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2973 /* compensate if menu bar wrapped */
\r
2974 GetClientRect(hwndMain, &crect);
\r
2975 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2976 winHeight += offby;
\r
2978 case WMSZ_TOPLEFT:
\r
2979 SetWindowPos(hwndMain, NULL,
\r
2980 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2981 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2984 case WMSZ_TOPRIGHT:
\r
2986 SetWindowPos(hwndMain, NULL,
\r
2987 wrect.left, wrect.bottom - winHeight,
\r
2988 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2991 case WMSZ_BOTTOMLEFT:
\r
2993 SetWindowPos(hwndMain, NULL,
\r
2994 wrect.right - winWidth, wrect.top,
\r
2995 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2998 case WMSZ_BOTTOMRIGHT:
\r
3002 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3003 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3008 for (i = 0; i < N_BUTTONS; i++) {
\r
3009 if (buttonDesc[i].hwnd != NULL) {
\r
3010 DestroyWindow(buttonDesc[i].hwnd);
\r
3011 buttonDesc[i].hwnd = NULL;
\r
3013 if (appData.showButtonBar) {
\r
3014 buttonDesc[i].hwnd =
\r
3015 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3016 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3017 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3018 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3019 (HMENU) buttonDesc[i].id,
\r
3020 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3022 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3023 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3024 MAKELPARAM(FALSE, 0));
\r
3026 if (buttonDesc[i].id == IDM_Pause)
\r
3027 hwndPause = buttonDesc[i].hwnd;
\r
3028 buttonDesc[i].wndproc = (WNDPROC)
\r
3029 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3032 if (gridPen != NULL) DeleteObject(gridPen);
\r
3033 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3034 if (premovePen != NULL) DeleteObject(premovePen);
\r
3035 if (lineGap != 0) {
\r
3036 logbrush.lbStyle = BS_SOLID;
\r
3037 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3039 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3040 lineGap, &logbrush, 0, NULL);
\r
3041 logbrush.lbColor = highlightSquareColor;
\r
3043 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3044 lineGap, &logbrush, 0, NULL);
\r
3046 logbrush.lbColor = premoveHighlightColor;
\r
3048 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3049 lineGap, &logbrush, 0, NULL);
\r
3051 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3052 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3053 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3054 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3055 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3056 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3057 BOARD_WIDTH * (squareSize + lineGap);
\r
3058 lineGap / 2 + (i * (squareSize + lineGap));
\r
3059 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3061 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3062 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3063 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3064 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3065 lineGap / 2 + (i * (squareSize + lineGap));
\r
3066 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3067 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3068 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3072 if (boardSize == oldBoardSize) return;
\r
3073 oldBoardSize = boardSize;
\r
3074 oldTinyLayout = tinyLayout;
\r
3076 /* Load piece bitmaps for this board size */
\r
3077 for (i=0; i<=2; i++) {
\r
3078 for (piece = WhitePawn;
\r
3079 (int) piece < (int) BlackPawn;
\r
3080 piece = (ChessSquare) ((int) piece + 1)) {
\r
3081 if (pieceBitmap[i][piece] != NULL)
\r
3082 DeleteObject(pieceBitmap[i][piece]);
\r
3086 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3087 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3088 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3089 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3090 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3091 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3092 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3093 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3094 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3095 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3096 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3097 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3098 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3099 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3100 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3101 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3102 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3103 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3105 if(squareSize==72 || squareSize==49) { /* experiment with some home-made bitmaps */
\r
3106 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3107 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3108 pieceBitmap[0][WhiteFairyPawn] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3109 pieceBitmap[0][WhiteFairyKnight] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3110 pieceBitmap[0][WhiteFairyBishop] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3111 pieceBitmap[0][WhiteFairyRook] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3112 pieceBitmap[0][WhiteFairyQueen] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3113 pieceBitmap[0][WhiteFairyCardinal] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3114 pieceBitmap[0][WhiteFairyMarshall] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3115 pieceBitmap[0][WhiteFairyKing] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3116 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3117 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3118 pieceBitmap[1][WhiteFairyPawn] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3119 pieceBitmap[1][WhiteFairyKnight] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3120 pieceBitmap[1][WhiteFairyBishop] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3121 pieceBitmap[1][WhiteFairyRook] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3122 pieceBitmap[1][WhiteFairyQueen] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3123 pieceBitmap[1][WhiteFairyCardinal] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3124 pieceBitmap[1][WhiteFairyMarshall] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3125 pieceBitmap[1][WhiteFairyKing] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3126 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3127 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3128 pieceBitmap[2][WhiteFairyPawn] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3129 pieceBitmap[2][WhiteFairyKnight] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3130 pieceBitmap[2][WhiteFairyBishop] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3131 pieceBitmap[2][WhiteFairyRook] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3132 pieceBitmap[2][WhiteFairyQueen] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3133 pieceBitmap[2][WhiteFairyCardinal] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3134 pieceBitmap[2][WhiteFairyMarshall] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3135 pieceBitmap[2][WhiteFairyKing] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3142 PieceBitmap(ChessSquare p, int kind)
\r
3144 if ((int) p >= (int) BlackPawn)
\r
3145 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3147 return pieceBitmap[kind][(int) p];
\r
3150 /***************************************************************/
\r
3152 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3153 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3155 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3156 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3160 SquareToPos(int row, int column, int * x, int * y)
\r
3163 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3164 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3166 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3167 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3172 DrawCoordsOnDC(HDC hdc)
\r
3174 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
3175 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
3176 char str[2] = { NULLCHAR, NULLCHAR };
\r
3177 int oldMode, oldAlign, x, y, start, i;
\r
3181 if (!appData.showCoords)
\r
3184 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3186 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3187 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3188 oldAlign = GetTextAlign(hdc);
\r
3189 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3191 y = boardRect.top + lineGap;
\r
3192 x = boardRect.left + lineGap;
\r
3194 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3195 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3196 str[0] = files[start + i];
\r
3197 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3198 y += squareSize + lineGap;
\r
3201 start = flipView ? 12-BOARD_WIDTH : 12;
\r
3203 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3204 for (i = 0; i < BOARD_WIDTH; i++) {
\r
3205 str[0] = ranks[start + i];
\r
3206 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3207 x += squareSize + lineGap;
\r
3210 SelectObject(hdc, oldBrush);
\r
3211 SetBkMode(hdc, oldMode);
\r
3212 SetTextAlign(hdc, oldAlign);
\r
3213 SelectObject(hdc, oldFont);
\r
3217 DrawGridOnDC(HDC hdc)
\r
3221 if (lineGap != 0) {
\r
3222 oldPen = SelectObject(hdc, gridPen);
\r
3223 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3224 SelectObject(hdc, oldPen);
\r
3228 #define HIGHLIGHT_PEN 0
\r
3229 #define PREMOVE_PEN 1
\r
3232 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3235 HPEN oldPen, hPen;
\r
3236 if (lineGap == 0) return;
\r
3238 x1 = boardRect.left +
\r
3239 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3240 y1 = boardRect.top +
\r
3241 lineGap/2 + y * (squareSize + lineGap);
\r
3243 x1 = boardRect.left +
\r
3244 lineGap/2 + x * (squareSize + lineGap);
\r
3245 y1 = boardRect.top +
\r
3246 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3248 hPen = pen ? premovePen : highlightPen;
\r
3249 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3250 MoveToEx(hdc, x1, y1, NULL);
\r
3251 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3252 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3253 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3254 LineTo(hdc, x1, y1);
\r
3255 SelectObject(hdc, oldPen);
\r
3259 DrawHighlightsOnDC(HDC hdc)
\r
3262 for (i=0; i<2; i++) {
\r
3263 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3264 DrawHighlightOnDC(hdc, TRUE,
\r
3265 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3268 for (i=0; i<2; i++) {
\r
3269 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3270 premoveHighlightInfo.sq[i].y >= 0) {
\r
3271 DrawHighlightOnDC(hdc, TRUE,
\r
3272 premoveHighlightInfo.sq[i].x,
\r
3273 premoveHighlightInfo.sq[i].y,
\r
3279 /* Note: sqcolor is used only in monoMode */
\r
3280 /* Note that this code is largely duplicated in woptions.c,
\r
3281 function DrawSampleSquare, so that needs to be updated too */
\r
3283 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3285 HBITMAP oldBitmap;
\r
3288 if (appData.blindfold) return;
\r
3290 /* [AS] Use font-based pieces if needed */
\r
3291 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3292 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3293 CreatePiecesFromFont();
\r
3295 if( fontBitmapSquareSize == squareSize ) {
\r
3296 int index = TranslatePieceToFontPiece( piece );
\r
3298 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3302 squareSize, squareSize,
\r
3307 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3311 squareSize, squareSize,
\r
3320 if (appData.monoMode) {
\r
3321 SelectObject(tmphdc, PieceBitmap(piece,
\r
3322 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3323 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3324 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3327 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3328 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3329 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3331 /* Use black piece color for outline of white pieces */
\r
3332 /* Not sure this looks really good (though xboard does it).
\r
3333 Maybe better to have another selectable color, default black */
\r
3334 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3335 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3336 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3338 /* Use black for outline of white pieces */
\r
3339 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3340 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
3344 /* Use white piece color for details of black pieces */
\r
3345 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3346 WHITE_PIECE ones aren't always the right shape. */
\r
3347 /* Not sure this looks really good (though xboard does it).
\r
3348 Maybe better to have another selectable color, default medium gray? */
\r
3349 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3350 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3351 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3352 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3353 SelectObject(hdc, blackPieceBrush);
\r
3354 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3356 /* Use square color for details of black pieces */
\r
3357 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3358 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3359 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3362 SelectObject(hdc, oldBrush);
\r
3363 SelectObject(tmphdc, oldBitmap);
\r
3367 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3368 int GetBackTextureMode( int algo )
\r
3370 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3374 case BACK_TEXTURE_MODE_PLAIN:
\r
3375 result = 1; /* Always use identity map */
\r
3377 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3378 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3386 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3387 to handle redraws cleanly (as random numbers would always be different).
\r
3389 VOID RebuildTextureSquareInfo()
\r
3399 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3401 if( liteBackTexture != NULL ) {
\r
3402 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3403 lite_w = bi.bmWidth;
\r
3404 lite_h = bi.bmHeight;
\r
3408 if( darkBackTexture != NULL ) {
\r
3409 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3410 dark_w = bi.bmWidth;
\r
3411 dark_h = bi.bmHeight;
\r
3415 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3416 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3417 if( (col + row) & 1 ) {
\r
3419 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3420 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_WIDTH;
\r
3421 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_HEIGHT;
\r
3422 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3427 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3428 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_WIDTH;
\r
3429 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_HEIGHT;
\r
3430 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3437 /* [AS] Arrow highlighting support */
\r
3439 static int A_WIDTH = 5; /* Width of arrow body */
\r
3441 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3442 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3444 static double Sqr( double x )
\r
3449 static int Round( double x )
\r
3451 return (int) (x + 0.5);
\r
3454 /* Draw an arrow between two points using current settings */
\r
3455 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3458 double dx, dy, j, k, x, y;
\r
3460 if( d_x == s_x ) {
\r
3461 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3463 arrow[0].x = s_x + A_WIDTH;
\r
3466 arrow[1].x = s_x + A_WIDTH;
\r
3467 arrow[1].y = d_y - h;
\r
3469 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3470 arrow[2].y = d_y - h;
\r
3475 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3476 arrow[4].y = d_y - h;
\r
3478 arrow[5].x = s_x - A_WIDTH;
\r
3479 arrow[5].y = d_y - h;
\r
3481 arrow[6].x = s_x - A_WIDTH;
\r
3484 else if( d_y == s_y ) {
\r
3485 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3488 arrow[0].y = s_y + A_WIDTH;
\r
3490 arrow[1].x = d_x - w;
\r
3491 arrow[1].y = s_y + A_WIDTH;
\r
3493 arrow[2].x = d_x - w;
\r
3494 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3499 arrow[4].x = d_x - w;
\r
3500 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3502 arrow[5].x = d_x - w;
\r
3503 arrow[5].y = s_y - A_WIDTH;
\r
3506 arrow[6].y = s_y - A_WIDTH;
\r
3509 /* [AS] Needed a lot of paper for this! :-) */
\r
3510 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3511 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3513 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3515 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3520 arrow[0].x = Round(x - j);
\r
3521 arrow[0].y = Round(y + j*dx);
\r
3523 arrow[1].x = Round(x + j);
\r
3524 arrow[1].y = Round(y - j*dx);
\r
3527 x = (double) d_x - k;
\r
3528 y = (double) d_y - k*dy;
\r
3531 x = (double) d_x + k;
\r
3532 y = (double) d_y + k*dy;
\r
3535 arrow[2].x = Round(x + j);
\r
3536 arrow[2].y = Round(y - j*dx);
\r
3538 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3539 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3544 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3545 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3547 arrow[6].x = Round(x - j);
\r
3548 arrow[6].y = Round(y + j*dx);
\r
3551 Polygon( hdc, arrow, 7 );
\r
3554 /* [AS] Draw an arrow between two squares */
\r
3555 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3557 int s_x, s_y, d_x, d_y;
\r
3564 if( s_col == d_col && s_row == d_row ) {
\r
3568 /* Get source and destination points */
\r
3569 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3570 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3573 d_y += squareSize / 4;
\r
3575 else if( d_y < s_y ) {
\r
3576 d_y += 3 * squareSize / 4;
\r
3579 d_y += squareSize / 2;
\r
3583 d_x += squareSize / 4;
\r
3585 else if( d_x < s_x ) {
\r
3586 d_x += 3 * squareSize / 4;
\r
3589 d_x += squareSize / 2;
\r
3592 s_x += squareSize / 2;
\r
3593 s_y += squareSize / 2;
\r
3595 /* Adjust width */
\r
3596 A_WIDTH = squareSize / 14;
\r
3599 stLB.lbStyle = BS_SOLID;
\r
3600 stLB.lbColor = appData.highlightArrowColor;
\r
3603 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3604 holdpen = SelectObject( hdc, hpen );
\r
3605 hbrush = CreateBrushIndirect( &stLB );
\r
3606 holdbrush = SelectObject( hdc, hbrush );
\r
3608 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3610 SelectObject( hdc, holdpen );
\r
3611 SelectObject( hdc, holdbrush );
\r
3612 DeleteObject( hpen );
\r
3613 DeleteObject( hbrush );
\r
3616 BOOL HasHighlightInfo()
\r
3618 BOOL result = FALSE;
\r
3620 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3621 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3629 BOOL IsDrawArrowEnabled()
\r
3631 BOOL result = FALSE;
\r
3633 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3640 VOID DrawArrowHighlight( HDC hdc )
\r
3642 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3643 DrawArrowBetweenSquares( hdc,
\r
3644 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3645 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3649 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3651 HRGN result = NULL;
\r
3653 if( HasHighlightInfo() ) {
\r
3654 int x1, y1, x2, y2;
\r
3655 int sx, sy, dx, dy;
\r
3657 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3658 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3660 sx = MIN( x1, x2 );
\r
3661 sy = MIN( y1, y2 );
\r
3662 dx = MAX( x1, x2 ) + squareSize;
\r
3663 dy = MAX( y1, y2 ) + squareSize;
\r
3665 result = CreateRectRgn( sx, sy, dx, dy );
\r
3672 Warning: this function modifies the behavior of several other functions.
\r
3674 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3675 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3676 repaint is scattered all over the place, which is not good for features such as
\r
3677 "arrow highlighting" that require a full repaint of the board.
\r
3679 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3680 user interaction, when speed is not so important) but especially to avoid errors
\r
3681 in the displayed graphics.
\r
3683 In such patched places, I always try refer to this function so there is a single
\r
3684 place to maintain knowledge.
\r
3686 To restore the original behavior, just return FALSE unconditionally.
\r
3688 BOOL IsFullRepaintPreferrable()
\r
3690 BOOL result = FALSE;
\r
3692 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3693 /* Arrow may appear on the board */
\r
3701 This function is called by DrawPosition to know whether a full repaint must
\r
3704 Only DrawPosition may directly call this function, which makes use of
\r
3705 some state information. Other function should call DrawPosition specifying
\r
3706 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3708 BOOL DrawPositionNeedsFullRepaint()
\r
3710 BOOL result = FALSE;
\r
3713 Probably a slightly better policy would be to trigger a full repaint
\r
3714 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3715 but animation is fast enough that it's difficult to notice.
\r
3717 if( animInfo.piece == EmptySquare ) {
\r
3718 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3727 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3729 int row, column, x, y, square_color, piece_color;
\r
3730 ChessSquare piece;
\r
3732 HDC texture_hdc = NULL;
\r
3734 /* [AS] Initialize background textures if needed */
\r
3735 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3736 if( backTextureSquareSize != squareSize ) {
\r
3737 backTextureSquareSize = squareSize;
\r
3738 RebuildTextureSquareInfo();
\r
3741 texture_hdc = CreateCompatibleDC( hdc );
\r
3744 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3745 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3747 SquareToPos(row, column, &x, &y);
\r
3749 piece = board[row][column];
\r
3751 square_color = ((column + row) % 2) == 1;
\r
3752 if(!strcmp(appData.variant, "xiangqi") ) {
\r
3754 if( (row < 3 || row > BOARD_HEIGHT-4) &&
\r
3755 column < (BOARD_WIDTH + 4)/2 &&
\r
3756 column > (BOARD_WIDTH - 5)/2 ) square_color = 0;
\r
3758 piece_color = (int) piece < (int) BlackPawn;
\r
3760 if (appData.monoMode) {
\r
3761 if (piece == EmptySquare) {
\r
3762 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3763 square_color ? WHITENESS : BLACKNESS);
\r
3765 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3768 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
3769 /* [AS] Draw the square using a texture bitmap */
\r
3770 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3773 squareSize, squareSize,
\r
3776 backTextureSquareInfo[row][column].mode,
\r
3777 backTextureSquareInfo[row][column].x,
\r
3778 backTextureSquareInfo[row][column].y );
\r
3780 SelectObject( texture_hdc, hbm );
\r
3782 if (piece != EmptySquare) {
\r
3783 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3787 oldBrush = SelectObject(hdc, square_color ?
\r
3788 lightSquareBrush : darkSquareBrush);
\r
3789 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3790 SelectObject(hdc, oldBrush);
\r
3791 if (piece != EmptySquare)
\r
3792 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3797 if( texture_hdc != NULL ) {
\r
3798 DeleteDC( texture_hdc );
\r
3802 #define MAX_CLIPS 200 /* more than enough */
\r
3805 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3807 static Board lastReq, lastDrawn;
\r
3808 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3809 static int lastDrawnFlipView = 0;
\r
3810 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3811 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3814 HBITMAP bufferBitmap;
\r
3815 HBITMAP oldBitmap;
\r
3817 HRGN clips[MAX_CLIPS];
\r
3818 ChessSquare dragged_piece = EmptySquare;
\r
3820 /* I'm undecided on this - this function figures out whether a full
\r
3821 * repaint is necessary on its own, so there's no real reason to have the
\r
3822 * caller tell it that. I think this can safely be set to FALSE - but
\r
3823 * if we trust the callers not to request full repaints unnessesarily, then
\r
3824 * we could skip some clipping work. In other words, only request a full
\r
3825 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3826 * gamestart and similar) --Hawk
\r
3828 Boolean fullrepaint = repaint;
\r
3830 if( DrawPositionNeedsFullRepaint() ) {
\r
3831 fullrepaint = TRUE;
\r
3835 if( fullrepaint ) {
\r
3836 static int repaint_count = 0;
\r
3840 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
3841 OutputDebugString( buf );
\r
3845 if (board == NULL) {
\r
3846 if (!lastReqValid) {
\r
3851 CopyBoard(lastReq, board);
\r
3855 if (doingSizing) {
\r
3859 if (IsIconic(hwndMain)) {
\r
3863 if (hdc == NULL) {
\r
3864 hdc = GetDC(hwndMain);
\r
3865 if (!appData.monoMode) {
\r
3866 SelectPalette(hdc, hPal, FALSE);
\r
3867 RealizePalette(hdc);
\r
3871 releaseDC = FALSE;
\r
3875 fprintf(debugFP, "*******************************\n"
\r
3877 "dragInfo.from (%d,%d)\n"
\r
3878 "dragInfo.start (%d,%d)\n"
\r
3879 "dragInfo.pos (%d,%d)\n"
\r
3880 "dragInfo.lastpos (%d,%d)\n",
\r
3881 repaint ? "TRUE" : "FALSE",
\r
3882 dragInfo.from.x, dragInfo.from.y,
\r
3883 dragInfo.start.x, dragInfo.start.y,
\r
3884 dragInfo.pos.x, dragInfo.pos.y,
\r
3885 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
3886 fprintf(debugFP, "prev: ");
\r
3887 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3888 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3889 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
3892 fprintf(debugFP, "\n");
\r
3893 fprintf(debugFP, "board: ");
\r
3894 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3895 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3896 fprintf(debugFP, "%d ", board[row][column]);
\r
3899 fprintf(debugFP, "\n");
\r
3903 /* Create some work-DCs */
\r
3904 hdcmem = CreateCompatibleDC(hdc);
\r
3905 tmphdc = CreateCompatibleDC(hdc);
\r
3907 /* Figure out which squares need updating by comparing the
\r
3908 * newest board with the last drawn board and checking if
\r
3909 * flipping has changed.
\r
3911 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3912 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3913 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3914 if (lastDrawn[row][column] != board[row][column]) {
\r
3915 SquareToPos(row, column, &x, &y);
\r
3916 clips[num_clips++] =
\r
3917 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3921 for (i=0; i<2; i++) {
\r
3922 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3923 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3924 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3925 lastDrawnHighlight.sq[i].y >= 0) {
\r
3926 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3927 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3928 clips[num_clips++] =
\r
3929 CreateRectRgn(x - lineGap, y - lineGap,
\r
3930 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3932 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3933 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3934 clips[num_clips++] =
\r
3935 CreateRectRgn(x - lineGap, y - lineGap,
\r
3936 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3940 for (i=0; i<2; i++) {
\r
3941 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3942 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3943 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3944 lastDrawnPremove.sq[i].y >= 0) {
\r
3945 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3946 lastDrawnPremove.sq[i].x, &x, &y);
\r
3947 clips[num_clips++] =
\r
3948 CreateRectRgn(x - lineGap, y - lineGap,
\r
3949 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3951 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3952 premoveHighlightInfo.sq[i].y >= 0) {
\r
3953 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3954 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3955 clips[num_clips++] =
\r
3956 CreateRectRgn(x - lineGap, y - lineGap,
\r
3957 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3962 fullrepaint = TRUE;
\r
3965 /* Create a buffer bitmap - this is the actual bitmap
\r
3966 * being written to. When all the work is done, we can
\r
3967 * copy it to the real DC (the screen). This avoids
\r
3968 * the problems with flickering.
\r
3970 GetClientRect(hwndMain, &Rect);
\r
3971 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3972 Rect.bottom-Rect.top+1);
\r
3973 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3974 if (!appData.monoMode) {
\r
3975 SelectPalette(hdcmem, hPal, FALSE);
\r
3978 /* Create clips for dragging */
\r
3979 if (!fullrepaint) {
\r
3980 if (dragInfo.from.x >= 0) {
\r
3981 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3982 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3984 if (dragInfo.start.x >= 0) {
\r
3985 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3986 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3988 if (dragInfo.pos.x >= 0) {
\r
3989 x = dragInfo.pos.x - squareSize / 2;
\r
3990 y = dragInfo.pos.y - squareSize / 2;
\r
3991 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3993 if (dragInfo.lastpos.x >= 0) {
\r
3994 x = dragInfo.lastpos.x - squareSize / 2;
\r
3995 y = dragInfo.lastpos.y - squareSize / 2;
\r
3996 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4000 /* If dragging is in progress, we temporarely remove the piece */
\r
4001 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4002 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4003 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4006 /* Are we animating a move?
\r
4008 * - remove the piece from the board (temporarely)
\r
4009 * - calculate the clipping region
\r
4011 if (!fullrepaint) {
\r
4012 if (animInfo.piece != EmptySquare) {
\r
4013 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4014 x = boardRect.left + animInfo.lastpos.x;
\r
4015 y = boardRect.top + animInfo.lastpos.y;
\r
4016 x2 = boardRect.left + animInfo.pos.x;
\r
4017 y2 = boardRect.top + animInfo.pos.y;
\r
4018 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4019 /* Slight kludge. The real problem is that after AnimateMove is
\r
4020 done, the position on the screen does not match lastDrawn.
\r
4021 This currently causes trouble only on e.p. captures in
\r
4022 atomic, where the piece moves to an empty square and then
\r
4023 explodes. The old and new positions both had an empty square
\r
4024 at the destination, but animation has drawn a piece there and
\r
4025 we have to remember to erase it. */
\r
4026 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4030 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4031 if (num_clips == 0)
\r
4032 fullrepaint = TRUE;
\r
4034 /* Set clipping on the memory DC */
\r
4035 if (!fullrepaint) {
\r
4036 SelectClipRgn(hdcmem, clips[0]);
\r
4037 for (x = 1; x < num_clips; x++) {
\r
4038 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4039 abort(); // this should never ever happen!
\r
4043 /* Do all the drawing to the memory DC */
\r
4044 DrawGridOnDC(hdcmem);
\r
4045 DrawHighlightsOnDC(hdcmem);
\r
4046 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4048 if( appData.highlightMoveWithArrow ) {
\r
4049 DrawArrowHighlight(hdcmem);
\r
4052 DrawCoordsOnDC(hdcmem);
\r
4054 /* Put the dragged piece back into place and draw it */
\r
4055 if (dragged_piece != EmptySquare) {
\r
4056 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4057 x = dragInfo.pos.x - squareSize / 2;
\r
4058 y = dragInfo.pos.y - squareSize / 2;
\r
4059 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4060 ((int) dragged_piece < (int) BlackPawn),
\r
4061 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4064 /* Put the animated piece back into place and draw it */
\r
4065 if (animInfo.piece != EmptySquare) {
\r
4066 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4067 x = boardRect.left + animInfo.pos.x;
\r
4068 y = boardRect.top + animInfo.pos.y;
\r
4069 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4070 ((int) animInfo.piece < (int) BlackPawn),
\r
4071 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4074 /* Release the bufferBitmap by selecting in the old bitmap
\r
4075 * and delete the memory DC
\r
4077 SelectObject(hdcmem, oldBitmap);
\r
4080 /* Set clipping on the target DC */
\r
4081 if (!fullrepaint) {
\r
4082 SelectClipRgn(hdc, clips[0]);
\r
4083 for (x = 1; x < num_clips; x++) {
\r
4084 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4085 abort(); // this should never ever happen!
\r
4089 /* Copy the new bitmap onto the screen in one go.
\r
4090 * This way we avoid any flickering
\r
4092 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4093 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4094 boardRect.right - boardRect.left,
\r
4095 boardRect.bottom - boardRect.top,
\r
4096 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4097 SelectObject(tmphdc, oldBitmap);
\r
4099 /* Massive cleanup */
\r
4100 for (x = 0; x < num_clips; x++)
\r
4101 DeleteObject(clips[x]);
\r
4104 DeleteObject(bufferBitmap);
\r
4107 ReleaseDC(hwndMain, hdc);
\r
4109 if (lastDrawnFlipView != flipView) {
\r
4111 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4113 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4116 CopyBoard(lastDrawn, board);
\r
4117 lastDrawnHighlight = highlightInfo;
\r
4118 lastDrawnPremove = premoveHighlightInfo;
\r
4119 lastDrawnFlipView = flipView;
\r
4120 lastDrawnValid = 1;
\r
4124 /*---------------------------------------------------------------------------*\
\r
4125 | CLIENT PAINT PROCEDURE
\r
4126 | This is the main event-handler for the WM_PAINT message.
\r
4128 \*---------------------------------------------------------------------------*/
\r
4130 PaintProc(HWND hwnd)
\r
4136 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4137 if (IsIconic(hwnd)) {
\r
4138 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4140 if (!appData.monoMode) {
\r
4141 SelectPalette(hdc, hPal, FALSE);
\r
4142 RealizePalette(hdc);
\r
4144 HDCDrawPosition(hdc, 1, NULL);
\r
4146 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4147 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4148 ETO_CLIPPED|ETO_OPAQUE,
\r
4149 &messageRect, messageText, strlen(messageText), NULL);
\r
4150 SelectObject(hdc, oldFont);
\r
4151 DisplayBothClocks();
\r
4153 EndPaint(hwnd,&ps);
\r
4161 * If the user selects on a border boundary, return -1; if off the board,
\r
4162 * return -2. Otherwise map the event coordinate to the square.
\r
4163 * The offset boardRect.left or boardRect.top must already have been
\r
4164 * subtracted from x.
\r
4167 EventToSquare(int x)
\r
4174 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4176 x /= (squareSize + lineGap);
\r
4177 if (x >= BOARD_SIZE)
\r
4188 DropEnable dropEnables[] = {
\r
4189 { 'P', DP_Pawn, "Pawn" },
\r
4190 { 'N', DP_Knight, "Knight" },
\r
4191 { 'B', DP_Bishop, "Bishop" },
\r
4192 { 'R', DP_Rook, "Rook" },
\r
4193 { 'Q', DP_Queen, "Queen" },
\r
4197 SetupDropMenu(HMENU hmenu)
\r
4199 int i, count, enable;
\r
4201 extern char white_holding[], black_holding[];
\r
4202 char item[MSG_SIZ];
\r
4204 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4205 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4206 dropEnables[i].piece);
\r
4208 while (p && *p++ == dropEnables[i].piece) count++;
\r
4209 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4210 enable = count > 0 || !appData.testLegality
\r
4211 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4212 && !appData.icsActive);
\r
4213 ModifyMenu(hmenu, dropEnables[i].command,
\r
4214 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4215 dropEnables[i].command, item);
\r
4219 static int fromX = -1, fromY = -1, toX, toY;
\r
4221 /* Event handler for mouse messages */
\r
4223 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4227 static int recursive = 0;
\r
4229 BOOLEAN needsRedraw = FALSE;
\r
4230 BOOLEAN saveAnimate;
\r
4231 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4232 static BOOLEAN sameAgain = FALSE;
\r
4235 if (message == WM_MBUTTONUP) {
\r
4236 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4237 to the middle button: we simulate pressing the left button too!
\r
4239 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4240 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4246 pt.x = LOWORD(lParam);
\r
4247 pt.y = HIWORD(lParam);
\r
4248 x = EventToSquare(pt.x - boardRect.left);
\r
4249 y = EventToSquare(pt.y - boardRect.top);
\r
4250 if (!flipView && y >= 0) {
\r
4251 y = BOARD_HEIGHT - 1 - y;
\r
4253 if (flipView && x >= 0) {
\r
4254 x = BOARD_WIDTH - 1 - x;
\r
4257 switch (message) {
\r
4258 case WM_LBUTTONDOWN:
\r
4260 sameAgain = FALSE;
\r
4262 /* Downclick vertically off board; check if on clock */
\r
4263 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4264 if (gameMode == EditPosition) {
\r
4265 SetWhiteToPlayEvent();
\r
4266 } else if (gameMode == IcsPlayingBlack ||
\r
4267 gameMode == MachinePlaysWhite) {
\r
4270 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4271 if (gameMode == EditPosition) {
\r
4272 SetBlackToPlayEvent();
\r
4273 } else if (gameMode == IcsPlayingWhite ||
\r
4274 gameMode == MachinePlaysBlack) {
\r
4278 if (!appData.highlightLastMove) {
\r
4279 ClearHighlights();
\r
4280 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4282 fromX = fromY = -1;
\r
4283 dragInfo.start.x = dragInfo.start.y = -1;
\r
4284 dragInfo.from = dragInfo.start;
\r
4286 } else if (x < 0 || y < 0) {
\r
4288 } else if (fromX == x && fromY == y) {
\r
4289 /* Downclick on same square again */
\r
4290 ClearHighlights();
\r
4291 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4292 sameAgain = TRUE;
\r
4293 } else if (fromX != -1) {
\r
4294 /* Downclick on different square */
\r
4295 ChessSquare pdown, pup;
\r
4296 pdown = boards[currentMove][fromY][fromX];
\r
4297 pup = boards[currentMove][y][x];
\r
4298 if (gameMode == EditPosition || /* [HGM] max piece > King! */
\r
4299 !((WhitePawn <= pdown && pdown < BlackPawn &&
\r
4300 WhitePawn <= pup && pup < BlackPawn) ||
\r
4301 (BlackPawn <= pdown && pdown < EmptySquare &&
\r
4302 BlackPawn <= pup && pup < EmptySquare))) {
\r
4303 /* EditPosition, empty square, or different color piece;
\r
4304 click-click move is possible */
\r
4307 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
4308 if (appData.alwaysPromoteToQueen) {
\r
4309 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
4310 if (!appData.highlightLastMove) {
\r
4311 ClearHighlights();
\r
4312 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4315 SetHighlights(fromX, fromY, toX, toY);
\r
4316 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4317 PromotionPopup(hwnd);
\r
4319 } else { /* not a promotion */
\r
4320 if (appData.animate || appData.highlightLastMove) {
\r
4321 SetHighlights(fromX, fromY, toX, toY);
\r
4323 ClearHighlights();
\r
4325 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
4326 if (appData.animate && !appData.highlightLastMove) {
\r
4327 ClearHighlights();
\r
4328 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4331 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4332 fromX = fromY = -1;
\r
4335 ClearHighlights();
\r
4336 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4338 /* First downclick, or restart on a square with same color piece */
\r
4339 if (!frozen && OKToStartUserMove(x, y)) {
\r
4342 dragInfo.lastpos = pt;
\r
4343 dragInfo.from.x = fromX;
\r
4344 dragInfo.from.y = fromY;
\r
4345 dragInfo.start = dragInfo.from;
\r
4346 SetCapture(hwndMain);
\r
4348 fromX = fromY = -1;
\r
4349 dragInfo.start.x = dragInfo.start.y = -1;
\r
4350 dragInfo.from = dragInfo.start;
\r
4351 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4355 case WM_LBUTTONUP:
\r
4357 if (fromX == -1) break;
\r
4358 if (x == fromX && y == fromY) {
\r
4359 dragInfo.from.x = dragInfo.from.y = -1;
\r
4360 /* Upclick on same square */
\r
4362 /* Clicked same square twice: abort click-click move */
\r
4363 fromX = fromY = -1;
\r
4365 ClearPremoveHighlights();
\r
4367 /* First square clicked: start click-click move */
\r
4368 SetHighlights(fromX, fromY, -1, -1);
\r
4370 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4371 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4372 /* Errant click; ignore */
\r
4375 /* Finish drag move */
\r
4376 dragInfo.from.x = dragInfo.from.y = -1;
\r
4379 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4380 appData.animate = appData.animate && !appData.animateDragging;
\r
4381 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
4382 if (appData.alwaysPromoteToQueen) {
\r
4383 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
4385 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4386 PromotionPopup(hwnd);
\r
4389 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
4391 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4392 appData.animate = saveAnimate;
\r
4393 fromX = fromY = -1;
\r
4394 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
4395 ClearHighlights();
\r
4397 if (appData.animate || appData.animateDragging ||
\r
4398 appData.highlightDragging || gotPremove) {
\r
4399 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4402 dragInfo.start.x = dragInfo.start.y = -1;
\r
4403 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4406 case WM_MOUSEMOVE:
\r
4407 if ((appData.animateDragging || appData.highlightDragging)
\r
4408 && (wParam & MK_LBUTTON)
\r
4409 && dragInfo.from.x >= 0)
\r
4411 BOOL full_repaint = FALSE;
\r
4413 if (appData.animateDragging) {
\r
4414 dragInfo.pos = pt;
\r
4416 if (appData.highlightDragging) {
\r
4417 SetHighlights(fromX, fromY, x, y);
\r
4418 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y > BOARD_WIDTH) ) {
\r
4419 full_repaint = TRUE;
\r
4423 DrawPosition( full_repaint, NULL);
\r
4425 dragInfo.lastpos = dragInfo.pos;
\r
4429 case WM_MBUTTONDOWN:
\r
4430 case WM_RBUTTONDOWN:
\r
4433 fromX = fromY = -1;
\r
4434 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4435 dragInfo.start.x = dragInfo.start.y = -1;
\r
4436 dragInfo.from = dragInfo.start;
\r
4437 dragInfo.lastpos = dragInfo.pos;
\r
4438 if (appData.highlightDragging) {
\r
4439 ClearHighlights();
\r
4441 DrawPosition(TRUE, NULL);
\r
4443 switch (gameMode) {
\r
4444 case EditPosition:
\r
4445 case IcsExamining:
\r
4446 if (x < 0 || y < 0) break;
\r
4449 if (message == WM_MBUTTONDOWN) {
\r
4450 buttonCount = 3; /* even if system didn't think so */
\r
4451 if (wParam & MK_SHIFT)
\r
4452 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4454 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4455 } else { /* message == WM_RBUTTONDOWN */
\r
4457 if (buttonCount == 3) {
\r
4458 if (wParam & MK_SHIFT)
\r
4459 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4461 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4463 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4466 /* Just have one menu, on the right button. Windows users don't
\r
4467 think to try the middle one, and sometimes other software steals
\r
4468 it, or it doesn't really exist. */
\r
4469 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4473 case IcsPlayingWhite:
\r
4474 case IcsPlayingBlack:
\r
4476 case MachinePlaysWhite:
\r
4477 case MachinePlaysBlack:
\r
4478 if (appData.testLegality &&
\r
4479 gameInfo.variant != VariantBughouse &&
\r
4480 gameInfo.variant != VariantCrazyhouse) break;
\r
4481 if (x < 0 || y < 0) break;
\r
4484 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4485 SetupDropMenu(hmenu);
\r
4486 MenuPopup(hwnd, pt, hmenu, -1);
\r
4497 /* Preprocess messages for buttons in main window */
\r
4499 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4501 int id = GetWindowLong(hwnd, GWL_ID);
\r
4504 for (i=0; i<N_BUTTONS; i++) {
\r
4505 if (buttonDesc[i].id == id) break;
\r
4507 if (i == N_BUTTONS) return 0;
\r
4508 switch (message) {
\r
4513 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4514 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4521 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4524 if (appData.icsActive) {
\r
4525 if (GetKeyState(VK_SHIFT) < 0) {
\r
4527 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4528 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4532 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4533 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4540 if (appData.icsActive) {
\r
4541 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4542 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4544 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4546 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4547 PopUpMoveDialog((char)wParam);
\r
4553 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4556 /* Process messages for Promotion dialog box */
\r
4558 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4562 switch (message) {
\r
4563 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4564 /* Center the dialog over the application window */
\r
4565 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4566 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4567 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4568 gameInfo.variant == VariantGiveaway) ?
\r
4569 SW_SHOW : SW_HIDE);
\r
4571 /* [HGM] Only allow C & A promotions in Capablanca Chess */
\r
4572 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4573 (gameInfo.variant == VariantCapablanca ||
\r
4574 gameInfo.variant == VariantGothic) ?
\r
4575 SW_SHOW : SW_HIDE);
\r
4576 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4577 (gameInfo.variant == VariantCapablanca ||
\r
4578 gameInfo.variant == VariantGothic) ?
\r
4579 SW_SHOW : SW_HIDE);
\r
4583 case WM_COMMAND: /* message: received a command */
\r
4584 switch (LOWORD(wParam)) {
\r
4586 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4587 ClearHighlights();
\r
4588 DrawPosition(FALSE, NULL);
\r
4603 case PB_Chancellor:
\r
4606 case PB_Archbishop:
\r
4616 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4617 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4618 if (!appData.highlightLastMove) {
\r
4619 ClearHighlights();
\r
4620 DrawPosition(FALSE, NULL);
\r
4627 /* Pop up promotion dialog */
\r
4629 PromotionPopup(HWND hwnd)
\r
4633 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4634 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4635 hwnd, (DLGPROC)lpProc);
\r
4636 FreeProcInstance(lpProc);
\r
4639 /* Toggle ShowThinking */
\r
4641 ToggleShowThinking()
\r
4643 ShowThinkingEvent(!appData.showThinking);
\r
4647 LoadGameDialog(HWND hwnd, char* title)
\r
4651 char fileTitle[MSG_SIZ];
\r
4652 f = OpenFileDialog(hwnd, FALSE, "",
\r
4653 appData.oldSaveStyle ? "gam" : "pgn",
\r
4655 title, &number, fileTitle, NULL);
\r
4657 cmailMsgLoaded = FALSE;
\r
4658 if (number == 0) {
\r
4659 int error = GameListBuild(f);
\r
4661 DisplayError("Cannot build game list", error);
\r
4662 } else if (!ListEmpty(&gameList) &&
\r
4663 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4664 GameListPopUp(f, fileTitle);
\r
4667 GameListDestroy();
\r
4670 LoadGame(f, number, fileTitle, FALSE);
\r
4675 ChangedConsoleFont()
\r
4678 CHARRANGE tmpsel, sel;
\r
4679 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4680 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4681 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4684 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4685 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4686 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4687 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4688 * size. This was undocumented in the version of MSVC++ that I had
\r
4689 * when I wrote the code, but is apparently documented now.
\r
4691 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4692 cfmt.bCharSet = f->lf.lfCharSet;
\r
4693 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4694 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4695 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4696 /* Why are the following seemingly needed too? */
\r
4697 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4698 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4699 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4701 tmpsel.cpMax = -1; /*999999?*/
\r
4702 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4703 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4704 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4705 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4707 paraf.cbSize = sizeof(paraf);
\r
4708 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4709 paraf.dxStartIndent = 0;
\r
4710 paraf.dxOffset = WRAP_INDENT;
\r
4711 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4712 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4715 /*---------------------------------------------------------------------------*\
\r
4717 * Window Proc for main window
\r
4719 \*---------------------------------------------------------------------------*/
\r
4721 /* Process messages for main window, etc. */
\r
4723 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4726 int wmId, wmEvent;
\r
4730 char fileTitle[MSG_SIZ];
\r
4731 static SnapData sd;
\r
4733 switch (message) {
\r
4735 case WM_PAINT: /* message: repaint portion of window */
\r
4739 case WM_ERASEBKGND:
\r
4740 if (IsIconic(hwnd)) {
\r
4741 /* Cheat; change the message */
\r
4742 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4744 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4748 case WM_LBUTTONDOWN:
\r
4749 case WM_MBUTTONDOWN:
\r
4750 case WM_RBUTTONDOWN:
\r
4751 case WM_LBUTTONUP:
\r
4752 case WM_MBUTTONUP:
\r
4753 case WM_RBUTTONUP:
\r
4754 case WM_MOUSEMOVE:
\r
4755 MouseEvent(hwnd, message, wParam, lParam);
\r
4760 if (appData.icsActive) {
\r
4761 if (wParam == '\t') {
\r
4762 if (GetKeyState(VK_SHIFT) < 0) {
\r
4764 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4765 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4769 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4770 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4774 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4775 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4777 SendMessage(h, message, wParam, lParam);
\r
4779 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4780 PopUpMoveDialog((char)wParam);
\r
4784 case WM_PALETTECHANGED:
\r
4785 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4787 HDC hdc = GetDC(hwndMain);
\r
4788 SelectPalette(hdc, hPal, TRUE);
\r
4789 nnew = RealizePalette(hdc);
\r
4791 paletteChanged = TRUE;
\r
4793 UpdateColors(hdc);
\r
4795 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
4798 ReleaseDC(hwnd, hdc);
\r
4802 case WM_QUERYNEWPALETTE:
\r
4803 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4805 HDC hdc = GetDC(hwndMain);
\r
4806 paletteChanged = FALSE;
\r
4807 SelectPalette(hdc, hPal, FALSE);
\r
4808 nnew = RealizePalette(hdc);
\r
4810 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4812 ReleaseDC(hwnd, hdc);
\r
4817 case WM_COMMAND: /* message: command from application menu */
\r
4818 wmId = LOWORD(wParam);
\r
4819 wmEvent = HIWORD(wParam);
\r
4824 AnalysisPopDown();
\r
4827 case IDM_NewGameFRC:
\r
4828 if( NewGameFRC() == 0 ) {
\r
4830 AnalysisPopDown();
\r
4834 case IDM_LoadGame:
\r
4835 LoadGameDialog(hwnd, "Load Game from File");
\r
4838 case IDM_LoadNextGame:
\r
4842 case IDM_LoadPrevGame:
\r
4846 case IDM_ReloadGame:
\r
4850 case IDM_LoadPosition:
\r
4851 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4852 Reset(FALSE, TRUE);
\r
4855 f = OpenFileDialog(hwnd, FALSE, "",
\r
4856 appData.oldSaveStyle ? "pos" : "fen",
\r
4858 "Load Position from File", &number, fileTitle, NULL);
\r
4860 LoadPosition(f, number, fileTitle);
\r
4864 case IDM_LoadNextPosition:
\r
4865 ReloadPosition(1);
\r
4868 case IDM_LoadPrevPosition:
\r
4869 ReloadPosition(-1);
\r
4872 case IDM_ReloadPosition:
\r
4873 ReloadPosition(0);
\r
4876 case IDM_SaveGame:
\r
4877 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4878 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4879 appData.oldSaveStyle ? "gam" : "pgn",
\r
4881 "Save Game to File", NULL, fileTitle, NULL);
\r
4883 SaveGame(f, 0, "");
\r
4887 case IDM_SavePosition:
\r
4888 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4889 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4890 appData.oldSaveStyle ? "pos" : "fen",
\r
4892 "Save Position to File", NULL, fileTitle, NULL);
\r
4894 SavePosition(f, 0, "");
\r
4898 case IDM_CopyGame:
\r
4899 CopyGameToClipboard();
\r
4902 case IDM_PasteGame:
\r
4903 PasteGameFromClipboard();
\r
4906 case IDM_CopyGameListToClipboard:
\r
4907 CopyGameListToClipboard();
\r
4910 /* [AS] Autodetect FEN or PGN data */
\r
4911 case IDM_PasteAny:
\r
4912 PasteGameOrFENFromClipboard();
\r
4915 /* [AS] Move history */
\r
4916 case IDM_ShowMoveHistory:
\r
4917 if( MoveHistoryIsUp() ) {
\r
4918 MoveHistoryPopDown();
\r
4921 MoveHistoryPopUp();
\r
4925 /* [AS] Eval graph */
\r
4926 case IDM_ShowEvalGraph:
\r
4927 if( EvalGraphIsUp() ) {
\r
4928 EvalGraphPopDown();
\r
4935 /* [AS] Engine output */
\r
4936 case IDM_ShowEngineOutput:
\r
4937 if( EngineOutputIsUp() ) {
\r
4938 EngineOutputPopDown();
\r
4941 EngineOutputPopUp();
\r
4945 /* [AS] User adjudication */
\r
4946 case IDM_UserAdjudication_White:
\r
4947 UserAdjudicationEvent( +1 );
\r
4950 case IDM_UserAdjudication_Black:
\r
4951 UserAdjudicationEvent( -1 );
\r
4954 case IDM_UserAdjudication_Draw:
\r
4955 UserAdjudicationEvent( 0 );
\r
4958 /* [AS] Game list options dialog */
\r
4959 case IDM_GameListOptions:
\r
4960 GameListOptions();
\r
4963 case IDM_CopyPosition:
\r
4964 CopyFENToClipboard();
\r
4967 case IDM_PastePosition:
\r
4968 PasteFENFromClipboard();
\r
4971 case IDM_MailMove:
\r
4975 case IDM_ReloadCMailMsg:
\r
4976 Reset(TRUE, TRUE);
\r
4977 ReloadCmailMsgEvent(FALSE);
\r
4980 case IDM_Minimize:
\r
4981 ShowWindow(hwnd, SW_MINIMIZE);
\r
4988 case IDM_MachineWhite:
\r
4989 MachineWhiteEvent();
\r
4991 * refresh the tags dialog only if it's visible
\r
4993 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4995 tags = PGNTags(&gameInfo);
\r
4996 TagsPopUp(tags, CmailMsg());
\r
5001 case IDM_MachineBlack:
\r
5002 MachineBlackEvent();
\r
5004 * refresh the tags dialog only if it's visible
\r
5006 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5008 tags = PGNTags(&gameInfo);
\r
5009 TagsPopUp(tags, CmailMsg());
\r
5014 case IDM_TwoMachines:
\r
5015 TwoMachinesEvent();
\r
5017 * refresh the tags dialog only if it's visible
\r
5019 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5021 tags = PGNTags(&gameInfo);
\r
5022 TagsPopUp(tags, CmailMsg());
\r
5027 case IDM_AnalysisMode:
\r
5028 if (!first.analysisSupport) {
\r
5029 char buf[MSG_SIZ];
\r
5030 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5031 DisplayError(buf, 0);
\r
5033 if (!appData.showThinking) ToggleShowThinking();
\r
5034 AnalyzeModeEvent();
\r
5038 case IDM_AnalyzeFile:
\r
5039 if (!first.analysisSupport) {
\r
5040 char buf[MSG_SIZ];
\r
5041 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5042 DisplayError(buf, 0);
\r
5044 if (!appData.showThinking) ToggleShowThinking();
\r
5045 AnalyzeFileEvent();
\r
5046 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5047 AnalysisPeriodicEvent(1);
\r
5051 case IDM_IcsClient:
\r
5055 case IDM_EditGame:
\r
5059 case IDM_EditPosition:
\r
5060 EditPositionEvent();
\r
5063 case IDM_Training:
\r
5067 case IDM_ShowGameList:
\r
5068 ShowGameListProc();
\r
5071 case IDM_EditTags:
\r
5075 case IDM_EditComment:
\r
5076 if (commentDialogUp && editComment) {
\r
5079 EditCommentEvent();
\r
5099 case IDM_CallFlag:
\r
5119 case IDM_StopObserving:
\r
5120 StopObservingEvent();
\r
5123 case IDM_StopExamining:
\r
5124 StopExaminingEvent();
\r
5127 case IDM_TypeInMove:
\r
5128 PopUpMoveDialog('\000');
\r
5131 case IDM_Backward:
\r
5133 SetFocus(hwndMain);
\r
5138 SetFocus(hwndMain);
\r
5143 SetFocus(hwndMain);
\r
5148 SetFocus(hwndMain);
\r
5155 case IDM_TruncateGame:
\r
5156 TruncateGameEvent();
\r
5163 case IDM_RetractMove:
\r
5164 RetractMoveEvent();
\r
5167 case IDM_FlipView:
\r
5168 flipView = !flipView;
\r
5169 DrawPosition(FALSE, NULL);
\r
5172 case IDM_GeneralOptions:
\r
5173 GeneralOptionsPopup(hwnd);
\r
5174 DrawPosition(TRUE, NULL);
\r
5177 case IDM_BoardOptions:
\r
5178 BoardOptionsPopup(hwnd);
\r
5181 case IDM_EnginePlayOptions:
\r
5182 EnginePlayOptionsPopup(hwnd);
\r
5185 case IDM_OptionsUCI:
\r
5186 UciOptionsPopup(hwnd);
\r
5189 case IDM_IcsOptions:
\r
5190 IcsOptionsPopup(hwnd);
\r
5194 FontsOptionsPopup(hwnd);
\r
5198 SoundOptionsPopup(hwnd);
\r
5201 case IDM_CommPort:
\r
5202 CommPortOptionsPopup(hwnd);
\r
5205 case IDM_LoadOptions:
\r
5206 LoadOptionsPopup(hwnd);
\r
5209 case IDM_SaveOptions:
\r
5210 SaveOptionsPopup(hwnd);
\r
5213 case IDM_TimeControl:
\r
5214 TimeControlOptionsPopup(hwnd);
\r
5217 case IDM_SaveSettings:
\r
5218 SaveSettings(settingsFileName);
\r
5221 case IDM_SaveSettingsOnExit:
\r
5222 saveSettingsOnExit = !saveSettingsOnExit;
\r
5223 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5224 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5225 MF_CHECKED : MF_UNCHECKED));
\r
5236 case IDM_AboutGame:
\r
5241 appData.debugMode = !appData.debugMode;
\r
5242 if (appData.debugMode) {
\r
5243 char dir[MSG_SIZ];
\r
5244 GetCurrentDirectory(MSG_SIZ, dir);
\r
5245 SetCurrentDirectory(installDir);
\r
5246 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5247 SetCurrentDirectory(dir);
\r
5248 setbuf(debugFP, NULL);
\r
5255 case IDM_HELPCONTENTS:
\r
5256 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5257 MessageBox (GetFocus(),
\r
5258 "Unable to activate help",
\r
5259 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5263 case IDM_HELPSEARCH:
\r
5264 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5265 MessageBox (GetFocus(),
\r
5266 "Unable to activate help",
\r
5267 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5271 case IDM_HELPHELP:
\r
5272 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5273 MessageBox (GetFocus(),
\r
5274 "Unable to activate help",
\r
5275 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5280 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5282 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5283 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5284 FreeProcInstance(lpProc);
\r
5287 case IDM_DirectCommand1:
\r
5288 AskQuestionEvent("Direct Command",
\r
5289 "Send to chess program:", "", "1");
\r
5291 case IDM_DirectCommand2:
\r
5292 AskQuestionEvent("Direct Command",
\r
5293 "Send to second chess program:", "", "2");
\r
5296 case EP_WhitePawn:
\r
5297 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5298 fromX = fromY = -1;
\r
5301 case EP_WhiteKnight:
\r
5302 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5303 fromX = fromY = -1;
\r
5306 case EP_WhiteBishop:
\r
5307 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5308 fromX = fromY = -1;
\r
5311 case EP_WhiteRook:
\r
5312 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5313 fromX = fromY = -1;
\r
5316 case EP_WhiteQueen:
\r
5317 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5318 fromX = fromY = -1;
\r
5321 case EP_WhiteKing:
\r
5322 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5323 fromX = fromY = -1;
\r
5326 case EP_BlackPawn:
\r
5327 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5328 fromX = fromY = -1;
\r
5331 case EP_BlackKnight:
\r
5332 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5333 fromX = fromY = -1;
\r
5336 case EP_BlackBishop:
\r
5337 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5338 fromX = fromY = -1;
\r
5341 case EP_BlackRook:
\r
5342 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5343 fromX = fromY = -1;
\r
5346 case EP_BlackQueen:
\r
5347 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5348 fromX = fromY = -1;
\r
5351 case EP_BlackKing:
\r
5352 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5353 fromX = fromY = -1;
\r
5356 case EP_EmptySquare:
\r
5357 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5358 fromX = fromY = -1;
\r
5361 case EP_ClearBoard:
\r
5362 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5363 fromX = fromY = -1;
\r
5367 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5368 fromX = fromY = -1;
\r
5372 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5373 fromX = fromY = -1;
\r
5377 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5378 fromX = fromY = -1;
\r
5382 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5383 fromX = fromY = -1;
\r
5387 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5388 fromX = fromY = -1;
\r
5392 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5393 fromX = fromY = -1;
\r
5397 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5398 fromX = fromY = -1;
\r
5402 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5408 case CLOCK_TIMER_ID:
\r
5409 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5410 clockTimerEvent = 0;
\r
5411 DecrementClocks(); /* call into back end */
\r
5413 case LOAD_GAME_TIMER_ID:
\r
5414 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5415 loadGameTimerEvent = 0;
\r
5416 AutoPlayGameLoop(); /* call into back end */
\r
5418 case ANALYSIS_TIMER_ID:
\r
5419 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
5420 appData.periodicUpdates) {
\r
5421 AnalysisPeriodicEvent(0);
\r
5423 KillTimer(hwnd, analysisTimerEvent);
\r
5424 analysisTimerEvent = 0;
\r
5427 case DELAYED_TIMER_ID:
\r
5428 KillTimer(hwnd, delayedTimerEvent);
\r
5429 delayedTimerEvent = 0;
\r
5430 delayedTimerCallback();
\r
5435 case WM_USER_Input:
\r
5436 InputEvent(hwnd, message, wParam, lParam);
\r
5439 /* [AS] Also move "attached" child windows */
\r
5440 case WM_WINDOWPOSCHANGING:
\r
5441 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5442 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5444 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
5445 /* Window is moving */
\r
5448 GetWindowRect( hwnd, &rcMain );
\r
5450 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5451 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5452 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5457 /* [AS] Snapping */
\r
5458 case WM_ENTERSIZEMOVE:
\r
5459 if (hwnd == hwndMain) {
\r
5460 doingSizing = TRUE;
\r
5463 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5467 if (hwnd == hwndMain) {
\r
5468 lastSizing = wParam;
\r
5473 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5475 case WM_EXITSIZEMOVE:
\r
5476 if (hwnd == hwndMain) {
\r
5478 doingSizing = FALSE;
\r
5479 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5480 GetClientRect(hwnd, &client);
\r
5481 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5484 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5487 case WM_DESTROY: /* message: window being destroyed */
\r
5488 PostQuitMessage(0);
\r
5492 if (hwnd == hwndMain) {
\r
5497 default: /* Passes it on if unprocessed */
\r
5498 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5503 /*---------------------------------------------------------------------------*\
\r
5505 * Misc utility routines
\r
5507 \*---------------------------------------------------------------------------*/
\r
5510 * Decent random number generator, at least not as bad as Windows
\r
5511 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5513 unsigned int randstate;
\r
5518 randstate = randstate * 1664525 + 1013904223;
\r
5519 return (int) randstate & 0x7fffffff;
\r
5523 mysrandom(unsigned int seed)
\r
5530 * returns TRUE if user selects a different color, FALSE otherwise
\r
5534 ChangeColor(HWND hwnd, COLORREF *which)
\r
5536 static BOOL firstTime = TRUE;
\r
5537 static DWORD customColors[16];
\r
5539 COLORREF newcolor;
\r
5544 /* Make initial colors in use available as custom colors */
\r
5545 /* Should we put the compiled-in defaults here instead? */
\r
5547 customColors[i++] = lightSquareColor & 0xffffff;
\r
5548 customColors[i++] = darkSquareColor & 0xffffff;
\r
5549 customColors[i++] = whitePieceColor & 0xffffff;
\r
5550 customColors[i++] = blackPieceColor & 0xffffff;
\r
5551 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5552 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5554 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5555 customColors[i++] = textAttribs[ccl].color;
\r
5557 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5558 firstTime = FALSE;
\r
5561 cc.lStructSize = sizeof(cc);
\r
5562 cc.hwndOwner = hwnd;
\r
5563 cc.hInstance = NULL;
\r
5564 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5565 cc.lpCustColors = (LPDWORD) customColors;
\r
5566 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5568 if (!ChooseColor(&cc)) return FALSE;
\r
5570 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5571 if (newcolor == *which) return FALSE;
\r
5572 *which = newcolor;
\r
5576 InitDrawingColors();
\r
5577 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5582 MyLoadSound(MySound *ms)
\r
5588 if (ms->data) free(ms->data);
\r
5591 switch (ms->name[0]) {
\r
5597 /* System sound from Control Panel. Don't preload here. */
\r
5601 if (ms->name[1] == NULLCHAR) {
\r
5602 /* "!" alone = silence */
\r
5605 /* Builtin wave resource. Error if not found. */
\r
5606 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5607 if (h == NULL) break;
\r
5608 ms->data = (void *)LoadResource(hInst, h);
\r
5609 if (h == NULL) break;
\r
5614 /* .wav file. Error if not found. */
\r
5615 f = fopen(ms->name, "rb");
\r
5616 if (f == NULL) break;
\r
5617 if (fstat(fileno(f), &st) < 0) break;
\r
5618 ms->data = malloc(st.st_size);
\r
5619 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5625 char buf[MSG_SIZ];
\r
5626 sprintf(buf, "Error loading sound %s", ms->name);
\r
5627 DisplayError(buf, GetLastError());
\r
5633 MyPlaySound(MySound *ms)
\r
5635 BOOLEAN ok = FALSE;
\r
5636 switch (ms->name[0]) {
\r
5642 /* System sound from Control Panel (deprecated feature).
\r
5643 "$" alone or an unset sound name gets default beep (still in use). */
\r
5644 if (ms->name[1]) {
\r
5645 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5647 if (!ok) ok = MessageBeep(MB_OK);
\r
5650 /* Builtin wave resource, or "!" alone for silence */
\r
5651 if (ms->name[1]) {
\r
5652 if (ms->data == NULL) return FALSE;
\r
5653 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5659 /* .wav file. Error if not found. */
\r
5660 if (ms->data == NULL) return FALSE;
\r
5661 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5664 /* Don't print an error: this can happen innocently if the sound driver
\r
5665 is busy; for instance, if another instance of WinBoard is playing
\r
5666 a sound at about the same time. */
\r
5669 char buf[MSG_SIZ];
\r
5670 sprintf(buf, "Error playing sound %s", ms->name);
\r
5671 DisplayError(buf, GetLastError());
\r
5679 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5682 OPENFILENAME *ofn;
\r
5683 static UINT *number; /* gross that this is static */
\r
5685 switch (message) {
\r
5686 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5687 /* Center the dialog over the application window */
\r
5688 ofn = (OPENFILENAME *) lParam;
\r
5689 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5690 number = (UINT *) ofn->lCustData;
\r
5691 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5695 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5696 return FALSE; /* Allow for further processing */
\r
5699 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5700 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5702 return FALSE; /* Allow for further processing */
\r
5708 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5710 static UINT *number;
\r
5711 OPENFILENAME *ofname;
\r
5714 case WM_INITDIALOG:
\r
5715 ofname = (OPENFILENAME *)lParam;
\r
5716 number = (UINT *)(ofname->lCustData);
\r
5719 ofnot = (OFNOTIFY *)lParam;
\r
5720 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5721 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5730 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
5731 char *nameFilt, char *dlgTitle, UINT *number,
\r
5732 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5734 OPENFILENAME openFileName;
\r
5735 char buf1[MSG_SIZ];
\r
5738 if (fileName == NULL) fileName = buf1;
\r
5739 if (defName == NULL) {
\r
5740 strcpy(fileName, "*.");
\r
5741 strcat(fileName, defExt);
\r
5743 strcpy(fileName, defName);
\r
5745 if (fileTitle) strcpy(fileTitle, "");
\r
5746 if (number) *number = 0;
\r
5748 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5749 openFileName.hwndOwner = hwnd;
\r
5750 openFileName.hInstance = (HANDLE) hInst;
\r
5751 openFileName.lpstrFilter = nameFilt;
\r
5752 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5753 openFileName.nMaxCustFilter = 0L;
\r
5754 openFileName.nFilterIndex = 1L;
\r
5755 openFileName.lpstrFile = fileName;
\r
5756 openFileName.nMaxFile = MSG_SIZ;
\r
5757 openFileName.lpstrFileTitle = fileTitle;
\r
5758 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5759 openFileName.lpstrInitialDir = NULL;
\r
5760 openFileName.lpstrTitle = dlgTitle;
\r
5761 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5762 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
5763 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5764 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5765 openFileName.nFileOffset = 0;
\r
5766 openFileName.nFileExtension = 0;
\r
5767 openFileName.lpstrDefExt = defExt;
\r
5768 openFileName.lCustData = (LONG) number;
\r
5769 openFileName.lpfnHook = oldDialog ?
\r
5770 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5771 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5773 if (write ? GetSaveFileName(&openFileName) :
\r
5774 GetOpenFileName(&openFileName)) {
\r
5775 /* open the file */
\r
5776 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
5778 MessageBox(hwnd, "File open failed", NULL,
\r
5779 MB_OK|MB_ICONEXCLAMATION);
\r
5783 int err = CommDlgExtendedError();
\r
5784 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
5793 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5795 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5798 * Get the first pop-up menu in the menu template. This is the
\r
5799 * menu that TrackPopupMenu displays.
\r
5801 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5803 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5806 * TrackPopup uses screen coordinates, so convert the
\r
5807 * coordinates of the mouse click to screen coordinates.
\r
5809 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5811 /* Draw and track the floating pop-up menu. */
\r
5812 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5813 pt.x, pt.y, 0, hwnd, NULL);
\r
5815 /* Destroy the menu.*/
\r
5816 DestroyMenu(hmenu);
\r
5821 int sizeX, sizeY, newSizeX, newSizeY;
\r
5823 } ResizeEditPlusButtonsClosure;
\r
5826 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5828 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5832 if (hChild == cl->hText) return TRUE;
\r
5833 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5834 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5835 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5836 ScreenToClient(cl->hDlg, &pt);
\r
5837 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5838 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5842 /* Resize a dialog that has a (rich) edit field filling most of
\r
5843 the top, with a row of buttons below */
\r
5845 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
5848 int newTextHeight, newTextWidth;
\r
5849 ResizeEditPlusButtonsClosure cl;
\r
5851 /*if (IsIconic(hDlg)) return;*/
\r
5852 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
5854 cl.hdwp = BeginDeferWindowPos(8);
\r
5856 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
5857 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5858 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5859 if (newTextHeight < 0) {
\r
5860 newSizeY += -newTextHeight;
\r
5861 newTextHeight = 0;
\r
5863 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
5864 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5870 cl.newSizeX = newSizeX;
\r
5871 cl.newSizeY = newSizeY;
\r
5872 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
5874 EndDeferWindowPos(cl.hdwp);
\r
5877 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
5879 RECT rChild, rParent;
\r
5880 int wChild, hChild, wParent, hParent;
\r
5881 int wScreen, hScreen, xNew, yNew;
\r
5884 /* Get the Height and Width of the child window */
\r
5885 GetWindowRect (hwndChild, &rChild);
\r
5886 wChild = rChild.right - rChild.left;
\r
5887 hChild = rChild.bottom - rChild.top;
\r
5889 /* Get the Height and Width of the parent window */
\r
5890 GetWindowRect (hwndParent, &rParent);
\r
5891 wParent = rParent.right - rParent.left;
\r
5892 hParent = rParent.bottom - rParent.top;
\r
5894 /* Get the display limits */
\r
5895 hdc = GetDC (hwndChild);
\r
5896 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
5897 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
5898 ReleaseDC(hwndChild, hdc);
\r
5900 /* Calculate new X position, then adjust for screen */
\r
5901 xNew = rParent.left + ((wParent - wChild) /2);
\r
5904 } else if ((xNew+wChild) > wScreen) {
\r
5905 xNew = wScreen - wChild;
\r
5908 /* Calculate new Y position, then adjust for screen */
\r
5910 yNew = rParent.top + ((hParent - hChild) /2);
\r
5913 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
5918 } else if ((yNew+hChild) > hScreen) {
\r
5919 yNew = hScreen - hChild;
\r
5922 /* Set it, and return */
\r
5923 return SetWindowPos (hwndChild, NULL,
\r
5924 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
5927 /* Center one window over another */
\r
5928 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
5930 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
5933 /*---------------------------------------------------------------------------*\
\r
5935 * Startup Dialog functions
\r
5937 \*---------------------------------------------------------------------------*/
\r
5939 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
5941 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5943 while (*cd != NULL) {
\r
5944 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
5950 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
5952 char buf1[ARG_MAX];
\r
5955 if (str[0] == '@') {
\r
5956 FILE* f = fopen(str + 1, "r");
\r
5958 DisplayFatalError(str + 1, errno, 2);
\r
5961 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
5963 buf1[len] = NULLCHAR;
\r
5967 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5970 char buf[MSG_SIZ];
\r
5971 char *end = strchr(str, '\n');
\r
5972 if (end == NULL) return;
\r
5973 memcpy(buf, str, end - str);
\r
5974 buf[end - str] = NULLCHAR;
\r
5975 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
5981 SetStartupDialogEnables(HWND hDlg)
\r
5983 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5984 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5985 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5986 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5987 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
5988 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
5989 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5990 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
5991 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
5992 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
5993 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5994 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
5995 IsDlgButtonChecked(hDlg, OPT_View));
\r
5999 QuoteForFilename(char *filename)
\r
6001 int dquote, space;
\r
6002 dquote = strchr(filename, '"') != NULL;
\r
6003 space = strchr(filename, ' ') != NULL;
\r
6004 if (dquote || space) {
\r
6016 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6018 char buf[MSG_SIZ];
\r
6021 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6022 q = QuoteForFilename(nthcp);
\r
6023 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6024 if (*nthdir != NULLCHAR) {
\r
6025 q = QuoteForFilename(nthdir);
\r
6026 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6028 if (*nthcp == NULLCHAR) {
\r
6029 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6030 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6031 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6032 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6037 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6039 char buf[MSG_SIZ];
\r
6043 switch (message) {
\r
6044 case WM_INITDIALOG:
\r
6045 /* Center the dialog */
\r
6046 CenterWindow (hDlg, GetDesktopWindow());
\r
6047 /* Initialize the dialog items */
\r
6048 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6049 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6050 firstChessProgramNames);
\r
6051 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6052 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6053 secondChessProgramNames);
\r
6054 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6055 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6056 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6057 if (*appData.icsHelper != NULLCHAR) {
\r
6058 char *q = QuoteForFilename(appData.icsHelper);
\r
6059 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6061 if (*appData.icsHost == NULLCHAR) {
\r
6062 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6063 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6064 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6065 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6066 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6069 if (appData.icsActive) {
\r
6070 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6072 else if (appData.noChessProgram) {
\r
6073 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6076 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6079 SetStartupDialogEnables(hDlg);
\r
6083 switch (LOWORD(wParam)) {
\r
6085 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6086 strcpy(buf, "/fcp=");
\r
6087 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6089 ParseArgs(StringGet, &p);
\r
6090 strcpy(buf, "/scp=");
\r
6091 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6093 ParseArgs(StringGet, &p);
\r
6094 appData.noChessProgram = FALSE;
\r
6095 appData.icsActive = FALSE;
\r
6096 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6097 strcpy(buf, "/ics /icshost=");
\r
6098 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6100 ParseArgs(StringGet, &p);
\r
6101 if (appData.zippyPlay) {
\r
6102 strcpy(buf, "/fcp=");
\r
6103 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6105 ParseArgs(StringGet, &p);
\r
6107 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6108 appData.noChessProgram = TRUE;
\r
6109 appData.icsActive = FALSE;
\r
6111 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6112 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6115 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6116 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6118 ParseArgs(StringGet, &p);
\r
6120 EndDialog(hDlg, TRUE);
\r
6127 case IDM_HELPCONTENTS:
\r
6128 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6129 MessageBox (GetFocus(),
\r
6130 "Unable to activate help",
\r
6131 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6136 SetStartupDialogEnables(hDlg);
\r
6144 /*---------------------------------------------------------------------------*\
\r
6146 * About box dialog functions
\r
6148 \*---------------------------------------------------------------------------*/
\r
6150 /* Process messages for "About" dialog box */
\r
6152 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6154 switch (message) {
\r
6155 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6156 /* Center the dialog over the application window */
\r
6157 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6158 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6161 case WM_COMMAND: /* message: received a command */
\r
6162 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6163 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6164 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6172 /*---------------------------------------------------------------------------*\
\r
6174 * Comment Dialog functions
\r
6176 \*---------------------------------------------------------------------------*/
\r
6179 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6181 static HANDLE hwndText = NULL;
\r
6182 int len, newSizeX, newSizeY, flags;
\r
6183 static int sizeX, sizeY;
\r
6188 switch (message) {
\r
6189 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6190 /* Initialize the dialog items */
\r
6191 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6192 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6193 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6194 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6195 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6196 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6197 SetWindowText(hDlg, commentTitle);
\r
6198 if (editComment) {
\r
6199 SetFocus(hwndText);
\r
6201 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6203 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6204 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6205 MAKELPARAM(FALSE, 0));
\r
6206 /* Size and position the dialog */
\r
6207 if (!commentDialog) {
\r
6208 commentDialog = hDlg;
\r
6209 flags = SWP_NOZORDER;
\r
6210 GetClientRect(hDlg, &rect);
\r
6211 sizeX = rect.right;
\r
6212 sizeY = rect.bottom;
\r
6213 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
6214 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
6215 WINDOWPLACEMENT wp;
\r
6216 EnsureOnScreen(&commentX, &commentY);
\r
6217 wp.length = sizeof(WINDOWPLACEMENT);
\r
6219 wp.showCmd = SW_SHOW;
\r
6220 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6221 wp.rcNormalPosition.left = commentX;
\r
6222 wp.rcNormalPosition.right = commentX + commentW;
\r
6223 wp.rcNormalPosition.top = commentY;
\r
6224 wp.rcNormalPosition.bottom = commentY + commentH;
\r
6225 SetWindowPlacement(hDlg, &wp);
\r
6227 GetClientRect(hDlg, &rect);
\r
6228 newSizeX = rect.right;
\r
6229 newSizeY = rect.bottom;
\r
6230 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6231 newSizeX, newSizeY);
\r
6238 case WM_COMMAND: /* message: received a command */
\r
6239 switch (LOWORD(wParam)) {
\r
6241 if (editComment) {
\r
6243 /* Read changed options from the dialog box */
\r
6244 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6245 len = GetWindowTextLength(hwndText);
\r
6246 str = (char *) malloc(len + 1);
\r
6247 GetWindowText(hwndText, str, len + 1);
\r
6256 ReplaceComment(commentIndex, str);
\r
6263 case OPT_CancelComment:
\r
6267 case OPT_ClearComment:
\r
6268 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6271 case OPT_EditComment:
\r
6272 EditCommentEvent();
\r
6281 newSizeX = LOWORD(lParam);
\r
6282 newSizeY = HIWORD(lParam);
\r
6283 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6288 case WM_GETMINMAXINFO:
\r
6289 /* Prevent resizing window too small */
\r
6290 mmi = (MINMAXINFO *) lParam;
\r
6291 mmi->ptMinTrackSize.x = 100;
\r
6292 mmi->ptMinTrackSize.y = 100;
\r
6299 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6304 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6306 if (str == NULL) str = "";
\r
6307 p = (char *) malloc(2 * strlen(str) + 2);
\r
6310 if (*str == '\n') *q++ = '\r';
\r
6314 if (commentText != NULL) free(commentText);
\r
6316 commentIndex = index;
\r
6317 commentTitle = title;
\r
6319 editComment = edit;
\r
6321 if (commentDialog) {
\r
6322 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6323 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
6325 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6326 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6327 hwndMain, (DLGPROC)lpProc);
\r
6328 FreeProcInstance(lpProc);
\r
6330 commentDialogUp = TRUE;
\r
6334 /*---------------------------------------------------------------------------*\
\r
6336 * Type-in move dialog functions
\r
6338 \*---------------------------------------------------------------------------*/
\r
6341 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6343 char move[MSG_SIZ];
\r
6345 ChessMove moveType;
\r
6346 int fromX, fromY, toX, toY;
\r
6349 switch (message) {
\r
6350 case WM_INITDIALOG:
\r
6351 move[0] = (char) lParam;
\r
6352 move[1] = NULLCHAR;
\r
6353 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6354 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6355 SetWindowText(hInput, move);
\r
6357 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6361 switch (LOWORD(wParam)) {
\r
6363 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
6364 gameMode != Training) {
\r
6365 DisplayMoveError("Displayed move is not current");
\r
6367 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6368 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6369 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
6370 if (gameMode != Training)
\r
6371 forwardMostMove = currentMove;
\r
6372 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
6374 DisplayMoveError("Could not parse move");
\r
6377 EndDialog(hDlg, TRUE);
\r
6380 EndDialog(hDlg, FALSE);
\r
6391 PopUpMoveDialog(char firstchar)
\r
6395 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
6396 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
6397 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
6398 gameMode == EditPosition || gameMode == IcsExamining ||
\r
6399 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
6400 gameMode == Training) {
\r
6401 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6402 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6403 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6404 FreeProcInstance(lpProc);
\r
6408 /*---------------------------------------------------------------------------*\
\r
6412 \*---------------------------------------------------------------------------*/
\r
6414 /* Nonmodal error box */
\r
6415 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6416 WPARAM wParam, LPARAM lParam);
\r
6419 ErrorPopUp(char *title, char *content)
\r
6423 BOOLEAN modal = hwndMain == NULL;
\r
6441 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6442 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6445 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6447 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6448 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6449 hwndMain, (DLGPROC)lpProc);
\r
6450 FreeProcInstance(lpProc);
\r
6457 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6458 if (errorDialog == NULL) return;
\r
6459 DestroyWindow(errorDialog);
\r
6460 errorDialog = NULL;
\r
6464 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6469 switch (message) {
\r
6470 case WM_INITDIALOG:
\r
6471 GetWindowRect(hDlg, &rChild);
\r
6474 SetWindowPos(hDlg, NULL, rChild.left,
\r
6475 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6476 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6480 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6481 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6482 and it doesn't work when you resize the dialog.
\r
6483 For now, just give it a default position.
\r
6485 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6487 errorDialog = hDlg;
\r
6488 SetWindowText(hDlg, errorTitle);
\r
6489 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6490 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6494 switch (LOWORD(wParam)) {
\r
6497 if (errorDialog == hDlg) errorDialog = NULL;
\r
6498 DestroyWindow(hDlg);
\r
6511 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6515 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6517 switch (message) {
\r
6518 case WM_INITDIALOG:
\r
6519 GetWindowRect(hDlg, &rChild);
\r
6521 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
6525 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6526 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6527 and it doesn't work when you resize the dialog.
\r
6528 For now, just give it a default position.
\r
6531 SetWindowText(hDlg, errorTitle);
\r
6532 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6533 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6537 switch (LOWORD(wParam)) {
\r
6540 if (errorDialog == hDlg) errorDialog = NULL;
\r
6541 DestroyWindow(hDlg);
\r
6553 GothicPopUp(char *title)
\r
6557 BOOLEAN modal = hwndMain == NULL;
\r
6559 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6560 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6562 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6563 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6564 hwndMain, (DLGPROC)lpProc);
\r
6565 FreeProcInstance(lpProc);
\r
6569 /*---------------------------------------------------------------------------*\
\r
6571 * Ics Interaction console functions
\r
6573 \*---------------------------------------------------------------------------*/
\r
6575 #define HISTORY_SIZE 64
\r
6576 static char *history[HISTORY_SIZE];
\r
6577 int histIn = 0, histP = 0;
\r
6580 SaveInHistory(char *cmd)
\r
6582 if (history[histIn] != NULL) {
\r
6583 free(history[histIn]);
\r
6584 history[histIn] = NULL;
\r
6586 if (*cmd == NULLCHAR) return;
\r
6587 history[histIn] = StrSave(cmd);
\r
6588 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6589 if (history[histIn] != NULL) {
\r
6590 free(history[histIn]);
\r
6591 history[histIn] = NULL;
\r
6597 PrevInHistory(char *cmd)
\r
6600 if (histP == histIn) {
\r
6601 if (history[histIn] != NULL) free(history[histIn]);
\r
6602 history[histIn] = StrSave(cmd);
\r
6604 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6605 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6607 return history[histP];
\r
6613 if (histP == histIn) return NULL;
\r
6614 histP = (histP + 1) % HISTORY_SIZE;
\r
6615 return history[histP];
\r
6622 BOOLEAN immediate;
\r
6623 } IcsTextMenuEntry;
\r
6624 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
6625 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
6628 ParseIcsTextMenu(char *icsTextMenuString)
\r
6631 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
6632 char *p = icsTextMenuString;
\r
6633 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6636 if (e->command != NULL) {
\r
6638 e->command = NULL;
\r
6642 e = icsTextMenuEntry;
\r
6643 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6644 if (*p == ';' || *p == '\n') {
\r
6645 e->item = strdup("-");
\r
6646 e->command = NULL;
\r
6648 } else if (*p == '-') {
\r
6649 e->item = strdup("-");
\r
6650 e->command = NULL;
\r
6654 char *q, *r, *s, *t;
\r
6656 q = strchr(p, ',');
\r
6657 if (q == NULL) break;
\r
6659 r = strchr(q + 1, ',');
\r
6660 if (r == NULL) break;
\r
6662 s = strchr(r + 1, ',');
\r
6663 if (s == NULL) break;
\r
6666 t = strchr(s + 1, c);
\r
6669 t = strchr(s + 1, c);
\r
6671 if (t != NULL) *t = NULLCHAR;
\r
6672 e->item = strdup(p);
\r
6673 e->command = strdup(q + 1);
\r
6674 e->getname = *(r + 1) != '0';
\r
6675 e->immediate = *(s + 1) != '0';
\r
6679 if (t == NULL) break;
\r
6688 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6692 hmenu = LoadMenu(hInst, "TextMenu");
\r
6693 h = GetSubMenu(hmenu, 0);
\r
6695 if (strcmp(e->item, "-") == 0) {
\r
6696 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6698 if (e->item[0] == '|') {
\r
6699 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6700 IDM_CommandX + i, &e->item[1]);
\r
6702 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
6711 WNDPROC consoleTextWindowProc;
\r
6714 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6716 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6717 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6721 SetWindowText(hInput, command);
\r
6723 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6725 sel.cpMin = 999999;
\r
6726 sel.cpMax = 999999;
\r
6727 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6732 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6733 if (sel.cpMin == sel.cpMax) {
\r
6734 /* Expand to surrounding word */
\r
6737 tr.chrg.cpMax = sel.cpMin;
\r
6738 tr.chrg.cpMin = --sel.cpMin;
\r
6739 if (sel.cpMin < 0) break;
\r
6740 tr.lpstrText = name;
\r
6741 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6742 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6746 tr.chrg.cpMin = sel.cpMax;
\r
6747 tr.chrg.cpMax = ++sel.cpMax;
\r
6748 tr.lpstrText = name;
\r
6749 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6750 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6753 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6754 MessageBeep(MB_ICONEXCLAMATION);
\r
6758 tr.lpstrText = name;
\r
6759 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6761 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6762 MessageBeep(MB_ICONEXCLAMATION);
\r
6765 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6768 sprintf(buf, "%s %s", command, name);
\r
6769 SetWindowText(hInput, buf);
\r
6770 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6772 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
6773 SetWindowText(hInput, buf);
\r
6774 sel.cpMin = 999999;
\r
6775 sel.cpMax = 999999;
\r
6776 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6782 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6787 switch (message) {
\r
6789 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6792 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6795 sel.cpMin = 999999;
\r
6796 sel.cpMax = 999999;
\r
6797 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6798 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6803 if (wParam == '\t') {
\r
6804 if (GetKeyState(VK_SHIFT) < 0) {
\r
6806 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6807 if (buttonDesc[0].hwnd) {
\r
6808 SetFocus(buttonDesc[0].hwnd);
\r
6810 SetFocus(hwndMain);
\r
6814 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
6817 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6819 SendMessage(hInput, message, wParam, lParam);
\r
6823 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6825 return SendMessage(hInput, message, wParam, lParam);
\r
6826 case WM_MBUTTONDOWN:
\r
6827 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6828 case WM_RBUTTONDOWN:
\r
6829 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6830 /* Move selection here if it was empty */
\r
6832 pt.x = LOWORD(lParam);
\r
6833 pt.y = HIWORD(lParam);
\r
6834 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6835 if (sel.cpMin == sel.cpMax) {
\r
6836 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6837 sel.cpMax = sel.cpMin;
\r
6838 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6840 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6843 case WM_RBUTTONUP:
\r
6844 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6845 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6846 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6849 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6850 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6851 if (sel.cpMin == sel.cpMax) {
\r
6852 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6853 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6855 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6856 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6858 pt.x = LOWORD(lParam);
\r
6859 pt.y = HIWORD(lParam);
\r
6860 MenuPopup(hwnd, pt, hmenu, -1);
\r
6864 switch (LOWORD(wParam)) {
\r
6865 case IDM_QuickPaste:
\r
6867 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6868 if (sel.cpMin == sel.cpMax) {
\r
6869 MessageBeep(MB_ICONEXCLAMATION);
\r
6872 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6873 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6874 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6879 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6882 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6885 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6889 int i = LOWORD(wParam) - IDM_CommandX;
\r
6890 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
6891 icsTextMenuEntry[i].command != NULL) {
\r
6892 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
6893 icsTextMenuEntry[i].getname,
\r
6894 icsTextMenuEntry[i].immediate);
\r
6902 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
6905 WNDPROC consoleInputWindowProc;
\r
6908 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6910 char buf[MSG_SIZ];
\r
6912 static BOOL sendNextChar = FALSE;
\r
6913 static BOOL quoteNextChar = FALSE;
\r
6914 InputSource *is = consoleInputSource;
\r
6918 switch (message) {
\r
6920 if (!appData.localLineEditing || sendNextChar) {
\r
6921 is->buf[0] = (CHAR) wParam;
\r
6923 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6924 sendNextChar = FALSE;
\r
6927 if (quoteNextChar) {
\r
6928 buf[0] = (char) wParam;
\r
6929 buf[1] = NULLCHAR;
\r
6930 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
6931 quoteNextChar = FALSE;
\r
6935 case '\r': /* Enter key */
\r
6936 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
6937 if (consoleEcho) SaveInHistory(is->buf);
\r
6938 is->buf[is->count++] = '\n';
\r
6939 is->buf[is->count] = NULLCHAR;
\r
6940 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6941 if (consoleEcho) {
\r
6942 ConsoleOutput(is->buf, is->count, TRUE);
\r
6943 } else if (appData.localLineEditing) {
\r
6944 ConsoleOutput("\n", 1, TRUE);
\r
6947 case '\033': /* Escape key */
\r
6948 SetWindowText(hwnd, "");
\r
6949 cf.cbSize = sizeof(CHARFORMAT);
\r
6950 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6951 if (consoleEcho) {
\r
6952 cf.crTextColor = textAttribs[ColorNormal].color;
\r
6954 cf.crTextColor = COLOR_ECHOOFF;
\r
6956 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
6957 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6959 case '\t': /* Tab key */
\r
6960 if (GetKeyState(VK_SHIFT) < 0) {
\r
6962 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
6965 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6966 if (buttonDesc[0].hwnd) {
\r
6967 SetFocus(buttonDesc[0].hwnd);
\r
6969 SetFocus(hwndMain);
\r
6973 case '\023': /* Ctrl+S */
\r
6974 sendNextChar = TRUE;
\r
6976 case '\021': /* Ctrl+Q */
\r
6977 quoteNextChar = TRUE;
\r
6986 GetWindowText(hwnd, buf, MSG_SIZ);
\r
6987 p = PrevInHistory(buf);
\r
6989 SetWindowText(hwnd, p);
\r
6990 sel.cpMin = 999999;
\r
6991 sel.cpMax = 999999;
\r
6992 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6997 p = NextInHistory();
\r
6999 SetWindowText(hwnd, p);
\r
7000 sel.cpMin = 999999;
\r
7001 sel.cpMax = 999999;
\r
7002 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7008 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7012 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7016 case WM_MBUTTONDOWN:
\r
7017 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7018 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7020 case WM_RBUTTONUP:
\r
7021 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7022 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7023 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7027 hmenu = LoadMenu(hInst, "InputMenu");
\r
7028 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7029 if (sel.cpMin == sel.cpMax) {
\r
7030 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7031 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7033 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7034 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7036 pt.x = LOWORD(lParam);
\r
7037 pt.y = HIWORD(lParam);
\r
7038 MenuPopup(hwnd, pt, hmenu, -1);
\r
7042 switch (LOWORD(wParam)) {
\r
7044 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7046 case IDM_SelectAll:
\r
7048 sel.cpMax = -1; /*999999?*/
\r
7049 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7052 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7055 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7058 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7063 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7066 #define CO_MAX 100000
\r
7067 #define CO_TRIM 1000
\r
7070 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7072 static SnapData sd;
\r
7073 static HWND hText, hInput, hFocus;
\r
7074 InputSource *is = consoleInputSource;
\r
7076 static int sizeX, sizeY;
\r
7077 int newSizeX, newSizeY;
\r
7080 switch (message) {
\r
7081 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7082 hwndConsole = hDlg;
\r
7083 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7084 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7086 consoleTextWindowProc = (WNDPROC)
\r
7087 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7088 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7089 consoleInputWindowProc = (WNDPROC)
\r
7090 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7091 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7092 Colorize(ColorNormal, TRUE);
\r
7093 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7094 ChangedConsoleFont();
\r
7095 GetClientRect(hDlg, &rect);
\r
7096 sizeX = rect.right;
\r
7097 sizeY = rect.bottom;
\r
7098 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7099 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7100 WINDOWPLACEMENT wp;
\r
7101 EnsureOnScreen(&consoleX, &consoleY);
\r
7102 wp.length = sizeof(WINDOWPLACEMENT);
\r
7104 wp.showCmd = SW_SHOW;
\r
7105 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7106 wp.rcNormalPosition.left = consoleX;
\r
7107 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7108 wp.rcNormalPosition.top = consoleY;
\r
7109 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7110 SetWindowPlacement(hDlg, &wp);
\r
7124 if (IsIconic(hDlg)) break;
\r
7125 newSizeX = LOWORD(lParam);
\r
7126 newSizeY = HIWORD(lParam);
\r
7127 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7128 RECT rectText, rectInput;
\r
7130 int newTextHeight, newTextWidth;
\r
7131 GetWindowRect(hText, &rectText);
\r
7132 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7133 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7134 if (newTextHeight < 0) {
\r
7135 newSizeY += -newTextHeight;
\r
7136 newTextHeight = 0;
\r
7138 SetWindowPos(hText, NULL, 0, 0,
\r
7139 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7140 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7141 pt.x = rectInput.left;
\r
7142 pt.y = rectInput.top + newSizeY - sizeY;
\r
7143 ScreenToClient(hDlg, &pt);
\r
7144 SetWindowPos(hInput, NULL,
\r
7145 pt.x, pt.y, /* needs client coords */
\r
7146 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7147 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7153 case WM_GETMINMAXINFO:
\r
7154 /* Prevent resizing window too small */
\r
7155 mmi = (MINMAXINFO *) lParam;
\r
7156 mmi->ptMinTrackSize.x = 100;
\r
7157 mmi->ptMinTrackSize.y = 100;
\r
7160 /* [AS] Snapping */
\r
7161 case WM_ENTERSIZEMOVE:
\r
7162 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7165 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7168 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7170 case WM_EXITSIZEMOVE:
\r
7171 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7174 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7182 if (hwndConsole) return;
\r
7183 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7184 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7189 ConsoleOutput(char* data, int length, int forceVisible)
\r
7194 char buf[CO_MAX+1];
\r
7197 static int delayLF = 0;
\r
7198 CHARRANGE savesel, sel;
\r
7200 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7208 while (length--) {
\r
7216 } else if (*p == '\007') {
\r
7217 MyPlaySound(&sounds[(int)SoundBell]);
\r
7224 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7225 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7226 /* Save current selection */
\r
7227 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7228 exlen = GetWindowTextLength(hText);
\r
7229 /* Find out whether current end of text is visible */
\r
7230 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7231 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7232 /* Trim existing text if it's too long */
\r
7233 if (exlen + (q - buf) > CO_MAX) {
\r
7234 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7237 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7238 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7240 savesel.cpMin -= trim;
\r
7241 savesel.cpMax -= trim;
\r
7242 if (exlen < 0) exlen = 0;
\r
7243 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7244 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7246 /* Append the new text */
\r
7247 sel.cpMin = exlen;
\r
7248 sel.cpMax = exlen;
\r
7249 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7250 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7251 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7252 if (forceVisible || exlen == 0 ||
\r
7253 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7254 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7255 /* Scroll to make new end of text visible if old end of text
\r
7256 was visible or new text is an echo of user typein */
\r
7257 sel.cpMin = 9999999;
\r
7258 sel.cpMax = 9999999;
\r
7259 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7260 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7261 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7262 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7264 if (savesel.cpMax == exlen || forceVisible) {
\r
7265 /* Move insert point to new end of text if it was at the old
\r
7266 end of text or if the new text is an echo of user typein */
\r
7267 sel.cpMin = 9999999;
\r
7268 sel.cpMax = 9999999;
\r
7269 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7271 /* Restore previous selection */
\r
7272 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7274 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7281 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7282 RECT *rect, char *color, char *flagFell)
\r
7286 COLORREF oldFg, oldBg;
\r
7289 if (appData.clockMode) {
\r
7291 sprintf(buf, "%c %s %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7293 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
7300 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7301 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7303 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7304 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7306 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7308 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7309 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7310 rect, str, strlen(str), NULL);
\r
7312 (void) SetTextColor(hdc, oldFg);
\r
7313 (void) SetBkColor(hdc, oldBg);
\r
7314 (void) SelectObject(hdc, oldFont);
\r
7319 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7325 if( count <= 0 ) {
\r
7326 if (appData.debugMode) {
\r
7327 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7330 return ERROR_INVALID_USER_BUFFER;
\r
7333 ResetEvent(ovl->hEvent);
\r
7334 ovl->Offset = ovl->OffsetHigh = 0;
\r
7335 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7339 err = GetLastError();
\r
7340 if (err == ERROR_IO_PENDING) {
\r
7341 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7345 err = GetLastError();
\r
7352 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7357 ResetEvent(ovl->hEvent);
\r
7358 ovl->Offset = ovl->OffsetHigh = 0;
\r
7359 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7363 err = GetLastError();
\r
7364 if (err == ERROR_IO_PENDING) {
\r
7365 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7369 err = GetLastError();
\r
7375 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7376 void CheckForInputBufferFull( InputSource * is )
\r
7378 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7379 /* Look for end of line */
\r
7380 char * p = is->buf;
\r
7382 while( p < is->next && *p != '\n' ) {
\r
7386 if( p >= is->next ) {
\r
7387 if (appData.debugMode) {
\r
7388 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
7391 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7392 is->count = (DWORD) -1;
\r
7393 is->next = is->buf;
\r
7399 InputThread(LPVOID arg)
\r
7404 is = (InputSource *) arg;
\r
7405 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7406 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7407 while (is->hThread != NULL) {
\r
7408 is->error = DoReadFile(is->hFile, is->next,
\r
7409 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7410 &is->count, &ovl);
\r
7411 if (is->error == NO_ERROR) {
\r
7412 is->next += is->count;
\r
7414 if (is->error == ERROR_BROKEN_PIPE) {
\r
7415 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7418 is->count = (DWORD) -1;
\r
7419 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7424 CheckForInputBufferFull( is );
\r
7426 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7428 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7430 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7433 CloseHandle(ovl.hEvent);
\r
7434 CloseHandle(is->hFile);
\r
7436 if (appData.debugMode) {
\r
7437 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
7444 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7446 NonOvlInputThread(LPVOID arg)
\r
7453 is = (InputSource *) arg;
\r
7454 while (is->hThread != NULL) {
\r
7455 is->error = ReadFile(is->hFile, is->next,
\r
7456 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7457 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7458 if (is->error == NO_ERROR) {
\r
7459 /* Change CRLF to LF */
\r
7460 if (is->next > is->buf) {
\r
7462 i = is->count + 1;
\r
7470 if (prev == '\r' && *p == '\n') {
\r
7482 if (is->error == ERROR_BROKEN_PIPE) {
\r
7483 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7486 is->count = (DWORD) -1;
\r
7490 CheckForInputBufferFull( is );
\r
7492 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7494 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7496 if (is->count < 0) break; /* Quit on error */
\r
7498 CloseHandle(is->hFile);
\r
7503 SocketInputThread(LPVOID arg)
\r
7507 is = (InputSource *) arg;
\r
7508 while (is->hThread != NULL) {
\r
7509 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7510 if ((int)is->count == SOCKET_ERROR) {
\r
7511 is->count = (DWORD) -1;
\r
7512 is->error = WSAGetLastError();
\r
7514 is->error = NO_ERROR;
\r
7515 is->next += is->count;
\r
7516 if (is->count == 0 && is->second == is) {
\r
7517 /* End of file on stderr; quit with no message */
\r
7521 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7523 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7525 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7531 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7535 is = (InputSource *) lParam;
\r
7536 if (is->lineByLine) {
\r
7537 /* Feed in lines one by one */
\r
7538 char *p = is->buf;
\r
7540 while (q < is->next) {
\r
7541 if (*q++ == '\n') {
\r
7542 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7547 /* Move any partial line to the start of the buffer */
\r
7549 while (p < is->next) {
\r
7554 if (is->error != NO_ERROR || is->count == 0) {
\r
7555 /* Notify backend of the error. Note: If there was a partial
\r
7556 line at the end, it is not flushed through. */
\r
7557 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7560 /* Feed in the whole chunk of input at once */
\r
7561 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7562 is->next = is->buf;
\r
7566 /*---------------------------------------------------------------------------*\
\r
7568 * Menu enables. Used when setting various modes.
\r
7570 \*---------------------------------------------------------------------------*/
\r
7578 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7580 while (enab->item > 0) {
\r
7581 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7586 Enables gnuEnables[] = {
\r
7587 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7588 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7589 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7590 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7591 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7592 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7593 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7594 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7595 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7596 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7600 Enables icsEnables[] = {
\r
7601 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7602 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7603 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7604 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7605 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7606 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7607 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7608 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7609 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7610 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7611 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7612 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7617 Enables zippyEnables[] = {
\r
7618 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7619 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7620 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7625 Enables ncpEnables[] = {
\r
7626 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7627 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7628 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7629 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7630 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7631 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7632 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7633 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7634 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7635 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7636 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7637 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7638 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7639 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7640 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7644 Enables trainingOnEnables[] = {
\r
7645 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7646 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7647 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7648 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7649 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7650 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7651 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7652 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7656 Enables trainingOffEnables[] = {
\r
7657 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7658 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7659 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7660 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7661 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7662 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7663 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7664 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7668 /* These modify either ncpEnables or gnuEnables */
\r
7669 Enables cmailEnables[] = {
\r
7670 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7671 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7672 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7673 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7674 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7675 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7676 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7680 Enables machineThinkingEnables[] = {
\r
7681 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7682 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7683 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7684 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7685 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7686 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7687 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7688 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7689 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7690 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7691 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7692 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7693 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7694 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7695 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7699 Enables userThinkingEnables[] = {
\r
7700 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7701 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7702 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7703 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7704 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7705 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7706 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7707 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7708 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7709 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7710 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7711 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7712 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7713 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7714 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7718 /*---------------------------------------------------------------------------*\
\r
7720 * Front-end interface functions exported by XBoard.
\r
7721 * Functions appear in same order as prototypes in frontend.h.
\r
7723 \*---------------------------------------------------------------------------*/
\r
7727 static UINT prevChecked = 0;
\r
7728 static int prevPausing = 0;
\r
7731 if (pausing != prevPausing) {
\r
7732 prevPausing = pausing;
\r
7733 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7734 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
7735 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
7738 switch (gameMode) {
\r
7739 case BeginningOfGame:
\r
7740 if (appData.icsActive)
\r
7741 nowChecked = IDM_IcsClient;
\r
7742 else if (appData.noChessProgram)
\r
7743 nowChecked = IDM_EditGame;
\r
7745 nowChecked = IDM_MachineBlack;
\r
7747 case MachinePlaysBlack:
\r
7748 nowChecked = IDM_MachineBlack;
\r
7750 case MachinePlaysWhite:
\r
7751 nowChecked = IDM_MachineWhite;
\r
7753 case TwoMachinesPlay:
\r
7754 nowChecked = IDM_TwoMachines;
\r
7757 nowChecked = IDM_AnalysisMode;
\r
7760 nowChecked = IDM_AnalyzeFile;
\r
7763 nowChecked = IDM_EditGame;
\r
7765 case PlayFromGameFile:
\r
7766 nowChecked = IDM_LoadGame;
\r
7768 case EditPosition:
\r
7769 nowChecked = IDM_EditPosition;
\r
7772 nowChecked = IDM_Training;
\r
7774 case IcsPlayingWhite:
\r
7775 case IcsPlayingBlack:
\r
7776 case IcsObserving:
\r
7778 nowChecked = IDM_IcsClient;
\r
7785 if (prevChecked != 0)
\r
7786 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7787 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
7788 if (nowChecked != 0)
\r
7789 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7790 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
7792 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
7793 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
7794 MF_BYCOMMAND|MF_ENABLED);
\r
7796 (void) EnableMenuItem(GetMenu(hwndMain),
\r
7797 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
7800 prevChecked = nowChecked;
\r
7806 HMENU hmenu = GetMenu(hwndMain);
\r
7807 SetMenuEnables(hmenu, icsEnables);
\r
7808 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
7809 MF_BYPOSITION|MF_ENABLED);
\r
7811 if (appData.zippyPlay) {
\r
7812 SetMenuEnables(hmenu, zippyEnables);
\r
7820 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
7826 HMENU hmenu = GetMenu(hwndMain);
\r
7827 SetMenuEnables(hmenu, ncpEnables);
\r
7828 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
7829 MF_BYPOSITION|MF_GRAYED);
\r
7830 DrawMenuBar(hwndMain);
\r
7836 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
7840 SetTrainingModeOn()
\r
7843 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
7844 for (i = 0; i < N_BUTTONS; i++) {
\r
7845 if (buttonDesc[i].hwnd != NULL)
\r
7846 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
7851 VOID SetTrainingModeOff()
\r
7854 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
7855 for (i = 0; i < N_BUTTONS; i++) {
\r
7856 if (buttonDesc[i].hwnd != NULL)
\r
7857 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
7863 SetUserThinkingEnables()
\r
7865 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
7869 SetMachineThinkingEnables()
\r
7871 HMENU hMenu = GetMenu(hwndMain);
\r
7872 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
7874 SetMenuEnables(hMenu, machineThinkingEnables);
\r
7876 if (gameMode == MachinePlaysBlack) {
\r
7877 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
7878 } else if (gameMode == MachinePlaysWhite) {
\r
7879 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
7880 } else if (gameMode == TwoMachinesPlay) {
\r
7881 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
7887 DisplayTitle(char *str)
\r
7889 char title[MSG_SIZ], *host;
\r
7890 if (str[0] != NULLCHAR) {
\r
7891 strcpy(title, str);
\r
7892 } else if (appData.icsActive) {
\r
7893 if (appData.icsCommPort[0] != NULLCHAR)
\r
7896 host = appData.icsHost;
\r
7897 sprintf(title, "%s: %s", szTitle, host);
\r
7898 } else if (appData.noChessProgram) {
\r
7899 strcpy(title, szTitle);
\r
7901 strcpy(title, szTitle);
\r
7902 strcat(title, ": ");
\r
7903 strcat(title, first.tidy);
\r
7905 SetWindowText(hwndMain, title);
\r
7910 DisplayMessage(char *str1, char *str2)
\r
7914 int remain = MESSAGE_TEXT_MAX - 1;
\r
7917 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
7918 messageText[0] = NULLCHAR;
\r
7920 len = strlen(str1);
\r
7921 if (len > remain) len = remain;
\r
7922 strncpy(messageText, str1, len);
\r
7923 messageText[len] = NULLCHAR;
\r
7926 if (*str2 && remain >= 2) {
\r
7928 strcat(messageText, " ");
\r
7931 len = strlen(str2);
\r
7932 if (len > remain) len = remain;
\r
7933 strncat(messageText, str2, len);
\r
7935 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
7937 if (IsIconic(hwndMain)) return;
\r
7938 hdc = GetDC(hwndMain);
\r
7939 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
7940 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7941 &messageRect, messageText, strlen(messageText), NULL);
\r
7942 (void) SelectObject(hdc, oldFont);
\r
7943 (void) ReleaseDC(hwndMain, hdc);
\r
7947 DisplayError(char *str, int error)
\r
7949 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
7955 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7956 NULL, error, LANG_NEUTRAL,
\r
7957 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7959 sprintf(buf, "%s:\n%s", str, buf2);
\r
7961 ErrorMap *em = errmap;
\r
7962 while (em->err != 0 && em->err != error) em++;
\r
7963 if (em->err != 0) {
\r
7964 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7966 sprintf(buf, "%s:\nError code %d", str, error);
\r
7971 ErrorPopUp("Error", buf);
\r
7976 DisplayMoveError(char *str)
\r
7978 fromX = fromY = -1;
\r
7979 ClearHighlights();
\r
7980 DrawPosition(FALSE, NULL);
\r
7981 if (appData.popupMoveErrors) {
\r
7982 ErrorPopUp("Error", str);
\r
7984 DisplayMessage(str, "");
\r
7985 moveErrorMessageUp = TRUE;
\r
7990 DisplayFatalError(char *str, int error, int exitStatus)
\r
7992 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
7994 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
7997 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7998 NULL, error, LANG_NEUTRAL,
\r
7999 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8001 sprintf(buf, "%s:\n%s", str, buf2);
\r
8003 ErrorMap *em = errmap;
\r
8004 while (em->err != 0 && em->err != error) em++;
\r
8005 if (em->err != 0) {
\r
8006 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8008 sprintf(buf, "%s:\nError code %d", str, error);
\r
8013 if (appData.debugMode) {
\r
8014 fprintf(debugFP, "%s: %s\n", label, str);
\r
8016 if (appData.popupExitMessage) {
\r
8017 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8018 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8020 ExitEvent(exitStatus);
\r
8025 DisplayInformation(char *str)
\r
8027 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8032 DisplayNote(char *str)
\r
8034 ErrorPopUp("Note", str);
\r
8039 char *title, *question, *replyPrefix;
\r
8044 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8046 static QuestionParams *qp;
\r
8047 char reply[MSG_SIZ];
\r
8050 switch (message) {
\r
8051 case WM_INITDIALOG:
\r
8052 qp = (QuestionParams *) lParam;
\r
8053 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8054 SetWindowText(hDlg, qp->title);
\r
8055 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8056 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8060 switch (LOWORD(wParam)) {
\r
8062 strcpy(reply, qp->replyPrefix);
\r
8063 if (*reply) strcat(reply, " ");
\r
8064 len = strlen(reply);
\r
8065 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8066 strcat(reply, "\n");
\r
8067 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8068 EndDialog(hDlg, TRUE);
\r
8069 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8072 EndDialog(hDlg, FALSE);
\r
8083 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8085 QuestionParams qp;
\r
8089 qp.question = question;
\r
8090 qp.replyPrefix = replyPrefix;
\r
8092 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8093 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8094 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8095 FreeProcInstance(lpProc);
\r
8098 /* [AS] Pick FRC position */
\r
8099 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8101 static int * lpIndexFRC;
\r
8107 case WM_INITDIALOG:
\r
8108 lpIndexFRC = (int *) lParam;
\r
8110 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8112 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8113 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8114 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8115 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8120 switch( LOWORD(wParam) ) {
\r
8122 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8123 EndDialog( hDlg, 0 );
\r
8126 EndDialog( hDlg, 1 );
\r
8128 case IDC_NFG_Edit:
\r
8129 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8130 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8132 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8135 case IDC_NFG_Random:
\r
8136 sprintf( buf, "%d", myrandom() % 960 );
\r
8137 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8150 int index = appData.defaultFrcPosition;
\r
8151 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8153 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8155 if( result == 0 ) {
\r
8156 appData.defaultFrcPosition = index;
\r
8162 /* [AS] Game list options */
\r
8168 static GLT_Item GLT_ItemInfo[] = {
\r
8169 { GLT_EVENT, "Event" },
\r
8170 { GLT_SITE, "Site" },
\r
8171 { GLT_DATE, "Date" },
\r
8172 { GLT_ROUND, "Round" },
\r
8173 { GLT_PLAYERS, "Players" },
\r
8174 { GLT_RESULT, "Result" },
\r
8175 { GLT_WHITE_ELO, "White Rating" },
\r
8176 { GLT_BLACK_ELO, "Black Rating" },
\r
8177 { GLT_TIME_CONTROL,"Time Control" },
\r
8178 { GLT_VARIANT, "Variant" },
\r
8179 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
8183 const char * GLT_FindItem( char id )
\r
8185 const char * result = 0;
\r
8187 GLT_Item * list = GLT_ItemInfo;
\r
8189 while( list->id != 0 ) {
\r
8190 if( list->id == id ) {
\r
8191 result = list->name;
\r
8201 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
8203 const char * name = GLT_FindItem( id );
\r
8206 if( index >= 0 ) {
\r
8207 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
8210 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
8215 void GLT_TagsToList( HWND hDlg, char * tags )
\r
8219 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8222 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8226 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
8228 pc = GLT_ALL_TAGS;
\r
8231 if( strchr( tags, *pc ) == 0 ) {
\r
8232 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8237 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8240 char GLT_ListItemToTag( HWND hDlg, int index )
\r
8242 char result = '\0';
\r
8245 GLT_Item * list = GLT_ItemInfo;
\r
8247 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
8248 while( list->id != 0 ) {
\r
8249 if( strcmp( list->name, name ) == 0 ) {
\r
8250 result = list->id;
\r
8261 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8263 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8264 int idx2 = idx1 + delta;
\r
8265 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8267 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8270 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8271 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8272 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8273 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8277 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8279 static char glt[64];
\r
8280 static char * lpUserGLT;
\r
8284 case WM_INITDIALOG:
\r
8285 lpUserGLT = (char *) lParam;
\r
8287 strcpy( glt, lpUserGLT );
\r
8289 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8291 /* Initialize list */
\r
8292 GLT_TagsToList( hDlg, glt );
\r
8294 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8299 switch( LOWORD(wParam) ) {
\r
8302 char * pc = lpUserGLT;
\r
8304 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8308 id = GLT_ListItemToTag( hDlg, idx );
\r
8312 } while( id != '\0' );
\r
8314 EndDialog( hDlg, 0 );
\r
8317 EndDialog( hDlg, 1 );
\r
8320 case IDC_GLT_Default:
\r
8321 strcpy( glt, GLT_DEFAULT_TAGS );
\r
8322 GLT_TagsToList( hDlg, glt );
\r
8325 case IDC_GLT_Restore:
\r
8326 strcpy( glt, lpUserGLT );
\r
8327 GLT_TagsToList( hDlg, glt );
\r
8331 GLT_MoveSelection( hDlg, -1 );
\r
8334 case IDC_GLT_Down:
\r
8335 GLT_MoveSelection( hDlg, +1 );
\r
8345 int GameListOptions()
\r
8349 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8351 strcpy( glt, appData.gameListTags );
\r
8353 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
8355 if( result == 0 ) {
\r
8356 /* [AS] Memory leak here! */
\r
8357 appData.gameListTags = strdup( glt );
\r
8365 DisplayIcsInteractionTitle(char *str)
\r
8367 char consoleTitle[MSG_SIZ];
\r
8369 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8370 SetWindowText(hwndConsole, consoleTitle);
\r
8374 DrawPosition(int fullRedraw, Board board)
\r
8376 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8383 fromX = fromY = -1;
\r
8384 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8385 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8386 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8387 dragInfo.lastpos = dragInfo.pos;
\r
8388 dragInfo.start.x = dragInfo.start.y = -1;
\r
8389 dragInfo.from = dragInfo.start;
\r
8391 DrawPosition(TRUE, NULL);
\r
8397 CommentPopUp(char *title, char *str)
\r
8399 HWND hwnd = GetActiveWindow();
\r
8400 EitherCommentPopUp(0, title, str, FALSE);
\r
8401 SetActiveWindow(hwnd);
\r
8405 CommentPopDown(void)
\r
8407 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8408 if (commentDialog) {
\r
8409 ShowWindow(commentDialog, SW_HIDE);
\r
8411 commentDialogUp = FALSE;
\r
8415 EditCommentPopUp(int index, char *title, char *str)
\r
8417 EitherCommentPopUp(index, title, str, TRUE);
\r
8424 MyPlaySound(&sounds[(int)SoundMove]);
\r
8427 VOID PlayIcsWinSound()
\r
8429 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8432 VOID PlayIcsLossSound()
\r
8434 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8437 VOID PlayIcsDrawSound()
\r
8439 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8442 VOID PlayIcsUnfinishedSound()
\r
8444 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8450 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8458 consoleEcho = TRUE;
\r
8459 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8460 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8461 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8470 consoleEcho = FALSE;
\r
8471 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8472 /* This works OK: set text and background both to the same color */
\r
8474 cf.crTextColor = COLOR_ECHOOFF;
\r
8475 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8476 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8479 /* No Raw()...? */
\r
8481 void Colorize(ColorClass cc, int continuation)
\r
8483 currentColorClass = cc;
\r
8484 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8485 consoleCF.crTextColor = textAttribs[cc].color;
\r
8486 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8487 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8493 static char buf[MSG_SIZ];
\r
8494 DWORD bufsiz = MSG_SIZ;
\r
8496 if (!GetUserName(buf, &bufsiz)) {
\r
8497 /*DisplayError("Error getting user name", GetLastError());*/
\r
8498 strcpy(buf, "User");
\r
8506 static char buf[MSG_SIZ];
\r
8507 DWORD bufsiz = MSG_SIZ;
\r
8509 if (!GetComputerName(buf, &bufsiz)) {
\r
8510 /*DisplayError("Error getting host name", GetLastError());*/
\r
8511 strcpy(buf, "Unknown");
\r
8518 ClockTimerRunning()
\r
8520 return clockTimerEvent != 0;
\r
8526 if (clockTimerEvent == 0) return FALSE;
\r
8527 KillTimer(hwndMain, clockTimerEvent);
\r
8528 clockTimerEvent = 0;
\r
8533 StartClockTimer(long millisec)
\r
8535 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8536 (UINT) millisec, NULL);
\r
8540 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8543 hdc = GetDC(hwndMain);
\r
8544 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8546 if (!IsIconic(hwndMain)) {
\r
8547 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White", flag);
\r
8549 if (highlight && iconCurrent == iconBlack) {
\r
8550 iconCurrent = iconWhite;
\r
8551 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8552 if (IsIconic(hwndMain)) {
\r
8553 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8556 (void) ReleaseDC(hwndMain, hdc);
\r
8558 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8562 DisplayBlackClock(long timeRemaining, int highlight)
\r
8565 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8567 hdc = GetDC(hwndMain);
\r
8568 if (!IsIconic(hwndMain)) {
\r
8569 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black", flag);
\r
8571 if (highlight && iconCurrent == iconWhite) {
\r
8572 iconCurrent = iconBlack;
\r
8573 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8574 if (IsIconic(hwndMain)) {
\r
8575 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8578 (void) ReleaseDC(hwndMain, hdc);
\r
8580 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8585 LoadGameTimerRunning()
\r
8587 return loadGameTimerEvent != 0;
\r
8591 StopLoadGameTimer()
\r
8593 if (loadGameTimerEvent == 0) return FALSE;
\r
8594 KillTimer(hwndMain, loadGameTimerEvent);
\r
8595 loadGameTimerEvent = 0;
\r
8600 StartLoadGameTimer(long millisec)
\r
8602 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8603 (UINT) millisec, NULL);
\r
8611 char fileTitle[MSG_SIZ];
\r
8613 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8614 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
8615 appData.oldSaveStyle ? "gam" : "pgn",
\r
8617 "Save Game to File", NULL, fileTitle, NULL);
\r
8619 SaveGame(f, 0, "");
\r
8626 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8628 if (delayedTimerEvent != 0) {
\r
8629 if (appData.debugMode) {
\r
8630 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8632 KillTimer(hwndMain, delayedTimerEvent);
\r
8633 delayedTimerEvent = 0;
\r
8634 delayedTimerCallback();
\r
8636 delayedTimerCallback = cb;
\r
8637 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8638 (UINT) millisec, NULL);
\r
8641 DelayedEventCallback
\r
8644 if (delayedTimerEvent) {
\r
8645 return delayedTimerCallback;
\r
8652 CancelDelayedEvent()
\r
8654 if (delayedTimerEvent) {
\r
8655 KillTimer(hwndMain, delayedTimerEvent);
\r
8656 delayedTimerEvent = 0;
\r
8660 /* Start a child process running the given program.
\r
8661 The process's standard output can be read from "from", and its
\r
8662 standard input can be written to "to".
\r
8663 Exit with fatal error if anything goes wrong.
\r
8664 Returns an opaque pointer that can be used to destroy the process
\r
8668 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8670 #define BUFSIZE 4096
\r
8672 HANDLE hChildStdinRd, hChildStdinWr,
\r
8673 hChildStdoutRd, hChildStdoutWr;
\r
8674 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8675 SECURITY_ATTRIBUTES saAttr;
\r
8677 PROCESS_INFORMATION piProcInfo;
\r
8678 STARTUPINFO siStartInfo;
\r
8680 char buf[MSG_SIZ];
\r
8683 if (appData.debugMode) {
\r
8684 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8689 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8690 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8691 saAttr.bInheritHandle = TRUE;
\r
8692 saAttr.lpSecurityDescriptor = NULL;
\r
8695 * The steps for redirecting child's STDOUT:
\r
8696 * 1. Create anonymous pipe to be STDOUT for child.
\r
8697 * 2. Create a noninheritable duplicate of read handle,
\r
8698 * and close the inheritable read handle.
\r
8701 /* Create a pipe for the child's STDOUT. */
\r
8702 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8703 return GetLastError();
\r
8706 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8707 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8708 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8709 FALSE, /* not inherited */
\r
8710 DUPLICATE_SAME_ACCESS);
\r
8712 return GetLastError();
\r
8714 CloseHandle(hChildStdoutRd);
\r
8717 * The steps for redirecting child's STDIN:
\r
8718 * 1. Create anonymous pipe to be STDIN for child.
\r
8719 * 2. Create a noninheritable duplicate of write handle,
\r
8720 * and close the inheritable write handle.
\r
8723 /* Create a pipe for the child's STDIN. */
\r
8724 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8725 return GetLastError();
\r
8728 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8729 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8730 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8731 FALSE, /* not inherited */
\r
8732 DUPLICATE_SAME_ACCESS);
\r
8734 return GetLastError();
\r
8736 CloseHandle(hChildStdinWr);
\r
8738 /* Arrange to (1) look in dir for the child .exe file, and
\r
8739 * (2) have dir be the child's working directory. Interpret
\r
8740 * dir relative to the directory WinBoard loaded from. */
\r
8741 GetCurrentDirectory(MSG_SIZ, buf);
\r
8742 SetCurrentDirectory(installDir);
\r
8743 SetCurrentDirectory(dir);
\r
8745 /* Now create the child process. */
\r
8747 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8748 siStartInfo.lpReserved = NULL;
\r
8749 siStartInfo.lpDesktop = NULL;
\r
8750 siStartInfo.lpTitle = NULL;
\r
8751 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8752 siStartInfo.cbReserved2 = 0;
\r
8753 siStartInfo.lpReserved2 = NULL;
\r
8754 siStartInfo.hStdInput = hChildStdinRd;
\r
8755 siStartInfo.hStdOutput = hChildStdoutWr;
\r
8756 siStartInfo.hStdError = hChildStdoutWr;
\r
8758 fSuccess = CreateProcess(NULL,
\r
8759 cmdLine, /* command line */
\r
8760 NULL, /* process security attributes */
\r
8761 NULL, /* primary thread security attrs */
\r
8762 TRUE, /* handles are inherited */
\r
8763 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
8764 NULL, /* use parent's environment */
\r
8766 &siStartInfo, /* STARTUPINFO pointer */
\r
8767 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
8769 err = GetLastError();
\r
8770 SetCurrentDirectory(buf); /* return to prev directory */
\r
8775 /* Close the handles we don't need in the parent */
\r
8776 CloseHandle(piProcInfo.hThread);
\r
8777 CloseHandle(hChildStdinRd);
\r
8778 CloseHandle(hChildStdoutWr);
\r
8780 /* Prepare return value */
\r
8781 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8782 cp->kind = CPReal;
\r
8783 cp->hProcess = piProcInfo.hProcess;
\r
8784 cp->pid = piProcInfo.dwProcessId;
\r
8785 cp->hFrom = hChildStdoutRdDup;
\r
8786 cp->hTo = hChildStdinWrDup;
\r
8788 *pr = (void *) cp;
\r
8790 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
8791 2000 where engines sometimes don't see the initial command(s)
\r
8792 from WinBoard and hang. I don't understand how that can happen,
\r
8793 but the Sleep is harmless, so I've put it in. Others have also
\r
8794 reported what may be the same problem, so hopefully this will fix
\r
8795 it for them too. */
\r
8803 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
8807 cp = (ChildProc *) pr;
\r
8808 if (cp == NULL) return;
\r
8810 switch (cp->kind) {
\r
8812 /* TerminateProcess is considered harmful, so... */
\r
8813 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
8814 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
8815 /* The following doesn't work because the chess program
\r
8816 doesn't "have the same console" as WinBoard. Maybe
\r
8817 we could arrange for this even though neither WinBoard
\r
8818 nor the chess program uses a console for stdio? */
\r
8819 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
8821 /* [AS] Special termination modes for misbehaving programs... */
\r
8822 if( signal == 9 ) {
\r
8823 if ( appData.debugMode) {
\r
8824 fprintf( debugFP, "Terminating process %u\n", cp->pid );
\r
8827 TerminateProcess( cp->hProcess, 0 );
\r
8829 else if( signal == 10 ) {
\r
8830 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
8832 if( dw != WAIT_OBJECT_0 ) {
\r
8833 if ( appData.debugMode) {
\r
8834 fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
\r
8837 TerminateProcess( cp->hProcess, 0 );
\r
8841 CloseHandle(cp->hProcess);
\r
8845 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
8849 closesocket(cp->sock);
\r
8854 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
8855 closesocket(cp->sock);
\r
8856 closesocket(cp->sock2);
\r
8864 InterruptChildProcess(ProcRef pr)
\r
8868 cp = (ChildProc *) pr;
\r
8869 if (cp == NULL) return;
\r
8870 switch (cp->kind) {
\r
8872 /* The following doesn't work because the chess program
\r
8873 doesn't "have the same console" as WinBoard. Maybe
\r
8874 we could arrange for this even though neither WinBoard
\r
8875 nor the chess program uses a console for stdio */
\r
8876 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
8881 /* Can't interrupt */
\r
8885 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
8892 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
8894 char cmdLine[MSG_SIZ];
\r
8896 if (port[0] == NULLCHAR) {
\r
8897 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
8899 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
8901 return StartChildProcess(cmdLine, "", pr);
\r
8905 /* Code to open TCP sockets */
\r
8908 OpenTCP(char *host, char *port, ProcRef *pr)
\r
8913 struct sockaddr_in sa, mysa;
\r
8914 struct hostent FAR *hp;
\r
8915 unsigned short uport;
\r
8916 WORD wVersionRequested;
\r
8919 /* Initialize socket DLL */
\r
8920 wVersionRequested = MAKEWORD(1, 1);
\r
8921 err = WSAStartup(wVersionRequested, &wsaData);
\r
8922 if (err != 0) return err;
\r
8925 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8926 err = WSAGetLastError();
\r
8931 /* Bind local address using (mostly) don't-care values.
\r
8933 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8934 mysa.sin_family = AF_INET;
\r
8935 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8936 uport = (unsigned short) 0;
\r
8937 mysa.sin_port = htons(uport);
\r
8938 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8939 == SOCKET_ERROR) {
\r
8940 err = WSAGetLastError();
\r
8945 /* Resolve remote host name */
\r
8946 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8947 if (!(hp = gethostbyname(host))) {
\r
8948 unsigned int b0, b1, b2, b3;
\r
8950 err = WSAGetLastError();
\r
8952 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8953 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8954 hp->h_addrtype = AF_INET;
\r
8956 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8957 hp->h_addr_list[0] = (char *) malloc(4);
\r
8958 hp->h_addr_list[0][0] = (char) b0;
\r
8959 hp->h_addr_list[0][1] = (char) b1;
\r
8960 hp->h_addr_list[0][2] = (char) b2;
\r
8961 hp->h_addr_list[0][3] = (char) b3;
\r
8967 sa.sin_family = hp->h_addrtype;
\r
8968 uport = (unsigned short) atoi(port);
\r
8969 sa.sin_port = htons(uport);
\r
8970 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8972 /* Make connection */
\r
8973 if (connect(s, (struct sockaddr *) &sa,
\r
8974 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8975 err = WSAGetLastError();
\r
8980 /* Prepare return value */
\r
8981 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8982 cp->kind = CPSock;
\r
8984 *pr = (ProcRef *) cp;
\r
8990 OpenCommPort(char *name, ProcRef *pr)
\r
8995 char fullname[MSG_SIZ];
\r
8997 if (*name != '\\')
\r
8998 sprintf(fullname, "\\\\.\\%s", name);
\r
9000 strcpy(fullname, name);
\r
9002 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9003 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9004 if (h == (HANDLE) -1) {
\r
9005 return GetLastError();
\r
9009 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9011 /* Accumulate characters until a 100ms pause, then parse */
\r
9012 ct.ReadIntervalTimeout = 100;
\r
9013 ct.ReadTotalTimeoutMultiplier = 0;
\r
9014 ct.ReadTotalTimeoutConstant = 0;
\r
9015 ct.WriteTotalTimeoutMultiplier = 0;
\r
9016 ct.WriteTotalTimeoutConstant = 0;
\r
9017 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9019 /* Prepare return value */
\r
9020 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9021 cp->kind = CPComm;
\r
9024 *pr = (ProcRef *) cp;
\r
9030 OpenLoopback(ProcRef *pr)
\r
9032 DisplayFatalError("Not implemented", 0, 1);
\r
9038 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9043 struct sockaddr_in sa, mysa;
\r
9044 struct hostent FAR *hp;
\r
9045 unsigned short uport;
\r
9046 WORD wVersionRequested;
\r
9049 char stderrPortStr[MSG_SIZ];
\r
9051 /* Initialize socket DLL */
\r
9052 wVersionRequested = MAKEWORD(1, 1);
\r
9053 err = WSAStartup(wVersionRequested, &wsaData);
\r
9054 if (err != 0) return err;
\r
9056 /* Resolve remote host name */
\r
9057 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9058 if (!(hp = gethostbyname(host))) {
\r
9059 unsigned int b0, b1, b2, b3;
\r
9061 err = WSAGetLastError();
\r
9063 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9064 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9065 hp->h_addrtype = AF_INET;
\r
9067 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9068 hp->h_addr_list[0] = (char *) malloc(4);
\r
9069 hp->h_addr_list[0][0] = (char) b0;
\r
9070 hp->h_addr_list[0][1] = (char) b1;
\r
9071 hp->h_addr_list[0][2] = (char) b2;
\r
9072 hp->h_addr_list[0][3] = (char) b3;
\r
9078 sa.sin_family = hp->h_addrtype;
\r
9079 uport = (unsigned short) 514;
\r
9080 sa.sin_port = htons(uport);
\r
9081 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9083 /* Bind local socket to unused "privileged" port address
\r
9085 s = INVALID_SOCKET;
\r
9086 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9087 mysa.sin_family = AF_INET;
\r
9088 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9089 for (fromPort = 1023;; fromPort--) {
\r
9090 if (fromPort < 0) {
\r
9092 return WSAEADDRINUSE;
\r
9094 if (s == INVALID_SOCKET) {
\r
9095 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9096 err = WSAGetLastError();
\r
9101 uport = (unsigned short) fromPort;
\r
9102 mysa.sin_port = htons(uport);
\r
9103 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9104 == SOCKET_ERROR) {
\r
9105 err = WSAGetLastError();
\r
9106 if (err == WSAEADDRINUSE) continue;
\r
9110 if (connect(s, (struct sockaddr *) &sa,
\r
9111 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9112 err = WSAGetLastError();
\r
9113 if (err == WSAEADDRINUSE) {
\r
9124 /* Bind stderr local socket to unused "privileged" port address
\r
9126 s2 = INVALID_SOCKET;
\r
9127 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9128 mysa.sin_family = AF_INET;
\r
9129 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9130 for (fromPort = 1023;; fromPort--) {
\r
9131 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9132 if (fromPort < 0) {
\r
9133 (void) closesocket(s);
\r
9135 return WSAEADDRINUSE;
\r
9137 if (s2 == INVALID_SOCKET) {
\r
9138 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9139 err = WSAGetLastError();
\r
9145 uport = (unsigned short) fromPort;
\r
9146 mysa.sin_port = htons(uport);
\r
9147 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9148 == SOCKET_ERROR) {
\r
9149 err = WSAGetLastError();
\r
9150 if (err == WSAEADDRINUSE) continue;
\r
9151 (void) closesocket(s);
\r
9155 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9156 err = WSAGetLastError();
\r
9157 if (err == WSAEADDRINUSE) {
\r
9159 s2 = INVALID_SOCKET;
\r
9162 (void) closesocket(s);
\r
9163 (void) closesocket(s2);
\r
9169 prevStderrPort = fromPort; // remember port used
\r
9170 sprintf(stderrPortStr, "%d", fromPort);
\r
9172 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9173 err = WSAGetLastError();
\r
9174 (void) closesocket(s);
\r
9175 (void) closesocket(s2);
\r
9180 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9181 err = WSAGetLastError();
\r
9182 (void) closesocket(s);
\r
9183 (void) closesocket(s2);
\r
9187 if (*user == NULLCHAR) user = UserName();
\r
9188 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9189 err = WSAGetLastError();
\r
9190 (void) closesocket(s);
\r
9191 (void) closesocket(s2);
\r
9195 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9196 err = WSAGetLastError();
\r
9197 (void) closesocket(s);
\r
9198 (void) closesocket(s2);
\r
9203 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9204 err = WSAGetLastError();
\r
9205 (void) closesocket(s);
\r
9206 (void) closesocket(s2);
\r
9210 (void) closesocket(s2); /* Stop listening */
\r
9212 /* Prepare return value */
\r
9213 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9214 cp->kind = CPRcmd;
\r
9217 *pr = (ProcRef *) cp;
\r
9224 AddInputSource(ProcRef pr, int lineByLine,
\r
9225 InputCallback func, VOIDSTAR closure)
\r
9227 InputSource *is, *is2 = NULL;
\r
9228 ChildProc *cp = (ChildProc *) pr;
\r
9230 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9231 is->lineByLine = lineByLine;
\r
9233 is->closure = closure;
\r
9234 is->second = NULL;
\r
9235 is->next = is->buf;
\r
9236 if (pr == NoProc) {
\r
9237 is->kind = CPReal;
\r
9238 consoleInputSource = is;
\r
9240 is->kind = cp->kind;
\r
9242 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9243 we create all threads suspended so that the is->hThread variable can be
\r
9244 safely assigned, then let the threads start with ResumeThread.
\r
9246 switch (cp->kind) {
\r
9248 is->hFile = cp->hFrom;
\r
9249 cp->hFrom = NULL; /* now owned by InputThread */
\r
9251 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9252 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9256 is->hFile = cp->hFrom;
\r
9257 cp->hFrom = NULL; /* now owned by InputThread */
\r
9259 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9260 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9264 is->sock = cp->sock;
\r
9266 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9267 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9271 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9273 is->sock = cp->sock;
\r
9275 is2->sock = cp->sock2;
\r
9276 is2->second = is2;
\r
9278 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9279 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9281 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9282 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9286 if( is->hThread != NULL ) {
\r
9287 ResumeThread( is->hThread );
\r
9290 if( is2 != NULL && is2->hThread != NULL ) {
\r
9291 ResumeThread( is2->hThread );
\r
9295 return (InputSourceRef) is;
\r
9299 RemoveInputSource(InputSourceRef isr)
\r
9303 is = (InputSource *) isr;
\r
9304 is->hThread = NULL; /* tell thread to stop */
\r
9305 CloseHandle(is->hThread);
\r
9306 if (is->second != NULL) {
\r
9307 is->second->hThread = NULL;
\r
9308 CloseHandle(is->second->hThread);
\r
9314 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9317 int outCount = SOCKET_ERROR;
\r
9318 ChildProc *cp = (ChildProc *) pr;
\r
9319 static OVERLAPPED ovl;
\r
9321 if (pr == NoProc) {
\r
9322 ConsoleOutput(message, count, FALSE);
\r
9326 if (ovl.hEvent == NULL) {
\r
9327 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9329 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9331 switch (cp->kind) {
\r
9334 outCount = send(cp->sock, message, count, 0);
\r
9335 if (outCount == SOCKET_ERROR) {
\r
9336 *outError = WSAGetLastError();
\r
9338 *outError = NO_ERROR;
\r
9343 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9344 &dOutCount, NULL)) {
\r
9345 *outError = NO_ERROR;
\r
9346 outCount = (int) dOutCount;
\r
9348 *outError = GetLastError();
\r
9353 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9354 &dOutCount, &ovl);
\r
9355 if (*outError == NO_ERROR) {
\r
9356 outCount = (int) dOutCount;
\r
9364 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9367 /* Ignore delay, not implemented for WinBoard */
\r
9368 return OutputToProcess(pr, message, count, outError);
\r
9373 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9374 char *buf, int count, int error)
\r
9376 DisplayFatalError("Not implemented", 0, 1);
\r
9379 /* see wgamelist.c for Game List functions */
\r
9380 /* see wedittags.c for Edit Tags functions */
\r
9387 char buf[MSG_SIZ];
\r
9390 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9391 f = fopen(buf, "r");
\r
9393 ProcessICSInitScript(f);
\r
9401 StartAnalysisClock()
\r
9403 if (analysisTimerEvent) return;
\r
9404 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9405 (UINT) 2000, NULL);
\r
9409 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9411 static HANDLE hwndText;
\r
9413 static int sizeX, sizeY;
\r
9414 int newSizeX, newSizeY, flags;
\r
9417 switch (message) {
\r
9418 case WM_INITDIALOG: /* message: initialize dialog box */
\r
9419 /* Initialize the dialog items */
\r
9420 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
9421 SetWindowText(hDlg, analysisTitle);
\r
9422 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
9423 /* Size and position the dialog */
\r
9424 if (!analysisDialog) {
\r
9425 analysisDialog = hDlg;
\r
9426 flags = SWP_NOZORDER;
\r
9427 GetClientRect(hDlg, &rect);
\r
9428 sizeX = rect.right;
\r
9429 sizeY = rect.bottom;
\r
9430 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
9431 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
9432 WINDOWPLACEMENT wp;
\r
9433 EnsureOnScreen(&analysisX, &analysisY);
\r
9434 wp.length = sizeof(WINDOWPLACEMENT);
\r
9436 wp.showCmd = SW_SHOW;
\r
9437 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
9438 wp.rcNormalPosition.left = analysisX;
\r
9439 wp.rcNormalPosition.right = analysisX + analysisW;
\r
9440 wp.rcNormalPosition.top = analysisY;
\r
9441 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
9442 SetWindowPlacement(hDlg, &wp);
\r
9444 GetClientRect(hDlg, &rect);
\r
9445 newSizeX = rect.right;
\r
9446 newSizeY = rect.bottom;
\r
9447 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
9448 newSizeX, newSizeY);
\r
9455 case WM_COMMAND: /* message: received a command */
\r
9456 switch (LOWORD(wParam)) {
\r
9466 newSizeX = LOWORD(lParam);
\r
9467 newSizeY = HIWORD(lParam);
\r
9468 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
9473 case WM_GETMINMAXINFO:
\r
9474 /* Prevent resizing window too small */
\r
9475 mmi = (MINMAXINFO *) lParam;
\r
9476 mmi->ptMinTrackSize.x = 100;
\r
9477 mmi->ptMinTrackSize.y = 100;
\r
9484 AnalysisPopUp(char* title, char* str)
\r
9490 EngineOutputPopUp();
\r
9493 if (str == NULL) str = "";
\r
9494 p = (char *) malloc(2 * strlen(str) + 2);
\r
9497 if (*str == '\n') *q++ = '\r';
\r
9501 if (analysisText != NULL) free(analysisText);
\r
9504 if (analysisDialog) {
\r
9505 SetWindowText(analysisDialog, title);
\r
9506 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
9507 ShowWindow(analysisDialog, SW_SHOW);
\r
9509 analysisTitle = title;
\r
9510 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
9511 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
9512 hwndMain, (DLGPROC)lpProc);
\r
9513 FreeProcInstance(lpProc);
\r
9515 analysisDialogUp = TRUE;
\r
9521 if (analysisDialog) {
\r
9522 ShowWindow(analysisDialog, SW_HIDE);
\r
9524 analysisDialogUp = FALSE;
\r
9529 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9531 highlightInfo.sq[0].x = fromX;
\r
9532 highlightInfo.sq[0].y = fromY;
\r
9533 highlightInfo.sq[1].x = toX;
\r
9534 highlightInfo.sq[1].y = toY;
\r
9540 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9541 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9545 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9547 premoveHighlightInfo.sq[0].x = fromX;
\r
9548 premoveHighlightInfo.sq[0].y = fromY;
\r
9549 premoveHighlightInfo.sq[1].x = toX;
\r
9550 premoveHighlightInfo.sq[1].y = toY;
\r
9554 ClearPremoveHighlights()
\r
9556 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9557 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9561 ShutDownFrontEnd()
\r
9563 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9564 DeleteClipboardTempFiles();
\r
9570 if (IsIconic(hwndMain))
\r
9571 ShowWindow(hwndMain, SW_RESTORE);
\r
9573 SetActiveWindow(hwndMain);
\r
9577 * Prototypes for animation support routines
\r
9579 static void ScreenSquare(int column, int row, POINT * pt);
\r
9580 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9581 POINT frames[], int * nFrames);
\r
9587 AnimateMove(board, fromX, fromY, toX, toY)
\r
9594 ChessSquare piece;
\r
9595 POINT start, finish, mid;
\r
9596 POINT frames[kFactor * 2 + 1];
\r
9599 if (!appData.animate) return;
\r
9600 if (doingSizing) return;
\r
9601 if (fromY < 0 || fromX < 0) return;
\r
9602 piece = board[fromY][fromX];
\r
9603 if (piece >= EmptySquare) return;
\r
9605 ScreenSquare(fromX, fromY, &start);
\r
9606 ScreenSquare(toX, toY, &finish);
\r
9608 /* All pieces except knights move in straight line */
\r
9609 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9610 mid.x = start.x + (finish.x - start.x) / 2;
\r
9611 mid.y = start.y + (finish.y - start.y) / 2;
\r
9613 /* Knight: make diagonal movement then straight */
\r
9614 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9615 mid.x = start.x + (finish.x - start.x) / 2;
\r
9619 mid.y = start.y + (finish.y - start.y) / 2;
\r
9623 /* Don't use as many frames for very short moves */
\r
9624 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9625 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9627 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9629 animInfo.from.x = fromX;
\r
9630 animInfo.from.y = fromY;
\r
9631 animInfo.to.x = toX;
\r
9632 animInfo.to.y = toY;
\r
9633 animInfo.lastpos = start;
\r
9634 animInfo.piece = piece;
\r
9635 for (n = 0; n < nFrames; n++) {
\r
9636 animInfo.pos = frames[n];
\r
9637 DrawPosition(FALSE, NULL);
\r
9638 animInfo.lastpos = animInfo.pos;
\r
9639 Sleep(appData.animSpeed);
\r
9641 animInfo.pos = finish;
\r
9642 DrawPosition(FALSE, NULL);
\r
9643 animInfo.piece = EmptySquare;
\r
9646 /* Convert board position to corner of screen rect and color */
\r
9649 ScreenSquare(column, row, pt)
\r
9650 int column; int row; POINT * pt;
\r
9653 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
9654 pt->y = lineGap + row * (squareSize + lineGap);
\r
9656 pt->x = lineGap + column * (squareSize + lineGap);
\r
9657 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
9661 /* Generate a series of frame coords from start->mid->finish.
\r
9662 The movement rate doubles until the half way point is
\r
9663 reached, then halves back down to the final destination,
\r
9664 which gives a nice slow in/out effect. The algorithmn
\r
9665 may seem to generate too many intermediates for short
\r
9666 moves, but remember that the purpose is to attract the
\r
9667 viewers attention to the piece about to be moved and
\r
9668 then to where it ends up. Too few frames would be less
\r
9672 Tween(start, mid, finish, factor, frames, nFrames)
\r
9673 POINT * start; POINT * mid;
\r
9674 POINT * finish; int factor;
\r
9675 POINT frames[]; int * nFrames;
\r
9677 int n, fraction = 1, count = 0;
\r
9679 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9680 for (n = 0; n < factor; n++)
\r
9682 for (n = 0; n < factor; n++) {
\r
9683 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9684 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9686 fraction = fraction / 2;
\r
9690 frames[count] = *mid;
\r
9693 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9695 for (n = 0; n < factor; n++) {
\r
9696 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9697 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9699 fraction = fraction * 2;
\r
9705 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
9710 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
9711 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
9713 OutputDebugString( buf );
\r
9716 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
9718 EvalGraphSet( first, last, current, pvInfoList );
\r
9721 void SetProgramStats( FrontEndProgramStats * stats )
\r
9726 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
9727 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
9729 OutputDebugString( buf );
\r
9732 EngineOutputUpdate( stats );
\r