allow the result comment as a display item in the game list
[xboard.git] / winboard / winboard.c
1 /*\r
2  * WinBoard.c -- Windows NT front end to XBoard\r
3  *\r
4  * Copyright 1991 by Digital Equipment Corporation, Maynard,\r
5  * Massachusetts. \r
6  *\r
7  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
8  * 2007, 2008, 2009 Free Software Foundation, Inc.\r
9  *\r
10  * Enhancements Copyright 2005 Alessandro Scotti\r
11  *\r
12  * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,\r
13  * which was written and is copyrighted by Wayne Christopher.\r
14  *\r
15  * The following terms apply to Digital Equipment Corporation's copyright\r
16  * interest in XBoard:\r
17  * ------------------------------------------------------------------------\r
18  * All Rights Reserved\r
19  *\r
20  * Permission to use, copy, modify, and distribute this software and its\r
21  * documentation for any purpose and without fee is hereby granted,\r
22  * provided that the above copyright notice appear in all copies and that\r
23  * both that copyright notice and this permission notice appear in\r
24  * supporting documentation, and that the name of Digital not be\r
25  * used in advertising or publicity pertaining to distribution of the\r
26  * software without specific, written prior permission.\r
27  *\r
28  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
29  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL\r
30  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
31  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\r
32  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\r
33  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\r
34  * SOFTWARE.\r
35  * ------------------------------------------------------------------------\r
36  *\r
37  * The following terms apply to the enhanced version of XBoard\r
38  * distributed by the Free Software Foundation:\r
39  * ------------------------------------------------------------------------\r
40  *\r
41  * GNU XBoard is free software: you can redistribute it and/or modify\r
42  * it under the terms of the GNU General Public License as published by\r
43  * the Free Software Foundation, either version 3 of the License, or (at\r
44  * your option) any later version.\r
45  *\r
46  * GNU XBoard is distributed in the hope that it will be useful, but\r
47  * WITHOUT ANY WARRANTY; without even the implied warranty of\r
48  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
49  * General Public License for more details.\r
50  *\r
51  * You should have received a copy of the GNU General Public License\r
52  * along with this program. If not, see http://www.gnu.org/licenses/.  *\r
53  *\r
54  *------------------------------------------------------------------------\r
55  ** See the file ChangeLog for a revision history.  */\r
56 \r
57 #include "config.h"\r
58 \r
59 #include <windows.h>\r
60 #include <winuser.h>\r
61 #include <winsock.h>\r
62 #include <commctrl.h>\r
63 \r
64 #include <stdio.h>\r
65 #include <stdlib.h>\r
66 #include <time.h>\r
67 #include <malloc.h>\r
68 #include <sys/stat.h>\r
69 #include <fcntl.h>\r
70 #include <math.h>\r
71 #include <commdlg.h>\r
72 #include <dlgs.h>\r
73 #include <richedit.h>\r
74 #include <mmsystem.h>\r
75 #include <ctype.h>\r
76 \r
77 #if __GNUC__\r
78 #include <errno.h>\r
79 #include <string.h>\r
80 #endif\r
81 \r
82 #include "common.h"\r
83 #include "winboard.h"\r
84 #include "frontend.h"\r
85 #include "backend.h"\r
86 #include "moves.h"\r
87 #include "wclipbrd.h"\r
88 #include "wgamelist.h"\r
89 #include "wedittags.h"\r
90 #include "woptions.h"\r
91 #include "wsockerr.h"\r
92 #include "defaults.h"\r
93 #include "help.h"\r
94 #include "wsnap.h"\r
95 \r
96 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );\r
97 \r
98   int myrandom(void);\r
99   void mysrandom(unsigned int seed);\r
100 \r
101 extern int whiteFlag, blackFlag;\r
102 Boolean flipClock = FALSE;\r
103 extern HANDLE chatHandle[];\r
104 extern int ics_type;\r
105 \r
106 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);\r
107 VOID NewVariantPopup(HWND hwnd);\r
108 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
109                    /*char*/int promoChar));\r
110 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);\r
111 void DisplayMove P((int moveNumber));\r
112 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
113 void ChatPopUp P(());\r
114 typedef struct {\r
115   ChessSquare piece;  \r
116   POINT pos;      /* window coordinates of current pos */\r
117   POINT lastpos;  /* window coordinates of last pos - used for clipping */\r
118   POINT from;     /* board coordinates of the piece's orig pos */\r
119   POINT to;       /* board coordinates of the piece's new pos */\r
120 } AnimInfo;\r
121 \r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };\r
123 \r
124 typedef struct {\r
125   POINT start;    /* window coordinates of start pos */\r
126   POINT pos;      /* window coordinates of current pos */\r
127   POINT lastpos;  /* window coordinates of last pos - used for clipping */\r
128   POINT from;     /* board coordinates of the piece's orig pos */\r
129 } DragInfo;\r
130 \r
131 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };\r
132 \r
133 typedef struct {\r
134   POINT sq[2];    /* board coordinates of from, to squares */\r
135 } HighlightInfo;\r
136 \r
137 static HighlightInfo highlightInfo        = { {{-1, -1}, {-1, -1}} };\r
138 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };\r
139 \r
140 typedef struct { // [HGM] atomic\r
141   int fromX, fromY, toX, toY, radius;\r
142 } ExplodeInfo;\r
143 \r
144 static ExplodeInfo explodeInfo;\r
145 \r
146 /* Window class names */\r
147 char szAppName[] = "WinBoard";\r
148 char szConsoleName[] = "WBConsole";\r
149 \r
150 /* Title bar text */\r
151 char szTitle[] = "WinBoard";\r
152 char szConsoleTitle[] = "I C S Interaction";\r
153 \r
154 char *programName;\r
155 char *settingsFileName;\r
156 BOOLEAN saveSettingsOnExit;\r
157 char installDir[MSG_SIZ];\r
158 \r
159 BoardSize boardSize;\r
160 BOOLEAN chessProgram;\r
161 static int boardX, boardY;\r
162 int  minX, minY; // [HGM] placement: volatile limits on upper-left corner\r
163 static int squareSize, lineGap, minorSize;\r
164 static int winWidth, winHeight, winW, winH;\r
165 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo\r
166 static int logoHeight = 0;\r
167 static char messageText[MESSAGE_TEXT_MAX];\r
168 static int clockTimerEvent = 0;\r
169 static int loadGameTimerEvent = 0;\r
170 static int analysisTimerEvent = 0;\r
171 static DelayedEventCallback delayedTimerCallback;\r
172 static int delayedTimerEvent = 0;\r
173 static int buttonCount = 2;\r
174 char *icsTextMenuString;\r
175 char *icsNames;\r
176 char *firstChessProgramNames;\r
177 char *secondChessProgramNames;\r
178 \r
179 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */\r
180 \r
181 #define PALETTESIZE 256\r
182 \r
183 HINSTANCE hInst;          /* current instance */\r
184 HWND hwndMain = NULL;        /* root window*/\r
185 HWND hwndConsole = NULL;\r
186 BOOLEAN alwaysOnTop = FALSE;\r
187 RECT boardRect;\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor, \r
189   blackPieceColor, highlightSquareColor, premoveHighlightColor;\r
190 HPALETTE hPal;\r
191 ColorClass currentColorClass;\r
192 \r
193 HWND hCommPort = NULL;    /* currently open comm port */\r
194 static HWND hwndPause;    /* pause button */\r
195 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */\r
196 static HBRUSH lightSquareBrush, darkSquareBrush,\r
197   blackSquareBrush, /* [HGM] for band between board and holdings */\r
198   explodeBrush,     /* [HGM] atomic */\r
199   whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;\r
200 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];\r
201 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];\r
202 static HPEN gridPen = NULL;\r
203 static HPEN highlightPen = NULL;\r
204 static HPEN premovePen = NULL;\r
205 static NPLOGPALETTE pLogPal;\r
206 static BOOL paletteChanged = FALSE;\r
207 static HICON iconWhite, iconBlack, iconCurrent;\r
208 static int doingSizing = FALSE;\r
209 static int lastSizing = 0;\r
210 static int prevStderrPort;\r
211 static HBITMAP userLogo;\r
212 \r
213 /* [AS] Support for background textures */\r
214 #define BACK_TEXTURE_MODE_DISABLED      0\r
215 #define BACK_TEXTURE_MODE_PLAIN         1\r
216 #define BACK_TEXTURE_MODE_FULL_RANDOM   2\r
217 \r
218 static HBITMAP liteBackTexture = NULL;\r
219 static HBITMAP darkBackTexture = NULL;\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
222 static int backTextureSquareSize = 0;\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];\r
224 \r
225 #if __GNUC__ && !defined(_winmajor)\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */\r
227 #else\r
228 #define oldDialog (_winmajor < 4)\r
229 #endif\r
230 \r
231 char *defaultTextAttribs[] = \r
232 {\r
233   COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,\r
234   COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,\r
235   COLOR_NONE\r
236 };\r
237 \r
238 typedef struct {\r
239   char *name;\r
240   int squareSize;\r
241   int lineGap;\r
242   int smallLayout;\r
243   int tinyLayout;\r
244   int cliWidth, cliHeight;\r
245 } SizeInfo;\r
246 \r
247 SizeInfo sizeInfo[] = \r
248 {\r
249   { "tiny",     21, 0, 1, 1, 0, 0 },\r
250   { "teeny",    25, 1, 1, 1, 0, 0 },\r
251   { "dinky",    29, 1, 1, 1, 0, 0 },\r
252   { "petite",   33, 1, 1, 1, 0, 0 },\r
253   { "slim",     37, 2, 1, 0, 0, 0 },\r
254   { "small",    40, 2, 1, 0, 0, 0 },\r
255   { "mediocre", 45, 2, 1, 0, 0, 0 },\r
256   { "middling", 49, 2, 0, 0, 0, 0 },\r
257   { "average",  54, 2, 0, 0, 0, 0 },\r
258   { "moderate", 58, 3, 0, 0, 0, 0 },\r
259   { "medium",   64, 3, 0, 0, 0, 0 },\r
260   { "bulky",    72, 3, 0, 0, 0, 0 },\r
261   { "large",    80, 3, 0, 0, 0, 0 },\r
262   { "big",      87, 3, 0, 0, 0, 0 },\r
263   { "huge",     95, 3, 0, 0, 0, 0 },\r
264   { "giant",    108, 3, 0, 0, 0, 0 },\r
265   { "colossal", 116, 4, 0, 0, 0, 0 },\r
266   { "titanic",  129, 4, 0, 0, 0, 0 },\r
267   { NULL, 0, 0, 0, 0, 0, 0 }\r
268 };\r
269 \r
270 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}\r
271 MyFont fontRec[NUM_SIZES][NUM_FONTS] =\r
272 {\r
273   { 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
274   { 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
275   { 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
276   { 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
277   { 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
278   { 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
279   { 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
280   { 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
281   { 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
282   { 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
283   { 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
284   { 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
285   { 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
286   { 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
287   { 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
288   { 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
289   { 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
290   { 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
291 };\r
292 \r
293 MyFont *font[NUM_SIZES][NUM_FONTS];\r
294 \r
295 typedef struct {\r
296   char *label;\r
297   int id;\r
298   HWND hwnd;\r
299   WNDPROC wndproc;\r
300 } MyButtonDesc;\r
301 \r
302 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)\r
303 #define N_BUTTONS 5\r
304 \r
305 MyButtonDesc buttonDesc[N_BUTTONS] =\r
306 {\r
307   {"<<", IDM_ToStart, NULL, NULL},\r
308   {"<", IDM_Backward, NULL, NULL},\r
309   {"P", IDM_Pause, NULL, NULL},\r
310   {">", IDM_Forward, NULL, NULL},\r
311   {">>", IDM_ToEnd, NULL, NULL},\r
312 };\r
313 \r
314 int tinyLayout = 0, smallLayout = 0;\r
315 #define MENU_BAR_ITEMS 7\r
316 char *menuBarText[2][MENU_BAR_ITEMS+1] = {\r
317   { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },\r
318   { "&F", "&M", "&A", "&S", "&O", "&H", NULL },\r
319 };\r
320 \r
321 \r
322 MySound sounds[(int)NSoundClasses];\r
323 MyTextAttribs textAttribs[(int)NColorClasses];\r
324 \r
325 MyColorizeAttribs colorizeAttribs[] = {\r
326   { (COLORREF)0, 0, "Shout Text" },\r
327   { (COLORREF)0, 0, "SShout/CShout" },\r
328   { (COLORREF)0, 0, "Channel 1 Text" },\r
329   { (COLORREF)0, 0, "Channel Text" },\r
330   { (COLORREF)0, 0, "Kibitz Text" },\r
331   { (COLORREF)0, 0, "Tell Text" },\r
332   { (COLORREF)0, 0, "Challenge Text" },\r
333   { (COLORREF)0, 0, "Request Text" },\r
334   { (COLORREF)0, 0, "Seek Text" },\r
335   { (COLORREF)0, 0, "Normal Text" },\r
336   { (COLORREF)0, 0, "None" }\r
337 };\r
338 \r
339 \r
340 \r
341 static char *commentTitle;\r
342 static char *commentText;\r
343 static int commentIndex;\r
344 static Boolean editComment = FALSE;\r
345 HWND commentDialog = NULL;\r
346 BOOLEAN commentDialogUp = FALSE;\r
347 static int commentX, commentY, commentH, commentW;\r
348 \r
349 static char *analysisTitle;\r
350 static char *analysisText;\r
351 HWND analysisDialog = NULL;\r
352 BOOLEAN analysisDialogUp = FALSE;\r
353 static int analysisX, analysisY, analysisH, analysisW;\r
354 \r
355 char errorTitle[MSG_SIZ];\r
356 char errorMessage[2*MSG_SIZ];\r
357 HWND errorDialog = NULL;\r
358 BOOLEAN moveErrorMessageUp = FALSE;\r
359 BOOLEAN consoleEcho = TRUE;\r
360 CHARFORMAT consoleCF;\r
361 COLORREF consoleBackgroundColor;\r
362 \r
363 char *programVersion;\r
364 \r
365 #define CPReal 1\r
366 #define CPComm 2\r
367 #define CPSock 3\r
368 #define CPRcmd 4\r
369 typedef int CPKind;\r
370 \r
371 typedef struct {\r
372   CPKind kind;\r
373   HANDLE hProcess;\r
374   DWORD pid;\r
375   HANDLE hTo;\r
376   HANDLE hFrom;\r
377   SOCKET sock;\r
378   SOCKET sock2;  /* stderr socket for OpenRcmd */\r
379 } ChildProc;\r
380 \r
381 #define INPUT_SOURCE_BUF_SIZE 4096\r
382 \r
383 typedef struct _InputSource {\r
384   CPKind kind;\r
385   HANDLE hFile;\r
386   SOCKET sock;\r
387   int lineByLine;\r
388   HANDLE hThread;\r
389   DWORD id;\r
390   char buf[INPUT_SOURCE_BUF_SIZE];\r
391   char *next;\r
392   DWORD count;\r
393   int error;\r
394   InputCallback func;\r
395   struct _InputSource *second;  /* for stderr thread on CPRcmd */\r
396   VOIDSTAR closure;\r
397 } InputSource;\r
398 \r
399 InputSource *consoleInputSource;\r
400 \r
401 DCB dcb;\r
402 \r
403 /* forward */\r
404 VOID ConsoleOutput(char* data, int length, int forceVisible);\r
405 VOID ConsoleCreate();\r
406 LRESULT CALLBACK\r
407   ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
408 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);\r
409 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);\r
410 VOID ParseCommSettings(char *arg, DCB *dcb);\r
411 LRESULT CALLBACK\r
412   StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
413 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);\r
414 void ParseIcsTextMenu(char *icsTextMenuString);\r
415 VOID PopUpMoveDialog(char firstchar);\r
416 VOID PopUpNameDialog(char firstchar);\r
417 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);\r
418 \r
419 /* [AS] */\r
420 int NewGameFRC();\r
421 int GameListOptions();\r
422 \r
423 HWND moveHistoryDialog = NULL;\r
424 BOOLEAN moveHistoryDialogUp = FALSE;\r
425 \r
426 WindowPlacement wpMoveHistory;\r
427 \r
428 HWND evalGraphDialog = NULL;\r
429 BOOLEAN evalGraphDialogUp = FALSE;\r
430 \r
431 WindowPlacement wpEvalGraph;\r
432 \r
433 HWND engineOutputDialog = NULL;\r
434 BOOLEAN engineOutputDialogUp = FALSE;\r
435 \r
436 WindowPlacement wpEngineOutput;\r
437 WindowPlacement wpGameList;\r
438 WindowPlacement wpConsole;\r
439 \r
440 VOID MoveHistoryPopUp();\r
441 VOID MoveHistoryPopDown();\r
442 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
443 BOOL MoveHistoryIsUp();\r
444 \r
445 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
446 VOID EvalGraphPopUp();\r
447 VOID EvalGraphPopDown();\r
448 BOOL EvalGraphIsUp();\r
449 \r
450 VOID EngineOutputPopUp();\r
451 VOID EngineOutputPopDown();\r
452 BOOL EngineOutputIsUp();\r
453 VOID EngineOutputUpdate( FrontEndProgramStats * stats );\r
454 \r
455 VOID EngineOptionsPopup(); // [HGM] settings\r
456 \r
457 VOID GothicPopUp(char *title, VariantClass variant);\r
458 /*\r
459  * Setting "frozen" should disable all user input other than deleting\r
460  * the window.  We do this while engines are initializing themselves.\r
461  */\r
462 static int frozen = 0;\r
463 static int oldMenuItemState[MENU_BAR_ITEMS];\r
464 void FreezeUI()\r
465 {\r
466   HMENU hmenu;\r
467   int i;\r
468 \r
469   if (frozen) return;\r
470   frozen = 1;\r
471   hmenu = GetMenu(hwndMain);\r
472   for (i=0; i<MENU_BAR_ITEMS; i++) {\r
473     oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);\r
474   }\r
475   DrawMenuBar(hwndMain);\r
476 }\r
477 \r
478 /* Undo a FreezeUI */\r
479 void ThawUI()\r
480 {\r
481   HMENU hmenu;\r
482   int i;\r
483 \r
484   if (!frozen) return;\r
485   frozen = 0;\r
486   hmenu = GetMenu(hwndMain);\r
487   for (i=0; i<MENU_BAR_ITEMS; i++) {\r
488     EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);\r
489   }\r
490   DrawMenuBar(hwndMain);\r
491 }\r
492 \r
493 static int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them\r
494 \r
495 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */\r
496 #ifdef JAWS\r
497 #include "jaws.c"\r
498 #else\r
499 #define JAWS_INIT\r
500 #define JAWS_ARGS\r
501 #define JAWS_ALT_INTERCEPT\r
502 #define JAWS_KB_NAVIGATION\r
503 #define JAWS_MENU_ITEMS\r
504 #define JAWS_SILENCE\r
505 #define JAWS_REPLAY\r
506 #define JAWS_ACCEL\r
507 #define JAWS_COPYRIGHT\r
508 #define JAWS_DELETE(X) X\r
509 #define SAYMACHINEMOVE()\r
510 #define SAY(X)\r
511 #endif\r
512 \r
513 /*---------------------------------------------------------------------------*\\r
514  *\r
515  * WinMain\r
516  *\r
517 \*---------------------------------------------------------------------------*/\r
518 \r
519 int APIENTRY\r
520 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,\r
521         LPSTR lpCmdLine, int nCmdShow)\r
522 {\r
523   MSG msg;\r
524   HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;\r
525 //  INITCOMMONCONTROLSEX ex;\r
526 \r
527   debugFP = stderr;\r
528 \r
529   LoadLibrary("RICHED32.DLL");\r
530   consoleCF.cbSize = sizeof(CHARFORMAT);\r
531 \r
532   if (!InitApplication(hInstance)) {\r
533     return (FALSE);\r
534   }\r
535   if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {\r
536     return (FALSE);\r
537   }\r
538 \r
539   JAWS_INIT\r
540 \r
541 //  InitCommonControlsEx(&ex);\r
542   InitCommonControls();\r
543 \r
544   hAccelMain = LoadAccelerators (hInstance, szAppName);\r
545   hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");\r
546   hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */\r
547 \r
548   /* Acquire and dispatch messages until a WM_QUIT message is received. */\r
549 \r
550   while (GetMessage(&msg, /* message structure */\r
551                     NULL, /* handle of window receiving the message */\r
552                     0,    /* lowest message to examine */\r
553                     0))   /* highest message to examine */\r
554     {\r
555 \r
556       if(msg.message == WM_CHAR && msg.wParam == '\t') {\r
557         // [HGM] navigate: switch between all windows with tab\r
558         HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;\r
559         int i, currentElement = 0;\r
560 \r
561         // first determine what element of the chain we come from (if any)\r
562         if(appData.icsActive) {\r
563             hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
564             hText  = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
565         }\r
566         if(engineOutputDialog && EngineOutputIsUp()) {\r
567             e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);\r
568             e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);\r
569         }\r
570         if(moveHistoryDialog && MoveHistoryIsUp()) {\r
571             mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);\r
572         }\r
573         if(msg.hwnd == hwndMain) currentElement = 7 ; else\r
574         if(msg.hwnd == engineOutputDialog) currentElement = 2; else\r
575         if(msg.hwnd == e1)                 currentElement = 2; else\r
576         if(msg.hwnd == e2)                 currentElement = 3; else\r
577         if(msg.hwnd == moveHistoryDialog) currentElement = 4; else\r
578         if(msg.hwnd == mh)                currentElement = 4; else\r
579         if(msg.hwnd == evalGraphDialog)    currentElement = 6; else\r
580         if(msg.hwnd == hText)  currentElement = 5; else\r
581         if(msg.hwnd == hInput) currentElement = 6; else\r
582         for (i = 0; i < N_BUTTONS; i++) {\r
583             if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }\r
584         }\r
585 \r
586         // determine where to go to\r
587         if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;\r
588           do {\r
589             currentElement = (currentElement + direction) % 7;\r
590             switch(currentElement) {\r
591                 case 0:\r
592                   h = hwndMain; break; // passing this case always makes the loop exit\r
593                 case 1:\r
594                   h = buttonDesc[0].hwnd; break; // could be NULL\r
595                 case 2:\r
596                   if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows\r
597                   h = e1; break;\r
598                 case 3:\r
599                   if(!EngineOutputIsUp()) continue;\r
600                   h = e2; break;\r
601                 case 4:\r
602                   if(!MoveHistoryIsUp()) continue;\r
603                   h = mh; break;\r
604 //              case 6: // input to eval graph does not seem to get here!\r
605 //                if(!EvalGraphIsUp()) continue;\r
606 //                h = evalGraphDialog; break;\r
607                 case 5:\r
608                   if(!appData.icsActive) continue;\r
609                   SAY("display");\r
610                   h = hText; break;\r
611                 case 6:\r
612                   if(!appData.icsActive) continue;\r
613                   SAY("input");\r
614                   h = hInput; break;\r
615             }\r
616           } while(h == 0);\r
617 \r
618           if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
619           if(currentElement < 5 && IsIconic(hwndMain))    ShowWindow(hwndMain, SW_RESTORE); // all open together\r
620           SetFocus(h);\r
621 \r
622           continue; // this message now has been processed\r
623         }\r
624       }\r
625 \r
626       if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&\r
627           !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&\r
628           !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&\r
629           !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&\r
630           !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&\r
631           !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&\r
632           !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&\r
633           !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL\r
634           !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&\r
635           !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {\r
636         int done = 0, i; // [HGM] chat: dispatch cat-box messages\r
637         for(i=0; i<MAX_CHAT; i++) \r
638             if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {\r
639                 done = 1; break;\r
640         }\r
641         if(done) continue; // [HGM] chat: end patch\r
642         TranslateMessage(&msg); /* Translates virtual key codes */\r
643         DispatchMessage(&msg);  /* Dispatches message to window */\r
644       }\r
645     }\r
646 \r
647 \r
648   return (msg.wParam);  /* Returns the value from PostQuitMessage */\r
649 }\r
650 \r
651 /*---------------------------------------------------------------------------*\\r
652  *\r
653  * Initialization functions\r
654  *\r
655 \*---------------------------------------------------------------------------*/\r
656 \r
657 void\r
658 SetUserLogo()\r
659 {   // update user logo if necessary\r
660     static char oldUserName[MSG_SIZ], *curName;\r
661 \r
662     if(appData.autoLogo) {\r
663           curName = UserName();\r
664           if(strcmp(curName, oldUserName)) {\r
665                 sprintf(oldUserName, "logos\\%s.bmp", curName);\r
666                 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );    \r
667                 strcpy(oldUserName, curName);\r
668           }\r
669     }\r
670 }\r
671 \r
672 BOOL\r
673 InitApplication(HINSTANCE hInstance)\r
674 {\r
675   WNDCLASS wc;\r
676 \r
677   /* Fill in window class structure with parameters that describe the */\r
678   /* main window. */\r
679 \r
680   wc.style         = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */\r
681   wc.lpfnWndProc   = (WNDPROC)WndProc;  /* Window Procedure */\r
682   wc.cbClsExtra    = 0;                 /* No per-class extra data. */\r
683   wc.cbWndExtra    = 0;                 /* No per-window extra data. */\r
684   wc.hInstance     = hInstance;         /* Owner of this class */\r
685   wc.hIcon         = LoadIcon(hInstance, "icon_white");\r
686   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);       /* Cursor */\r
687   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);  /* Default color */\r
688   wc.lpszMenuName  = szAppName;                 /* Menu name from .RC */\r
689   wc.lpszClassName = szAppName;                 /* Name to register as */\r
690 \r
691   /* Register the window class and return success/failure code. */\r
692   if (!RegisterClass(&wc)) return FALSE;\r
693 \r
694   wc.style         = CS_HREDRAW | CS_VREDRAW;\r
695   wc.lpfnWndProc   = (WNDPROC)ConsoleWndProc;\r
696   wc.cbClsExtra    = 0;\r
697   wc.cbWndExtra    = DLGWINDOWEXTRA;\r
698   wc.hInstance     = hInstance;\r
699   wc.hIcon         = LoadIcon(hInstance, "icon_white");\r
700   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);\r
701   wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);\r
702   wc.lpszMenuName  = NULL;\r
703   wc.lpszClassName = szConsoleName;\r
704 \r
705   if (!RegisterClass(&wc)) return FALSE;\r
706   return TRUE;\r
707 }\r
708 \r
709 \r
710 /* Set by InitInstance, used by EnsureOnScreen */\r
711 int screenHeight, screenWidth;\r
712 \r
713 void\r
714 EnsureOnScreen(int *x, int *y, int minX, int minY)\r
715 {\r
716 //  int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);\r
717   /* Be sure window at (x,y) is not off screen (or even mostly off screen) */\r
718   if (*x > screenWidth - 32) *x = 0;\r
719   if (*y > screenHeight - 32) *y = 0;\r
720   if (*x < minX) *x = minX;\r
721   if (*y < minY) *y = minY;\r
722 }\r
723 \r
724 BOOL\r
725 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)\r
726 {\r
727   HWND hwnd; /* Main window handle. */\r
728   int ibs;\r
729   WINDOWPLACEMENT wp;\r
730   char *filepart;\r
731 \r
732   hInst = hInstance;    /* Store instance handle in our global variable */\r
733 \r
734   if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {\r
735     *filepart = NULLCHAR;\r
736   } else {\r
737     GetCurrentDirectory(MSG_SIZ, installDir);\r
738   }\r
739   gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise\r
740   screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData\r
741   InitAppData(lpCmdLine);      /* Get run-time parameters */\r
742   if (appData.debugMode) {\r
743     debugFP = fopen(appData.nameOfDebugFile, "w");\r
744     setbuf(debugFP, NULL);\r
745   }\r
746 \r
747   InitBackEnd1();\r
748 \r
749 //  InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()\r
750 //  InitEngineUCI( installDir, &second );\r
751 \r
752   /* Create a main window for this application instance. */\r
753   hwnd = CreateWindow(szAppName, szTitle,\r
754                       (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),\r
755                       CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,\r
756                       NULL, NULL, hInstance, NULL);\r
757   hwndMain = hwnd;\r
758 \r
759   /* If window could not be created, return "failure" */\r
760   if (!hwnd) {\r
761     return (FALSE);\r
762   }\r
763 \r
764   /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */\r
765   if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {\r
766       first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
767 \r
768       if (first.programLogo == NULL && appData.debugMode) {\r
769           fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );\r
770       }\r
771   } else if(appData.autoLogo) {\r
772       if(appData.firstDirectory && appData.firstDirectory[0]) {\r
773         char buf[MSG_SIZ];\r
774         sprintf(buf, "%s/logo.bmp", appData.firstDirectory);\r
775         first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );   \r
776       }\r
777   }\r
778 \r
779   if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {\r
780       second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
781 \r
782       if (second.programLogo == NULL && appData.debugMode) {\r
783           fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );\r
784       }\r
785   } else if(appData.autoLogo) {\r
786       char buf[MSG_SIZ];\r
787       if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS\r
788         sprintf(buf, "logos\\%s.bmp", appData.icsHost);\r
789         second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
790       } else\r
791       if(appData.secondDirectory && appData.secondDirectory[0]) {\r
792         sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);\r
793         second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );  \r
794       }\r
795   }\r
796 \r
797   SetUserLogo();\r
798 \r
799   iconWhite = LoadIcon(hInstance, "icon_white");\r
800   iconBlack = LoadIcon(hInstance, "icon_black");\r
801   iconCurrent = iconWhite;\r
802   InitDrawingColors();\r
803   screenHeight = GetSystemMetrics(SM_CYSCREEN);\r
804   screenWidth = GetSystemMetrics(SM_CXSCREEN);\r
805   for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {\r
806     /* Compute window size for each board size, and use the largest\r
807        size that fits on this screen as the default. */\r
808     InitDrawingSizes((BoardSize)(ibs+1000), 0);\r
809     if (boardSize == (BoardSize)-1 &&\r
810         winH <= screenHeight\r
811            - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10\r
812         && winW <= screenWidth) {\r
813       boardSize = (BoardSize)ibs;\r
814     }\r
815   }\r
816 \r
817   InitDrawingSizes(boardSize, 0);\r
818   InitMenuChecks();\r
819   buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);\r
820 \r
821   /* [AS] Load textures if specified */\r
822   ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );\r
823   \r
824   if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {\r
825       liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
826       liteBackTextureMode = appData.liteBackTextureMode;\r
827 \r
828       if (liteBackTexture == NULL && appData.debugMode) {\r
829           fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );\r
830       }\r
831   }\r
832   \r
833   if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {\r
834       darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
835       darkBackTextureMode = appData.darkBackTextureMode;\r
836 \r
837       if (darkBackTexture == NULL && appData.debugMode) {\r
838           fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );\r
839       }\r
840   }\r
841 \r
842   mysrandom( (unsigned) time(NULL) );\r
843 \r
844   /* [AS] Restore layout */\r
845   if( wpMoveHistory.visible ) {\r
846       MoveHistoryPopUp();\r
847   }\r
848 \r
849   if( wpEvalGraph.visible ) {\r
850       EvalGraphPopUp();\r
851   }\r
852 \r
853   if( wpEngineOutput.visible ) {\r
854       EngineOutputPopUp();\r
855   }\r
856 \r
857   InitBackEnd2();\r
858 \r
859   /* Make the window visible; update its client area; and return "success" */\r
860   EnsureOnScreen(&boardX, &boardY, minX, minY);\r
861   wp.length = sizeof(WINDOWPLACEMENT);\r
862   wp.flags = 0;\r
863   wp.showCmd = nCmdShow;\r
864   wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
865   wp.rcNormalPosition.left = boardX;\r
866   wp.rcNormalPosition.right = boardX + winWidth;\r
867   wp.rcNormalPosition.top = boardY;\r
868   wp.rcNormalPosition.bottom = boardY + winHeight;\r
869   SetWindowPlacement(hwndMain, &wp);\r
870 \r
871   if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
872                0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
873 \r
874   if (hwndConsole) {\r
875 #if AOT_CONSOLE\r
876     SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
877                  0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
878 #endif\r
879     ShowWindow(hwndConsole, nCmdShow);\r
880   }\r
881   if(!appData.noGUI)   UpdateWindow(hwnd);  else ShowWindow(hwnd, SW_MINIMIZE);\r
882 \r
883   return TRUE;\r
884 \r
885 }\r
886 \r
887 \r
888 typedef enum {\r
889   ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone, \r
890   ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,\r
891   ArgSettingsFilename,\r
892   ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window\r
893 } ArgType;\r
894 \r
895 typedef struct {\r
896   char *argName;\r
897   ArgType argType;\r
898   /***\r
899   union {\r
900     String *pString;       // ArgString\r
901     int *pInt;             // ArgInt\r
902     float *pFloat;         // ArgFloat\r
903     Boolean *pBoolean;     // ArgBoolean\r
904     COLORREF *pColor;      // ArgColor\r
905     ColorClass cc;         // ArgAttribs\r
906     String *pFilename;     // ArgFilename\r
907     BoardSize *pBoardSize; // ArgBoardSize\r
908     int whichFont;         // ArgFont\r
909     DCB *pDCB;             // ArgCommSettings\r
910     String *pFilename;     // ArgSettingsFilename\r
911   } argLoc;\r
912   ***/\r
913   LPVOID argLoc;\r
914   BOOL save;\r
915 } ArgDescriptor;\r
916 \r
917 int junk;\r
918 ArgDescriptor argDescriptors[] = {\r
919   /* positional arguments */\r
920   { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
921   { "", ArgNone, NULL },\r
922   /* keyword arguments */\r
923   JAWS_ARGS\r
924   { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },\r
925   { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },\r
926   { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },\r
927   { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },\r
928   { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },\r
929   { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },\r
930   { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },\r
931   { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },\r
932   { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },\r
933   { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },\r
934   { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },\r
935   { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },\r
936   { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },\r
937   { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },\r
938   { "initString", ArgString, (LPVOID) &appData.initString, FALSE },\r
939   { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },\r
940   { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },\r
941   { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,\r
942     FALSE },\r
943   { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,\r
944     FALSE },\r
945   { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,\r
946     FALSE },\r
947   { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },\r
948   { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,\r
949     FALSE },\r
950   { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },\r
951   { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
952   { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
953   { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
954   { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
955   { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },\r
956   { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },\r
957   { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },\r
958   { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },\r
959   { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },\r
960   { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },\r
961   { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },\r
962   { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },\r
963   { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },\r
964   { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },\r
965   { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },\r
966   { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },\r
967   /*!!bitmapDirectory?*/\r
968   { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },\r
969   { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },\r
970   { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },\r
971   { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },\r
972   { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },\r
973   { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },\r
974   { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },\r
975   { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },\r
976   { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },\r
977   { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },\r
978   { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },\r
979   { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },\r
980   { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },\r
981   { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },\r
982   { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },\r
983   { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },\r
984   { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },\r
985   { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },\r
986   { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
987   { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
988   { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
989   { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
990   { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },\r
991   { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },\r
992   { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },\r
993   { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },\r
994   { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },\r
995   { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },\r
996   { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },\r
997   { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },\r
998   { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },\r
999   { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
1000   { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
1001   { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },\r
1002   { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },\r
1003   { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },\r
1004   { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },\r
1005   { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },\r
1006   { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },\r
1007   { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },\r
1008   { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },\r
1009   { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },\r
1010   { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },\r
1011   { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },\r
1012   { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },\r
1013   { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },\r
1014   { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },\r
1015   { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },\r
1016   { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },\r
1017   { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },\r
1018   { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },\r
1019   { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },\r
1020   { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },\r
1021   { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },\r
1022   { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },\r
1023   { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },\r
1024   { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },\r
1025   { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },\r
1026   { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },\r
1027   { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },\r
1028   { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },\r
1029   { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },\r
1030   { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },\r
1031   { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },\r
1032   { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },\r
1033   { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },\r
1034   { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },\r
1035   { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },\r
1036   { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },\r
1037   { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },\r
1038   { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },\r
1039   { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },\r
1040   { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },\r
1041   { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },\r
1042   { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },\r
1043   { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },\r
1044   { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },\r
1045   { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },\r
1046   { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },\r
1047   { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },\r
1048   { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },\r
1049   { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },\r
1050   { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },\r
1051   { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },\r
1052   { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },\r
1053   { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },\r
1054   { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },\r
1055   { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },\r
1056   { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },\r
1057   { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },\r
1058   { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },\r
1059   { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },\r
1060   { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },\r
1061   { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, \r
1062     FALSE }, /* only so that old WinBoard.ini files from betas can be read */\r
1063   { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },\r
1064   { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },\r
1065   { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },\r
1066   { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },\r
1067   { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },\r
1068   { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },\r
1069   { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */\r
1070   { "boardSize", ArgBoardSize, (LPVOID) &boardSize,\r
1071     TRUE }, /* must come after all fonts */\r
1072   { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },\r
1073   { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,\r
1074     FALSE }, /* historical; kept only so old winboard.ini files will parse */\r
1075   { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },\r
1076   { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },\r
1077   { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },\r
1078   { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },\r
1079   { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },\r
1080   { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },\r
1081   { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },\r
1082   { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },\r
1083   { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },\r
1084   { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },\r
1085   { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },\r
1086   { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },\r
1087   { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },\r
1088   { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },\r
1089   { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },\r
1090   { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },\r
1091   { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },\r
1092   { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },\r
1093   { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },\r
1094   { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },\r
1095   { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },\r
1096   { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },\r
1097   { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },\r
1098   { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },\r
1099   { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },\r
1100   { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
1101   { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
1102   { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
1103 #if 0\r
1104   { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },\r
1105   { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },\r
1106 #endif\r
1107   { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },\r
1108   { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
1109   { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
1110   { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
1111   { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },\r
1112   { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },\r
1113   { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },\r
1114   { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },\r
1115   { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },\r
1116   { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },\r
1117   { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },\r
1118   { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },\r
1119   { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },\r
1120   { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },\r
1121   { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },\r
1122   { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },\r
1123   { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },\r
1124   { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },\r
1125   { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },\r
1126   { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },\r
1127   { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },\r
1128   { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },\r
1129   { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },\r
1130   { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },\r
1131   { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },\r
1132   { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },\r
1133   { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },\r
1134   { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },\r
1135   { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },\r
1136   { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },\r
1137   { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },\r
1138   { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },\r
1139   { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },\r
1140   { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },\r
1141   { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},\r
1142   { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},\r
1143   { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},\r
1144   { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},\r
1145   { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},\r
1146   { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},\r
1147   { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},\r
1148   { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },\r
1149   { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },\r
1150   { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },\r
1151   { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },\r
1152   { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },\r
1153   { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },\r
1154   { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },\r
1155   { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },\r
1156   { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },\r
1157   { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },\r
1158   { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },\r
1159   { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },\r
1160   { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },\r
1161   { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },\r
1162   { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },\r
1163   { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },\r
1164   { "highlightLastMove", ArgBoolean,\r
1165     (LPVOID) &appData.highlightLastMove, TRUE },\r
1166   { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },\r
1167   { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },\r
1168   { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },\r
1169   { "highlightDragging", ArgBoolean,\r
1170     (LPVOID) &appData.highlightDragging, TRUE },\r
1171   { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },\r
1172   { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },\r
1173   { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },\r
1174   { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },\r
1175   { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },\r
1176   { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },\r
1177   { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },\r
1178   { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },\r
1179   { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },\r
1180   { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },\r
1181   { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },\r
1182   { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },\r
1183   { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },\r
1184   { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },\r
1185   { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },\r
1186   { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },\r
1187   { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },\r
1188   { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },\r
1189   { "soundShout", ArgFilename,\r
1190     (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },\r
1191   { "soundSShout", ArgFilename,\r
1192     (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },\r
1193   { "soundChannel1", ArgFilename,\r
1194     (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },\r
1195   { "soundChannel", ArgFilename,\r
1196     (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },\r
1197   { "soundKibitz", ArgFilename,\r
1198     (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },\r
1199   { "soundTell", ArgFilename,\r
1200     (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },\r
1201   { "soundChallenge", ArgFilename,\r
1202     (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },\r
1203   { "soundRequest", ArgFilename,\r
1204     (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },\r
1205   { "soundSeek", ArgFilename,\r
1206     (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },\r
1207   { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },\r
1208   { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },\r
1209   { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },\r
1210   { "soundIcsLoss", ArgFilename, \r
1211     (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },\r
1212   { "soundIcsDraw", ArgFilename, \r
1213     (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },\r
1214   { "soundIcsUnfinished", ArgFilename, \r
1215     (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},\r
1216   { "soundIcsAlarm", ArgFilename, \r
1217     (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },\r
1218   { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },\r
1219   { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },\r
1220   { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },\r
1221   { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },\r
1222   { "reuseChessPrograms", ArgBoolean,\r
1223     (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */\r
1224   { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },\r
1225   { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },\r
1226   { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
1227   { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
1228   { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },\r
1229   { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
1230   { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
1231   { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },\r
1232   { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },\r
1233   { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },\r
1234   { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },\r
1235   { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },\r
1236   { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },\r
1237   { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },\r
1238   { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,\r
1239     TRUE },\r
1240   { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,\r
1241     TRUE },\r
1242   { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
1243   { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
1244   { "variant", ArgString, (LPVOID) &appData.variant, FALSE },\r
1245   { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },\r
1246   { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },\r
1247   { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },\r
1248   { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },\r
1249   { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
1250   { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
1251   /* [AS] New features */\r
1252   { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },\r
1253   { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },\r
1254   { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },\r
1255   { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },\r
1256   { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },\r
1257   { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },\r
1258   { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },\r
1259   { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },\r
1260   { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },\r
1261   { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },\r
1262   { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },\r
1263   { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },\r
1264   { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },\r
1265   { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },\r
1266   { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },\r
1267   { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },\r
1268   { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },\r
1269   { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },\r
1270   { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },\r
1271   { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },\r
1272   { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },\r
1273   { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },\r
1274   { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },\r
1275   { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },\r
1276   { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },\r
1277   { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },\r
1278   { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },\r
1279   { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },\r
1280   { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },\r
1281   { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },\r
1282   { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },\r
1283   { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },\r
1284   { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },\r
1285   { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },\r
1286   { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },\r
1287   { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },\r
1288   { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },\r
1289   { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },\r
1290   { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
1291   { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
1292   { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
1293   { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
1294   { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
1295   { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
1296   { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },\r
1297   { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },\r
1298   { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },\r
1299   { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE }, \r
1300   { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },\r
1301   { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },\r
1302 \r
1303   /* [HGM] board-size, adjudication and misc. options */\r
1304   { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },\r
1305   { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },\r
1306   { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },\r
1307   { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },\r
1308   { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },\r
1309   { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },\r
1310   { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },\r
1311   { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },\r
1312   { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },\r
1313   { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },\r
1314   { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },\r
1315   { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },\r
1316   { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },\r
1317   { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },\r
1318   { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },\r
1319   { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },\r
1320   { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },\r
1321   { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },\r
1322   { "userName", ArgString, (LPVOID) &appData.userName, FALSE },\r
1323   { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },\r
1324   { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },\r
1325   { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },\r
1326   { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },\r
1327   { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },\r
1328   { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },\r
1329   { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },\r
1330   { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },\r
1331   { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },\r
1332   { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },\r
1333   { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },\r
1334   { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },\r
1335   { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },\r
1336   { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },\r
1337 \r
1338 #ifdef ZIPPY\r
1339   { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
1340   { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },\r
1341   { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
1342   { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
1343   { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },\r
1344   { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },\r
1345   { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
1346   { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
1347   { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },\r
1348   { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },\r
1349   { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },\r
1350   { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },\r
1351   { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,\r
1352     FALSE },\r
1353   { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },\r
1354   { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },\r
1355   { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },\r
1356   { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
1357   { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
1358   { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },\r
1359   { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,\r
1360     FALSE },\r
1361   { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
1362   { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
1363   { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
1364   { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },\r
1365   { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },\r
1366   { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1367   { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1368   { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1369   { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1370   { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },\r
1371   { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },\r
1372   { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
1373   { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
1374   { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },\r
1375   { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },\r
1376   { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },\r
1377   { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },\r
1378   /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */\r
1379   { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },\r
1380 #endif\r
1381   /* [HGM] options for broadcasting and time odds */\r
1382   { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },\r
1383   { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },\r
1384   { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },\r
1385   { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },\r
1386   { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },\r
1387   { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },\r
1388   { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },\r
1389   { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },\r
1390   { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },\r
1391   { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },\r
1392   { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },\r
1393 \r
1394   // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others\r
1395   { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed\r
1396   { "minY", ArgZ, (LPVOID) &minY, FALSE },\r
1397   { "winWidth",  ArgInt, (LPVOID) &winWidth,  TRUE }, // [HGM] placement: dummies to remember right & bottom\r
1398   { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, //       for attaching auxiliary windows to them\r
1399   { "x", ArgInt, (LPVOID) &boardX, TRUE },\r
1400   { "y", ArgInt, (LPVOID) &boardY, TRUE },\r
1401   { "icsX", ArgX,   (LPVOID) &wpConsole.x, TRUE },\r
1402   { "icsY", ArgY,   (LPVOID) &wpConsole.y, TRUE },\r
1403   { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },\r
1404   { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },\r
1405   { "analysisX", ArgX,   (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists\r
1406   { "analysisY", ArgY,   (LPVOID) &analysisY, FALSE }, //       provided for compatibility with old ini files\r
1407   { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },\r
1408   { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },\r
1409   { "commentX", ArgX,   (LPVOID) &commentX, TRUE },\r
1410   { "commentY", ArgY,   (LPVOID) &commentY, TRUE },\r
1411   { "commentW", ArgInt, (LPVOID) &commentW, TRUE },\r
1412   { "commentH", ArgInt, (LPVOID) &commentH, TRUE },\r
1413   { "tagsX", ArgX,   (LPVOID) &editTagsX, TRUE },\r
1414   { "tagsY", ArgY,   (LPVOID) &editTagsY, TRUE },\r
1415   { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },\r
1416   { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },\r
1417   { "gameListX", ArgX,   (LPVOID) &wpGameList.x, TRUE },\r
1418   { "gameListY", ArgY,   (LPVOID) &wpGameList.y, TRUE },\r
1419   { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },\r
1420   { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },\r
1421   /* [AS] Layout stuff */\r
1422   { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },\r
1423   { "moveHistoryX", ArgX,   (LPVOID) &wpMoveHistory.x, TRUE },\r
1424   { "moveHistoryY", ArgY,   (LPVOID) &wpMoveHistory.y, TRUE },\r
1425   { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },\r
1426   { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },\r
1427 \r
1428   { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },\r
1429   { "evalGraphX", ArgX,   (LPVOID) &wpEvalGraph.x, TRUE },\r
1430   { "evalGraphY", ArgY,   (LPVOID) &wpEvalGraph.y, TRUE },\r
1431   { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },\r
1432   { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },\r
1433 \r
1434   { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },\r
1435   { "engineOutputX", ArgX,   (LPVOID) &wpEngineOutput.x, TRUE },\r
1436   { "engineOutputY", ArgY,   (LPVOID) &wpEngineOutput.y, TRUE },\r
1437   { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },\r
1438   { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },\r
1439 \r
1440   { NULL, ArgNone, NULL, FALSE }\r
1441 };\r
1442 \r
1443 \r
1444 /* Kludge for indirection files on command line */\r
1445 char* lastIndirectionFilename;\r
1446 ArgDescriptor argDescriptorIndirection =\r
1447 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };\r
1448 \r
1449 \r
1450 VOID\r
1451 ExitArgError(char *msg, char *badArg)\r
1452 {\r
1453   char buf[MSG_SIZ];\r
1454 \r
1455   sprintf(buf, "%s %s", msg, badArg);\r
1456   DisplayFatalError(buf, 0, 2);\r
1457   exit(2);\r
1458 }\r
1459 \r
1460 /* Command line font name parser.  NULL name means do nothing.\r
1461    Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"\r
1462    For backward compatibility, syntax without the colon is also\r
1463    accepted, but font names with digits in them won't work in that case.\r
1464 */\r
1465 VOID\r
1466 ParseFontName(char *name, MyFontParams *mfp)\r
1467 {\r
1468   char *p, *q;\r
1469   if (name == NULL) return;\r
1470   p = name;\r
1471   q = strchr(p, ':');\r
1472   if (q) {\r
1473     if (q - p >= sizeof(mfp->faceName))\r
1474       ExitArgError("Font name too long:", name);\r
1475     memcpy(mfp->faceName, p, q - p);\r
1476     mfp->faceName[q - p] = NULLCHAR;\r
1477     p = q + 1;\r
1478   } else {\r
1479     q = mfp->faceName;\r
1480     while (*p && !isdigit(*p)) {\r
1481       *q++ = *p++;\r
1482       if (q - mfp->faceName >= sizeof(mfp->faceName))\r
1483         ExitArgError("Font name too long:", name);\r
1484     }\r
1485     while (q > mfp->faceName && q[-1] == ' ') q--;\r
1486     *q = NULLCHAR;\r
1487   }\r
1488   if (!*p) ExitArgError("Font point size missing:", name);\r
1489   mfp->pointSize = (float) atof(p);\r
1490   mfp->bold = (strchr(p, 'b') != NULL);\r
1491   mfp->italic = (strchr(p, 'i') != NULL);\r
1492   mfp->underline = (strchr(p, 'u') != NULL);\r
1493   mfp->strikeout = (strchr(p, 's') != NULL);\r
1494 }\r
1495 \r
1496 /* Color name parser.\r
1497    X version accepts X color names, but this one\r
1498    handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */\r
1499 COLORREF\r
1500 ParseColorName(char *name)\r
1501 {\r
1502   int red, green, blue, count;\r
1503   char buf[MSG_SIZ];\r
1504 \r
1505   count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);\r
1506   if (count != 3) {\r
1507     count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d", \r
1508       &red, &green, &blue);\r
1509   }\r
1510   if (count != 3) {\r
1511     sprintf(buf, "Can't parse color name %s", name);\r
1512     DisplayError(buf, 0);\r
1513     return RGB(0, 0, 0);\r
1514   }\r
1515   return PALETTERGB(red, green, blue);\r
1516 }\r
1517 \r
1518 \r
1519 void ParseAttribs(COLORREF *color, int *effects, char* argValue)\r
1520 {\r
1521   char *e = argValue;\r
1522   int eff = 0;\r
1523 \r
1524   while (*e) {\r
1525     if (*e == 'b')      eff |= CFE_BOLD;\r
1526     else if (*e == 'i') eff |= CFE_ITALIC;\r
1527     else if (*e == 'u') eff |= CFE_UNDERLINE;\r
1528     else if (*e == 's') eff |= CFE_STRIKEOUT;\r
1529     else if (*e == '#' || isdigit(*e)) break;\r
1530     e++;\r
1531   }\r
1532   *effects = eff;\r
1533   *color   = ParseColorName(e);\r
1534 }\r
1535 \r
1536 \r
1537 BoardSize\r
1538 ParseBoardSize(char *name)\r
1539 {\r
1540   BoardSize bs = SizeTiny;\r
1541   while (sizeInfo[bs].name != NULL) {\r
1542     if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;\r
1543     bs++;\r
1544   }\r
1545   ExitArgError("Unrecognized board size value", name);\r
1546   return bs; /* not reached */\r
1547 }\r
1548 \r
1549 \r
1550 char\r
1551 StringGet(void *getClosure)\r
1552 {\r
1553   char **p = (char **) getClosure;\r
1554   return *((*p)++);\r
1555 }\r
1556 \r
1557 char\r
1558 FileGet(void *getClosure)\r
1559 {\r
1560   int c;\r
1561   FILE* f = (FILE*) getClosure;\r
1562 \r
1563   c = getc(f);\r
1564   if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely\r
1565   if (c == EOF)\r
1566     return NULLCHAR;\r
1567   else\r
1568     return (char) c;\r
1569 }\r
1570 \r
1571 /* Parse settings file named "name". If file found, return the\r
1572    full name in fullname and return TRUE; else return FALSE */\r
1573 BOOLEAN\r
1574 ParseSettingsFile(char *name, char fullname[MSG_SIZ])\r
1575 {\r
1576   char *dummy;\r
1577   FILE *f;\r
1578   int ok; char buf[MSG_SIZ];\r
1579 \r
1580   ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);\r
1581   if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed\r
1582     sprintf(buf, "%s.ini", name);\r
1583     ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);\r
1584   }\r
1585   if (ok) {\r
1586     f = fopen(fullname, "r");\r
1587     if (f != NULL) {\r
1588       ParseArgs(FileGet, f);\r
1589       fclose(f);\r
1590       return TRUE;\r
1591     }\r
1592   }\r
1593   return FALSE;\r
1594 }\r
1595 \r
1596 VOID\r
1597 ParseArgs(GetFunc get, void *cl)\r
1598 {\r
1599   char argName[ARG_MAX];\r
1600   char argValue[ARG_MAX];\r
1601   ArgDescriptor *ad;\r
1602   char start;\r
1603   char *q;\r
1604   int i, octval;\r
1605   char ch;\r
1606   int posarg = 0;\r
1607 \r
1608   ch = get(cl);\r
1609   for (;;) {\r
1610     while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);\r
1611     if (ch == NULLCHAR) break;\r
1612     if (ch == ';') {\r
1613       /* Comment to end of line */\r
1614       ch = get(cl);\r
1615       while (ch != '\n' && ch != NULLCHAR) ch = get(cl);\r
1616       continue;\r
1617     } else if (ch == '/' || ch == '-') {\r
1618       /* Switch */\r
1619       q = argName;\r
1620       while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&\r
1621              ch != '\n' && ch != '\t') {\r
1622         *q++ = ch;\r
1623         ch = get(cl);\r
1624       }\r
1625       *q = NULLCHAR;\r
1626 \r
1627       for (ad = argDescriptors; ad->argName != NULL; ad++)\r
1628         if (strcmp(ad->argName, argName + 1) == 0) break;\r
1629 \r
1630       if (ad->argName == NULL)\r
1631         ExitArgError("Unrecognized argument", argName);\r
1632 \r
1633     } else if (ch == '@') {\r
1634       /* Indirection file */\r
1635       ad = &argDescriptorIndirection;\r
1636       ch = get(cl);\r
1637     } else {\r
1638       /* Positional argument */\r
1639       ad = &argDescriptors[posarg++];\r
1640       strcpy(argName, ad->argName);\r
1641     }\r
1642 \r
1643     if (ad->argType == ArgTrue) {\r
1644       *(Boolean *) ad->argLoc = TRUE;\r
1645       continue;\r
1646     }\r
1647     if (ad->argType == ArgFalse) {\r
1648       *(Boolean *) ad->argLoc = FALSE;\r
1649       continue;\r
1650     }\r
1651 \r
1652     while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);\r
1653     if (ch == NULLCHAR || ch == '\n') {\r
1654       ExitArgError("No value provided for argument", argName);\r
1655     }\r
1656     q = argValue;\r
1657     if (ch == '{') {\r
1658       // Quoting with { }.  No characters have to (or can) be escaped.\r
1659       // Thus the string cannot contain a '}' character.\r
1660       start = ch;\r
1661       ch = get(cl);\r
1662       while (start) {\r
1663         switch (ch) {\r
1664         case NULLCHAR:\r
1665           start = NULLCHAR;\r
1666           break;\r
1667           \r
1668         case '}':\r
1669           ch = get(cl);\r
1670           start = NULLCHAR;\r
1671           break;\r
1672 \r
1673         default:\r
1674           *q++ = ch;\r
1675           ch = get(cl);\r
1676           break;\r
1677         }\r
1678       }   \r
1679     } else if (ch == '\'' || ch == '"') {\r
1680       // Quoting with ' ' or " ", with \ as escape character.\r
1681       // Inconvenient for long strings that may contain Windows filenames.\r
1682       start = ch;\r
1683       ch = get(cl);\r
1684       while (start) {\r
1685         switch (ch) {\r
1686         case NULLCHAR:\r
1687           start = NULLCHAR;\r
1688           break;\r
1689 \r
1690         default:\r
1691         not_special:\r
1692           *q++ = ch;\r
1693           ch = get(cl);\r
1694           break;\r
1695 \r
1696         case '\'':\r
1697         case '\"':\r
1698           if (ch == start) {\r
1699             ch = get(cl);\r
1700             start = NULLCHAR;\r
1701             break;\r
1702           } else {\r
1703             goto not_special;\r
1704           }\r
1705 \r
1706         case '\\':\r
1707           if (ad->argType == ArgFilename\r
1708               || ad->argType == ArgSettingsFilename) {\r
1709               goto not_special;\r
1710           }\r
1711           ch = get(cl);\r
1712           switch (ch) {\r
1713           case NULLCHAR:\r
1714             ExitArgError("Incomplete \\ escape in value for", argName);\r
1715             break;\r
1716           case 'n':\r
1717             *q++ = '\n';\r
1718             ch = get(cl);\r
1719             break;\r
1720           case 'r':\r
1721             *q++ = '\r';\r
1722             ch = get(cl);\r
1723             break;\r
1724           case 't':\r
1725             *q++ = '\t';\r
1726             ch = get(cl);\r
1727             break;\r
1728           case 'b':\r
1729             *q++ = '\b';\r
1730             ch = get(cl);\r
1731             break;\r
1732           case 'f':\r
1733             *q++ = '\f';\r
1734             ch = get(cl);\r
1735             break;\r
1736           default:\r
1737             octval = 0;\r
1738             for (i = 0; i < 3; i++) {\r
1739               if (ch >= '0' && ch <= '7') {\r
1740                 octval = octval*8 + (ch - '0');\r
1741                 ch = get(cl);\r
1742               } else {\r
1743                 break;\r
1744               }\r
1745             }\r
1746             if (i > 0) {\r
1747               *q++ = (char) octval;\r
1748             } else {\r
1749               *q++ = ch;\r
1750               ch = get(cl);\r
1751             }\r
1752             break;\r
1753           }\r
1754           break;\r
1755         }\r
1756       }\r
1757     } else {\r
1758       while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {\r
1759         *q++ = ch;\r
1760         ch = get(cl);\r
1761       }\r
1762     }\r
1763     *q = NULLCHAR;\r
1764 \r
1765     switch (ad->argType) {\r
1766     case ArgInt:\r
1767       *(int *) ad->argLoc = atoi(argValue);\r
1768       break;\r
1769 \r
1770     case ArgX:\r
1771       *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute \r
1772       break;\r
1773 \r
1774     case ArgY:\r
1775       *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)\r
1776       break;\r
1777 \r
1778     case ArgZ:\r
1779       *(int *) ad->argLoc = atoi(argValue);\r
1780       EnsureOnScreen(&boardX, &boardY, minX, minY); \r
1781       break;\r
1782 \r
1783     case ArgFloat:\r
1784       *(float *) ad->argLoc = (float) atof(argValue);\r
1785       break;\r
1786 \r
1787     case ArgString:\r
1788     case ArgFilename:\r
1789       *(char **) ad->argLoc = strdup(argValue);\r
1790       break;\r
1791 \r
1792     case ArgSettingsFilename:\r
1793       {\r
1794         char fullname[MSG_SIZ];\r
1795         if (ParseSettingsFile(argValue, fullname)) {\r
1796           if (ad->argLoc != NULL) {\r
1797             *(char **) ad->argLoc = strdup(fullname);\r
1798           }\r
1799         } else {\r
1800           if (ad->argLoc != NULL) {\r
1801           } else {\r
1802             ExitArgError("Failed to open indirection file", argValue);\r
1803           }\r
1804         }\r
1805       }\r
1806       break;\r
1807 \r
1808     case ArgBoolean:\r
1809       switch (argValue[0]) {\r
1810       case 't':\r
1811       case 'T':\r
1812         *(Boolean *) ad->argLoc = TRUE;\r
1813         break;\r
1814       case 'f':\r
1815       case 'F':\r
1816         *(Boolean *) ad->argLoc = FALSE;\r
1817         break;\r
1818       default:\r
1819         ExitArgError("Unrecognized boolean argument value", argValue);\r
1820         break;\r
1821       }\r
1822       break;\r
1823 \r
1824     case ArgColor:\r
1825       *(COLORREF *)ad->argLoc = ParseColorName(argValue);\r
1826       break;\r
1827 \r
1828     case ArgAttribs: {\r
1829       ColorClass cc = (ColorClass)ad->argLoc;\r
1830       ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);\r
1831       }\r
1832       break;\r
1833       \r
1834     case ArgBoardSize:\r
1835       *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);\r
1836       break;\r
1837 \r
1838     case ArgFont:\r
1839       ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);\r
1840       break;\r
1841 \r
1842     case ArgCommSettings:\r
1843       ParseCommSettings(argValue, &dcb);\r
1844       break;\r
1845 \r
1846     case ArgNone:\r
1847       ExitArgError("Unrecognized argument", argValue);\r
1848       break;\r
1849     case ArgTrue:\r
1850     case ArgFalse: ;\r
1851     }\r
1852   }\r
1853 }\r
1854 \r
1855 VOID\r
1856 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)\r
1857 {\r
1858   HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);\r
1859   lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);\r
1860   DeleteDC(hdc);\r
1861   lf->lfWidth = 0;\r
1862   lf->lfEscapement = 0;\r
1863   lf->lfOrientation = 0;\r
1864   lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;\r
1865   lf->lfItalic = mfp->italic;\r
1866   lf->lfUnderline = mfp->underline;\r
1867   lf->lfStrikeOut = mfp->strikeout;\r
1868   lf->lfCharSet = DEFAULT_CHARSET;\r
1869   lf->lfOutPrecision = OUT_DEFAULT_PRECIS;\r
1870   lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
1871   lf->lfQuality = DEFAULT_QUALITY;\r
1872   lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;\r
1873   strcpy(lf->lfFaceName, mfp->faceName);\r
1874 }\r
1875 \r
1876 VOID\r
1877 CreateFontInMF(MyFont *mf)\r
1878 {\r
1879   LFfromMFP(&mf->lf, &mf->mfp);\r
1880   if (mf->hf) DeleteObject(mf->hf);\r
1881   mf->hf = CreateFontIndirect(&mf->lf);\r
1882 }\r
1883 \r
1884 VOID\r
1885 SetDefaultTextAttribs()\r
1886 {\r
1887   ColorClass cc;\r
1888   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1889     ParseAttribs(&textAttribs[cc].color, \r
1890                  &textAttribs[cc].effects, \r
1891                  defaultTextAttribs[cc]);\r
1892   }\r
1893 }\r
1894 \r
1895 VOID\r
1896 SetDefaultSounds()\r
1897 {\r
1898   ColorClass cc;\r
1899   SoundClass sc;\r
1900   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1901     textAttribs[cc].sound.name = strdup("");\r
1902     textAttribs[cc].sound.data = NULL;\r
1903   }\r
1904   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
1905     sounds[sc].name = strdup("");\r
1906     sounds[sc].data = NULL;\r
1907   }\r
1908   sounds[(int)SoundBell].name = strdup(SOUND_BELL);\r
1909 }\r
1910 \r
1911 VOID\r
1912 LoadAllSounds()\r
1913 {\r
1914   ColorClass cc;\r
1915   SoundClass sc;\r
1916   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1917     MyLoadSound(&textAttribs[cc].sound);\r
1918   }\r
1919   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
1920     MyLoadSound(&sounds[sc]);\r
1921   }\r
1922 }\r
1923 \r
1924 VOID\r
1925 InitAppData(LPSTR lpCmdLine)\r
1926 {\r
1927   int i, j;\r
1928   char buf[ARG_MAX], currDir[MSG_SIZ];\r
1929   char *dummy, *p;\r
1930 \r
1931   programName = szAppName;\r
1932 \r
1933   /* Initialize to defaults */\r
1934   lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);\r
1935   darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);\r
1936   whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);\r
1937   blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);\r
1938   highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);\r
1939   premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);\r
1940   consoleBackgroundColor = ParseColorName(COLOR_BKGD);\r
1941   SetDefaultTextAttribs();\r
1942   SetDefaultSounds();\r
1943   appData.movesPerSession = MOVES_PER_SESSION;\r
1944   appData.initString = INIT_STRING;\r
1945   appData.secondInitString = INIT_STRING;\r
1946   appData.firstComputerString = COMPUTER_STRING;\r
1947   appData.secondComputerString = COMPUTER_STRING;\r
1948   appData.firstChessProgram = FIRST_CHESS_PROGRAM;\r
1949   appData.secondChessProgram = SECOND_CHESS_PROGRAM;\r
1950   appData.firstPlaysBlack = FALSE;\r
1951   appData.noChessProgram = FALSE;\r
1952   chessProgram = FALSE;\r
1953   appData.firstHost = FIRST_HOST;\r
1954   appData.secondHost = SECOND_HOST;\r
1955   appData.firstDirectory = FIRST_DIRECTORY;\r
1956   appData.secondDirectory = SECOND_DIRECTORY;\r
1957   appData.bitmapDirectory = "";\r
1958   appData.remoteShell = REMOTE_SHELL;\r
1959   appData.remoteUser = "";\r
1960   appData.timeDelay = TIME_DELAY;\r
1961   appData.timeControl = TIME_CONTROL;\r
1962   appData.timeIncrement = TIME_INCREMENT;\r
1963   appData.icsActive = FALSE;\r
1964   appData.icsHost = "";\r
1965   appData.icsPort = ICS_PORT;\r
1966   appData.icsCommPort = ICS_COMM_PORT;\r
1967   appData.icsLogon = ICS_LOGON;\r
1968   appData.icsHelper = "";\r
1969   appData.useTelnet = FALSE;\r
1970   appData.telnetProgram = TELNET_PROGRAM;\r
1971   appData.gateway = "";\r
1972   appData.loadGameFile = "";\r
1973   appData.loadGameIndex = 0;\r
1974   appData.saveGameFile = "";\r
1975   appData.autoSaveGames = FALSE;\r
1976   appData.loadPositionFile = "";\r
1977   appData.loadPositionIndex = 1;\r
1978   appData.savePositionFile = "";\r
1979   appData.matchMode = FALSE;\r
1980   appData.matchGames = 0;\r
1981   appData.monoMode = FALSE;\r
1982   appData.debugMode = FALSE;\r
1983   appData.clockMode = TRUE;\r
1984   boardSize = (BoardSize) -1; /* determine by screen size */\r
1985   appData.Iconic = FALSE; /*unused*/\r
1986   appData.searchTime = "";\r
1987   appData.searchDepth = 0;\r
1988   appData.showCoords = FALSE;\r
1989   appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/\r
1990   appData.autoCallFlag = FALSE;\r
1991   appData.flipView = FALSE;\r
1992   appData.autoFlipView = TRUE;\r
1993   appData.cmailGameName = "";\r
1994   appData.alwaysPromoteToQueen = FALSE;\r
1995   appData.oldSaveStyle = FALSE;\r
1996   appData.quietPlay = FALSE;\r
1997   appData.showThinking = FALSE;\r
1998   appData.ponderNextMove = TRUE;\r
1999   appData.periodicUpdates = TRUE;\r
2000   appData.popupExitMessage = TRUE;\r
2001   appData.popupMoveErrors = FALSE;\r
2002   appData.autoObserve = FALSE;\r
2003   appData.autoComment = FALSE;\r
2004   appData.animate = TRUE;\r
2005   appData.animSpeed = 10;\r
2006   appData.animateDragging = TRUE;\r
2007   appData.highlightLastMove = TRUE;\r
2008   appData.getMoveList = TRUE;\r
2009   appData.testLegality = TRUE;\r
2010   appData.premove = TRUE;\r
2011   appData.premoveWhite = FALSE;\r
2012   appData.premoveWhiteText = "";\r
2013   appData.premoveBlack = FALSE;\r
2014   appData.premoveBlackText = "";\r
2015   appData.icsAlarm = TRUE;\r
2016   appData.icsAlarmTime = 5000;\r
2017   appData.autoRaiseBoard = TRUE;\r
2018   appData.localLineEditing = TRUE;\r
2019   appData.colorize = TRUE;\r
2020   appData.reuseFirst = TRUE;\r
2021   appData.reuseSecond = TRUE;\r
2022   appData.blindfold = FALSE;\r
2023   appData.icsEngineAnalyze = FALSE;\r
2024   memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +\r
2025   dcb.DCBlength = sizeof(DCB);\r
2026   dcb.BaudRate = 9600;\r
2027   dcb.fBinary = TRUE;\r
2028   dcb.fParity = FALSE;\r
2029   dcb.fOutxCtsFlow = FALSE;\r
2030   dcb.fOutxDsrFlow = FALSE;\r
2031   dcb.fDtrControl = DTR_CONTROL_ENABLE;\r
2032   dcb.fDsrSensitivity = FALSE;\r
2033   dcb.fTXContinueOnXoff = TRUE;\r
2034   dcb.fOutX = FALSE;\r
2035   dcb.fInX = FALSE;\r
2036   dcb.fNull = FALSE;\r
2037   dcb.fRtsControl = RTS_CONTROL_ENABLE;\r
2038   dcb.fAbortOnError = FALSE;\r
2039   dcb.ByteSize = 7;\r
2040   dcb.Parity = SPACEPARITY;\r
2041   dcb.StopBits = ONESTOPBIT;\r
2042   settingsFileName = SETTINGS_FILE;\r
2043   saveSettingsOnExit = TRUE;\r
2044   boardX = CW_USEDEFAULT;\r
2045   boardY = CW_USEDEFAULT;\r
2046   analysisX = CW_USEDEFAULT; \r
2047   analysisY = CW_USEDEFAULT; \r
2048   analysisW = CW_USEDEFAULT;\r
2049   analysisH = CW_USEDEFAULT;\r
2050   commentX = CW_USEDEFAULT; \r
2051   commentY = CW_USEDEFAULT; \r
2052   commentW = CW_USEDEFAULT;\r
2053   commentH = CW_USEDEFAULT;\r
2054   editTagsX = CW_USEDEFAULT; \r
2055   editTagsY = CW_USEDEFAULT; \r
2056   editTagsW = CW_USEDEFAULT;\r
2057   editTagsH = CW_USEDEFAULT;\r
2058   icsTextMenuString = ICS_TEXT_MENU_DEFAULT;\r
2059   icsNames = ICS_NAMES;\r
2060   firstChessProgramNames = FCP_NAMES;\r
2061   secondChessProgramNames = SCP_NAMES;\r
2062   appData.initialMode = "";\r
2063   appData.variant = "normal";\r
2064   appData.firstProtocolVersion = PROTOVER;\r
2065   appData.secondProtocolVersion = PROTOVER;\r
2066   appData.showButtonBar = TRUE;\r
2067 \r
2068    /* [AS] New properties (see comments in header file) */\r
2069   appData.firstScoreIsAbsolute = FALSE;\r
2070   appData.secondScoreIsAbsolute = FALSE;\r
2071   appData.saveExtendedInfoInPGN = FALSE;\r
2072   appData.hideThinkingFromHuman = FALSE;\r
2073   appData.liteBackTextureFile = "";\r
2074   appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
2075   appData.darkBackTextureFile = "";\r
2076   appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
2077   appData.renderPiecesWithFont = "";\r
2078   appData.fontToPieceTable = "";\r
2079   appData.fontBackColorWhite = 0;\r
2080   appData.fontForeColorWhite = 0;\r
2081   appData.fontBackColorBlack = 0;\r
2082   appData.fontForeColorBlack = 0;\r
2083   appData.fontPieceSize = 80;\r
2084   appData.overrideLineGap = 1;\r
2085   appData.adjudicateLossThreshold = 0;\r
2086   appData.delayBeforeQuit = 0;\r
2087   appData.delayAfterQuit = 0;\r
2088   appData.nameOfDebugFile = "winboard.debug";\r
2089   appData.pgnEventHeader = "Computer Chess Game";\r
2090   appData.defaultFrcPosition = -1;\r
2091   appData.gameListTags = GLT_DEFAULT_TAGS;\r
2092   appData.saveOutOfBookInfo = TRUE;\r
2093   appData.showEvalInMoveHistory = TRUE;\r
2094   appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );\r
2095   appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );\r
2096   appData.highlightMoveWithArrow = FALSE;\r
2097   appData.highlightArrowColor = ParseColorName( "#FFFF80" );\r
2098   appData.useStickyWindows = TRUE;\r
2099   appData.adjudicateDrawMoves = 0;\r
2100   appData.autoDisplayComment = TRUE;\r
2101   appData.autoDisplayTags = TRUE;\r
2102   appData.firstIsUCI = FALSE;\r
2103   appData.secondIsUCI = FALSE;\r
2104   appData.firstHasOwnBookUCI = TRUE;\r
2105   appData.secondHasOwnBookUCI = TRUE;\r
2106   appData.polyglotDir = "";\r
2107   appData.usePolyglotBook = FALSE;\r
2108   appData.polyglotBook = "";\r
2109   appData.defaultHashSize = 64;\r
2110   appData.defaultCacheSizeEGTB = 4;\r
2111   appData.defaultPathEGTB = "c:\\egtb";\r
2112   appData.firstOptions = "";\r
2113   appData.secondOptions = "";\r
2114 \r
2115   InitWindowPlacement( &wpGameList );\r
2116   InitWindowPlacement( &wpMoveHistory );\r
2117   InitWindowPlacement( &wpEvalGraph );\r
2118   InitWindowPlacement( &wpEngineOutput );\r
2119   InitWindowPlacement( &wpConsole );\r
2120 \r
2121   /* [HGM] User-selectable board size, adjudication control, miscellaneous */\r
2122   appData.NrFiles      = -1;\r
2123   appData.NrRanks      = -1;\r
2124   appData.holdingsSize = -1;\r
2125   appData.testClaims   = FALSE;\r
2126   appData.checkMates   = FALSE;\r
2127   appData.materialDraws= FALSE;\r
2128   appData.trivialDraws = FALSE;\r
2129   appData.ruleMoves    = 51;\r
2130   appData.drawRepeats  = 6;\r
2131   appData.matchPause   = 10000;\r
2132   appData.alphaRank    = FALSE;\r
2133   appData.allWhite     = FALSE;\r
2134   appData.upsideDown   = FALSE;\r
2135   appData.serverPause  = 15;\r
2136   appData.serverMovesName   = NULL;\r
2137   appData.suppressLoadMoves = FALSE;\r
2138   appData.firstTimeOdds  = 1;\r
2139   appData.secondTimeOdds = 1;\r
2140   appData.firstAccumulateTC  = 1; // combine previous and current sessions\r
2141   appData.secondAccumulateTC = 1;\r
2142   appData.firstNPS  = -1; // [HGM] nps: use wall-clock time\r
2143   appData.secondNPS = -1;\r
2144   appData.engineComments = 1;\r
2145   appData.smpCores = 1; // [HGM] SMP: max nr of cores\r
2146   appData.egtFormats = "";\r
2147 \r
2148 #ifdef ZIPPY\r
2149   appData.zippyTalk = ZIPPY_TALK;\r
2150   appData.zippyPlay = ZIPPY_PLAY;\r
2151   appData.zippyLines = ZIPPY_LINES;\r
2152   appData.zippyPinhead = ZIPPY_PINHEAD;\r
2153   appData.zippyPassword = ZIPPY_PASSWORD;\r
2154   appData.zippyPassword2 = ZIPPY_PASSWORD2;\r
2155   appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;\r
2156   appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;\r
2157   appData.zippyUseI = ZIPPY_USE_I;\r
2158   appData.zippyBughouse = ZIPPY_BUGHOUSE;\r
2159   appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;\r
2160   appData.zippyGameEnd = ZIPPY_GAME_END;\r
2161   appData.zippyGameStart = ZIPPY_GAME_START;\r
2162   appData.zippyAdjourn = ZIPPY_ADJOURN;\r
2163   appData.zippyAbort = ZIPPY_ABORT;\r
2164   appData.zippyVariants = ZIPPY_VARIANTS;\r
2165   appData.zippyMaxGames = ZIPPY_MAX_GAMES;\r
2166   appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;\r
2167 #endif\r
2168 \r
2169   /* Point font array elements to structures and\r
2170      parse default font names */\r
2171   for (i=0; i<NUM_FONTS; i++) {\r
2172     for (j=0; j<NUM_SIZES; j++) {\r
2173       font[j][i] = &fontRec[j][i];\r
2174       ParseFontName(font[j][i]->def, &font[j][i]->mfp);\r
2175     }\r
2176   }\r
2177   \r
2178   /* Parse default settings file if any */\r
2179   if (ParseSettingsFile(settingsFileName, buf)) {\r
2180     settingsFileName = strdup(buf);\r
2181   }\r
2182 \r
2183   /* Parse command line */\r
2184   ParseArgs(StringGet, &lpCmdLine);\r
2185 \r
2186   /* [HGM] make sure board size is acceptable */\r
2187   if(appData.NrFiles > BOARD_SIZE ||\r
2188      appData.NrRanks > BOARD_SIZE   )\r
2189       DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);\r
2190 \r
2191   /* [HGM] After parsing the options from the .ini file, and overruling them\r
2192    * with options from the command line, we now make an even higher priority\r
2193    * overrule by WB options attached to the engine command line. This so that\r
2194    * tournament managers can use WB options (such as /timeOdds) that follow\r
2195    * the engines.\r
2196    */\r
2197   if(appData.firstChessProgram != NULL) {\r
2198       char *p = StrStr(appData.firstChessProgram, "WBopt");\r
2199       static char *f = "first";\r
2200       char buf[MSG_SIZ], *q = buf;\r
2201       if(p != NULL) { // engine command line contains WinBoard options\r
2202           sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"\r
2203           ParseArgs(StringGet, &q);\r
2204           p[-1] = 0; // cut them offengine command line\r
2205       }\r
2206   }\r
2207   // now do same for second chess program\r
2208   if(appData.secondChessProgram != NULL) {\r
2209       char *p = StrStr(appData.secondChessProgram, "WBopt");\r
2210       static char *s = "second";\r
2211       char buf[MSG_SIZ], *q = buf;\r
2212       if(p != NULL) { // engine command line contains WinBoard options\r
2213           sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"\r
2214           ParseArgs(StringGet, &q);\r
2215           p[-1] = 0; // cut them offengine command line\r
2216       }\r
2217   }\r
2218 \r
2219 \r
2220   /* Propagate options that affect others */\r
2221   if (appData.matchMode || appData.matchGames) chessProgram = TRUE;\r
2222   if (appData.icsActive || appData.noChessProgram) {\r
2223      chessProgram = FALSE;  /* not local chess program mode */\r
2224   }\r
2225 \r
2226   /* Open startup dialog if needed */\r
2227   if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||\r
2228       (appData.icsActive && *appData.icsHost == NULLCHAR) ||\r
2229       (chessProgram && (*appData.firstChessProgram == NULLCHAR ||\r
2230                         *appData.secondChessProgram == NULLCHAR))) {\r
2231     FARPROC lpProc;\r
2232     \r
2233     lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);\r
2234     DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);\r
2235     FreeProcInstance(lpProc);\r
2236   }\r
2237 \r
2238   /* Make sure save files land in the right (?) directory */\r
2239   if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {\r
2240     appData.saveGameFile = strdup(buf);\r
2241   }\r
2242   if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {\r
2243     appData.savePositionFile = strdup(buf);\r
2244   }\r
2245 \r
2246   /* Finish initialization for fonts and sounds */\r
2247   for (i=0; i<NUM_FONTS; i++) {\r
2248     for (j=0; j<NUM_SIZES; j++) {\r
2249       CreateFontInMF(font[j][i]);\r
2250     }\r
2251   }\r
2252   /* xboard, and older WinBoards, controlled the move sound with the\r
2253      appData.ringBellAfterMoves option.  In the current WinBoard, we\r
2254      always turn the option on (so that the backend will call us),\r
2255      then let the user turn the sound off by setting it to silence if\r
2256      desired.  To accommodate old winboard.ini files saved by old\r
2257      versions of WinBoard, we also turn off the sound if the option\r
2258      was initially set to false. */\r
2259   if (!appData.ringBellAfterMoves) {\r
2260     sounds[(int)SoundMove].name = strdup("");\r
2261     appData.ringBellAfterMoves = TRUE;\r
2262   }\r
2263   GetCurrentDirectory(MSG_SIZ, currDir);\r
2264   SetCurrentDirectory(installDir);\r
2265   LoadAllSounds();\r
2266   SetCurrentDirectory(currDir);\r
2267 \r
2268   p = icsTextMenuString;\r
2269   if (p[0] == '@') {\r
2270     FILE* f = fopen(p + 1, "r");\r
2271     if (f == NULL) {\r
2272       DisplayFatalError(p + 1, errno, 2);\r
2273       return;\r
2274     }\r
2275     i = fread(buf, 1, sizeof(buf)-1, f);\r
2276     fclose(f);\r
2277     buf[i] = NULLCHAR;\r
2278     p = buf;\r
2279   }\r
2280   ParseIcsTextMenu(strdup(p));\r
2281 }\r
2282 \r
2283 \r
2284 VOID\r
2285 InitMenuChecks()\r
2286 {\r
2287   HMENU hmenu = GetMenu(hwndMain);\r
2288 \r
2289   (void) EnableMenuItem(hmenu, IDM_CommPort,\r
2290                         MF_BYCOMMAND|((appData.icsActive &&\r
2291                                        *appData.icsCommPort != NULLCHAR) ?\r
2292                                       MF_ENABLED : MF_GRAYED));\r
2293   (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,\r
2294                        MF_BYCOMMAND|(saveSettingsOnExit ?\r
2295                                      MF_CHECKED : MF_UNCHECKED));\r
2296 }\r
2297 \r
2298 \r
2299 VOID\r
2300 SaveSettings(char* name)\r
2301 {\r
2302   FILE *f;\r
2303   ArgDescriptor *ad;\r
2304   WINDOWPLACEMENT wp;\r
2305   char dir[MSG_SIZ];\r
2306 \r
2307   if (!hwndMain) return;\r
2308 \r
2309   GetCurrentDirectory(MSG_SIZ, dir);\r
2310   SetCurrentDirectory(installDir);\r
2311   f = fopen(name, "w");\r
2312   SetCurrentDirectory(dir);\r
2313   if (f == NULL) {\r
2314     DisplayError(name, errno);\r
2315     return;\r
2316   }\r
2317   fprintf(f, ";\n");\r
2318   fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);\r
2319   fprintf(f, ";\n");\r
2320   fprintf(f, "; You can edit the values of options that are already set in this file,\n");\r
2321   fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");\r
2322   fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");\r
2323   fprintf(f, ";\n");\r
2324 \r
2325   wp.length = sizeof(WINDOWPLACEMENT);\r
2326   GetWindowPlacement(hwndMain, &wp);\r
2327   boardX = wp.rcNormalPosition.left;\r
2328   boardY = wp.rcNormalPosition.top;\r
2329 \r
2330   if (hwndConsole) {\r
2331     GetWindowPlacement(hwndConsole, &wp);\r
2332     wpConsole.x = wp.rcNormalPosition.left;\r
2333     wpConsole.y = wp.rcNormalPosition.top;\r
2334     wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2335     wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2336   }\r
2337 \r
2338   if (analysisDialog) {\r
2339     GetWindowPlacement(analysisDialog, &wp);\r
2340     analysisX = wp.rcNormalPosition.left;\r
2341     analysisY = wp.rcNormalPosition.top;\r
2342     analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2343     analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2344   }\r
2345 \r
2346   if (commentDialog) {\r
2347     GetWindowPlacement(commentDialog, &wp);\r
2348     commentX = wp.rcNormalPosition.left;\r
2349     commentY = wp.rcNormalPosition.top;\r
2350     commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2351     commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2352   }\r
2353 \r
2354   if (editTagsDialog) {\r
2355     GetWindowPlacement(editTagsDialog, &wp);\r
2356     editTagsX = wp.rcNormalPosition.left;\r
2357     editTagsY = wp.rcNormalPosition.top;\r
2358     editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2359     editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2360   }\r
2361 \r
2362   if (gameListDialog) {\r
2363     GetWindowPlacement(gameListDialog, &wp);\r
2364     wpGameList.x = wp.rcNormalPosition.left;\r
2365     wpGameList.y = wp.rcNormalPosition.top;\r
2366     wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2367     wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2368   }\r
2369 \r
2370   /* [AS] Move history */\r
2371   wpMoveHistory.visible = MoveHistoryIsUp();\r
2372   \r
2373   if( moveHistoryDialog ) {\r
2374     GetWindowPlacement(moveHistoryDialog, &wp);\r
2375     wpMoveHistory.x = wp.rcNormalPosition.left;\r
2376     wpMoveHistory.y = wp.rcNormalPosition.top;\r
2377     wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2378     wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2379   }\r
2380 \r
2381   /* [AS] Eval graph */\r
2382   wpEvalGraph.visible = EvalGraphIsUp();\r
2383 \r
2384   if( evalGraphDialog ) {\r
2385     GetWindowPlacement(evalGraphDialog, &wp);\r
2386     wpEvalGraph.x = wp.rcNormalPosition.left;\r
2387     wpEvalGraph.y = wp.rcNormalPosition.top;\r
2388     wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2389     wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2390   }\r
2391 \r
2392   /* [AS] Engine output */\r
2393   wpEngineOutput.visible = EngineOutputIsUp();\r
2394 \r
2395   if( engineOutputDialog ) {\r
2396     GetWindowPlacement(engineOutputDialog, &wp);\r
2397     wpEngineOutput.x = wp.rcNormalPosition.left;\r
2398     wpEngineOutput.y = wp.rcNormalPosition.top;\r
2399     wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2400     wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2401   }\r
2402 \r
2403   for (ad = argDescriptors; ad->argName != NULL; ad++) {\r
2404     if (!ad->save) continue;\r
2405     switch (ad->argType) {\r
2406     case ArgString:\r
2407       {\r
2408         char *p = *(char **)ad->argLoc;\r
2409         if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {\r
2410           /* Quote multiline values or \-containing values\r
2411              with { } if possible */\r
2412           fprintf(f, "/%s={%s}\n", ad->argName, p);\r
2413         } else {\r
2414           /* Else quote with " " */\r
2415           fprintf(f, "/%s=\"", ad->argName);\r
2416           while (*p) {\r
2417             if (*p == '\n') fprintf(f, "\n");\r
2418             else if (*p == '\r') fprintf(f, "\\r");\r
2419             else if (*p == '\t') fprintf(f, "\\t");\r
2420             else if (*p == '\b') fprintf(f, "\\b");\r
2421             else if (*p == '\f') fprintf(f, "\\f");\r
2422             else if (*p < ' ') fprintf(f, "\\%03o", *p);\r
2423             else if (*p == '\"') fprintf(f, "\\\"");\r
2424             else if (*p == '\\') fprintf(f, "\\\\");\r
2425             else putc(*p, f);\r
2426             p++;\r
2427           }\r
2428           fprintf(f, "\"\n");\r
2429         }\r
2430       }\r
2431       break;\r
2432     case ArgInt:\r
2433     case ArgZ:\r
2434       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);\r
2435       break;\r
2436     case ArgX:\r
2437       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value\r
2438       break;\r
2439     case ArgY:\r
2440       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);\r
2441       break;\r
2442     case ArgFloat:\r
2443       fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);\r
2444       break;\r
2445     case ArgBoolean:\r
2446       fprintf(f, "/%s=%s\n", ad->argName, \r
2447         (*(Boolean *)ad->argLoc) ? "true" : "false");\r
2448       break;\r
2449     case ArgTrue:\r
2450       if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
2451       break;\r
2452     case ArgFalse:\r
2453       if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
2454       break;\r
2455     case ArgColor:\r
2456       {\r
2457         COLORREF color = *(COLORREF *)ad->argLoc;\r
2458         fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName, \r
2459           color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
2460       }\r
2461       break;\r
2462     case ArgAttribs:\r
2463       {\r
2464         MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];\r
2465         fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,\r
2466           (ta->effects & CFE_BOLD) ? "b" : "",\r
2467           (ta->effects & CFE_ITALIC) ? "i" : "",\r
2468           (ta->effects & CFE_UNDERLINE) ? "u" : "",\r
2469           (ta->effects & CFE_STRIKEOUT) ? "s" : "",\r
2470           (ta->effects) ? " " : "",\r
2471           ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);\r
2472       }\r
2473       break;\r
2474     case ArgFilename:\r
2475       if (strchr(*(char **)ad->argLoc, '\"')) {\r
2476         fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);\r
2477       } else {\r
2478         fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);\r
2479       }\r
2480       break;\r
2481     case ArgBoardSize:\r
2482       fprintf(f, "/%s=%s\n", ad->argName,\r
2483               sizeInfo[*(BoardSize *)ad->argLoc].name);\r
2484       break;\r
2485     case ArgFont:\r
2486       {\r
2487         int bs;\r
2488         for (bs=0; bs<NUM_SIZES; bs++) {\r
2489           MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;\r
2490           fprintf(f, "/size=%s ", sizeInfo[bs].name);\r
2491           fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",\r
2492             ad->argName, mfp->faceName, mfp->pointSize,\r
2493             mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",\r
2494             mfp->bold ? "b" : "",\r
2495             mfp->italic ? "i" : "",\r
2496             mfp->underline ? "u" : "",\r
2497             mfp->strikeout ? "s" : "");\r
2498         }\r
2499       }\r
2500       break;\r
2501     case ArgCommSettings:\r
2502       PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);\r
2503     case ArgNone:\r
2504     case ArgSettingsFilename: ;\r
2505     }\r
2506   }\r
2507   fclose(f);\r
2508 }\r
2509 \r
2510 \r
2511 \r
2512 /*---------------------------------------------------------------------------*\\r
2513  *\r
2514  * GDI board drawing routines\r
2515  *\r
2516 \*---------------------------------------------------------------------------*/\r
2517 \r
2518 /* [AS] Draw square using background texture */\r
2519 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )\r
2520 {\r
2521     XFORM   x;\r
2522 \r
2523     if( mode == 0 ) {\r
2524         return; /* Should never happen! */\r
2525     }\r
2526 \r
2527     SetGraphicsMode( dst, GM_ADVANCED );\r
2528 \r
2529     switch( mode ) {\r
2530     case 1:\r
2531         /* Identity */\r
2532         break;\r
2533     case 2:\r
2534         /* X reflection */\r
2535         x.eM11 = -1.0;\r
2536         x.eM12 = 0;\r
2537         x.eM21 = 0;\r
2538         x.eM22 = 1.0;\r
2539         x.eDx = (FLOAT) dw + dx - 1;\r
2540         x.eDy = 0;\r
2541         dx = 0;\r
2542         SetWorldTransform( dst, &x );\r
2543         break;\r
2544     case 3:\r
2545         /* Y reflection */\r
2546         x.eM11 = 1.0;\r
2547         x.eM12 = 0;\r
2548         x.eM21 = 0;\r
2549         x.eM22 = -1.0;\r
2550         x.eDx = 0;\r
2551         x.eDy = (FLOAT) dh + dy - 1;\r
2552         dy = 0;\r
2553         SetWorldTransform( dst, &x );\r
2554         break;\r
2555     case 4:\r
2556         /* X/Y flip */\r
2557         x.eM11 = 0;\r
2558         x.eM12 = 1.0;\r
2559         x.eM21 = 1.0;\r
2560         x.eM22 = 0;\r
2561         x.eDx = (FLOAT) dx;\r
2562         x.eDy = (FLOAT) dy;\r
2563         dx = 0;\r
2564         dy = 0;\r
2565         SetWorldTransform( dst, &x );\r
2566         break;\r
2567     }\r
2568 \r
2569     BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );\r
2570 \r
2571     x.eM11 = 1.0;\r
2572     x.eM12 = 0;\r
2573     x.eM21 = 0;\r
2574     x.eM22 = 1.0;\r
2575     x.eDx = 0;\r
2576     x.eDy = 0;\r
2577     SetWorldTransform( dst, &x );\r
2578 \r
2579     ModifyWorldTransform( dst, 0, MWT_IDENTITY );\r
2580 }\r
2581 \r
2582 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */\r
2583 enum {\r
2584     PM_WP = (int) WhitePawn, \r
2585     PM_WN = (int) WhiteKnight, \r
2586     PM_WB = (int) WhiteBishop, \r
2587     PM_WR = (int) WhiteRook, \r
2588     PM_WQ = (int) WhiteQueen, \r
2589     PM_WF = (int) WhiteFerz, \r
2590     PM_WW = (int) WhiteWazir, \r
2591     PM_WE = (int) WhiteAlfil, \r
2592     PM_WM = (int) WhiteMan, \r
2593     PM_WO = (int) WhiteCannon, \r
2594     PM_WU = (int) WhiteUnicorn, \r
2595     PM_WH = (int) WhiteNightrider, \r
2596     PM_WA = (int) WhiteAngel, \r
2597     PM_WC = (int) WhiteMarshall, \r
2598     PM_WAB = (int) WhiteCardinal, \r
2599     PM_WD = (int) WhiteDragon, \r
2600     PM_WL = (int) WhiteLance, \r
2601     PM_WS = (int) WhiteCobra, \r
2602     PM_WV = (int) WhiteFalcon, \r
2603     PM_WSG = (int) WhiteSilver, \r
2604     PM_WG = (int) WhiteGrasshopper, \r
2605     PM_WK = (int) WhiteKing,\r
2606     PM_BP = (int) BlackPawn, \r
2607     PM_BN = (int) BlackKnight, \r
2608     PM_BB = (int) BlackBishop, \r
2609     PM_BR = (int) BlackRook, \r
2610     PM_BQ = (int) BlackQueen, \r
2611     PM_BF = (int) BlackFerz, \r
2612     PM_BW = (int) BlackWazir, \r
2613     PM_BE = (int) BlackAlfil, \r
2614     PM_BM = (int) BlackMan,\r
2615     PM_BO = (int) BlackCannon, \r
2616     PM_BU = (int) BlackUnicorn, \r
2617     PM_BH = (int) BlackNightrider, \r
2618     PM_BA = (int) BlackAngel, \r
2619     PM_BC = (int) BlackMarshall, \r
2620     PM_BG = (int) BlackGrasshopper, \r
2621     PM_BAB = (int) BlackCardinal,\r
2622     PM_BD = (int) BlackDragon,\r
2623     PM_BL = (int) BlackLance,\r
2624     PM_BS = (int) BlackCobra,\r
2625     PM_BV = (int) BlackFalcon,\r
2626     PM_BSG = (int) BlackSilver,\r
2627     PM_BK = (int) BlackKing\r
2628 };\r
2629 \r
2630 static HFONT hPieceFont = NULL;\r
2631 static HBITMAP hPieceMask[(int) EmptySquare];\r
2632 static HBITMAP hPieceFace[(int) EmptySquare];\r
2633 static int fontBitmapSquareSize = 0;\r
2634 static char pieceToFontChar[(int) EmptySquare] =\r
2635                               { 'p', 'n', 'b', 'r', 'q', \r
2636                       'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',\r
2637                       'k', 'o', 'm', 'v', 't', 'w', \r
2638                       'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',\r
2639                                                               'l' };\r
2640 \r
2641 extern BOOL SetCharTable( char *table, const char * map );\r
2642 /* [HGM] moved to backend.c */\r
2643 \r
2644 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )\r
2645 {\r
2646     HBRUSH hbrush;\r
2647     BYTE r1 = GetRValue( color );\r
2648     BYTE g1 = GetGValue( color );\r
2649     BYTE b1 = GetBValue( color );\r
2650     BYTE r2 = r1 / 2;\r
2651     BYTE g2 = g1 / 2;\r
2652     BYTE b2 = b1 / 2;\r
2653     RECT rc;\r
2654 \r
2655     /* Create a uniform background first */\r
2656     hbrush = CreateSolidBrush( color );\r
2657     SetRect( &rc, 0, 0, squareSize, squareSize );\r
2658     FillRect( hdc, &rc, hbrush );\r
2659     DeleteObject( hbrush );\r
2660     \r
2661     if( mode == 1 ) {\r
2662         /* Vertical gradient, good for pawn, knight and rook, less for queen and king */\r
2663         int steps = squareSize / 2;\r
2664         int i;\r
2665 \r
2666         for( i=0; i<steps; i++ ) {\r
2667             BYTE r = r1 - (r1-r2) * i / steps;\r
2668             BYTE g = g1 - (g1-g2) * i / steps;\r
2669             BYTE b = b1 - (b1-b2) * i / steps;\r
2670 \r
2671             hbrush = CreateSolidBrush( RGB(r,g,b) );\r
2672             SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );\r
2673             FillRect( hdc, &rc, hbrush );\r
2674             DeleteObject(hbrush);\r
2675         }\r
2676     }\r
2677     else if( mode == 2 ) {\r
2678         /* Diagonal gradient, good more or less for every piece */\r
2679         POINT triangle[3];\r
2680         HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );\r
2681         HBRUSH hbrush_old;\r
2682         int steps = squareSize;\r
2683         int i;\r
2684 \r
2685         triangle[0].x = squareSize - steps;\r
2686         triangle[0].y = squareSize;\r
2687         triangle[1].x = squareSize;\r
2688         triangle[1].y = squareSize;\r
2689         triangle[2].x = squareSize;\r
2690         triangle[2].y = squareSize - steps;\r
2691 \r
2692         for( i=0; i<steps; i++ ) {\r
2693             BYTE r = r1 - (r1-r2) * i / steps;\r
2694             BYTE g = g1 - (g1-g2) * i / steps;\r
2695             BYTE b = b1 - (b1-b2) * i / steps;\r
2696 \r
2697             hbrush = CreateSolidBrush( RGB(r,g,b) );\r
2698             hbrush_old = SelectObject( hdc, hbrush );\r
2699             Polygon( hdc, triangle, 3 );\r
2700             SelectObject( hdc, hbrush_old );\r
2701             DeleteObject(hbrush);\r
2702             triangle[0].x++;\r
2703             triangle[2].y++;\r
2704         }\r
2705 \r
2706         SelectObject( hdc, hpen );\r
2707     }\r
2708 }\r
2709 \r
2710 /*\r
2711     [AS] The method I use to create the bitmaps it a bit tricky, but it\r
2712     seems to work ok. The main problem here is to find the "inside" of a chess\r
2713     piece: follow the steps as explained below.\r
2714 */\r
2715 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )\r
2716 {\r
2717     HBITMAP hbm;\r
2718     HBITMAP hbm_old;\r
2719     COLORREF chroma = RGB(0xFF,0x00,0xFF);\r
2720     RECT rc;\r
2721     SIZE sz;\r
2722     POINT pt;\r
2723     int backColor = whitePieceColor; \r
2724     int foreColor = blackPieceColor;\r
2725     \r
2726     if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {\r
2727         backColor = appData.fontBackColorWhite;\r
2728         foreColor = appData.fontForeColorWhite;\r
2729     }\r
2730     else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {\r
2731         backColor = appData.fontBackColorBlack;\r
2732         foreColor = appData.fontForeColorBlack;\r
2733     }\r
2734 \r
2735     /* Mask */\r
2736     hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2737 \r
2738     hbm_old = SelectObject( hdc, hbm );\r
2739 \r
2740     rc.left = 0;\r
2741     rc.top = 0;\r
2742     rc.right = squareSize;\r
2743     rc.bottom = squareSize;\r
2744 \r
2745     /* Step 1: background is now black */\r
2746     FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );\r
2747 \r
2748     GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );\r
2749 \r
2750     pt.x = (squareSize - sz.cx) / 2;\r
2751     pt.y = (squareSize - sz.cy) / 2;\r
2752 \r
2753     SetBkMode( hdc, TRANSPARENT );\r
2754     SetTextColor( hdc, chroma );\r
2755     /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */\r
2756     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2757 \r
2758     SelectObject( hdc, GetStockObject(WHITE_BRUSH) );\r
2759     /* Step 3: the area outside the piece is filled with white */\r
2760 //    FloodFill( hdc, 0, 0, chroma );\r
2761     ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );\r
2762     ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big\r
2763     ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );\r
2764     ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );\r
2765     SelectObject( hdc, GetStockObject(BLACK_BRUSH) );\r
2766     /* \r
2767         Step 4: this is the tricky part, the area inside the piece is filled with black,\r
2768         but if the start point is not inside the piece we're lost!\r
2769         There should be a better way to do this... if we could create a region or path\r
2770         from the fill operation we would be fine for example.\r
2771     */\r
2772 //    FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );\r
2773     ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );\r
2774 \r
2775     {   /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */\r
2776         HDC dc2 = CreateCompatibleDC( hdc_window );\r
2777         HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2778 \r
2779         SelectObject( dc2, bm2 );\r
2780         BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy\r
2781         BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2782         BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2783         BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2784         BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2785 \r
2786         DeleteDC( dc2 );\r
2787         DeleteObject( bm2 );\r
2788     }\r
2789 \r
2790     SetTextColor( hdc, 0 );\r
2791     /* \r
2792         Step 5: some fonts have "disconnected" areas that are skipped by the fill:\r
2793         draw the piece again in black for safety.\r
2794     */\r
2795     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2796 \r
2797     SelectObject( hdc, hbm_old );\r
2798 \r
2799     if( hPieceMask[index] != NULL ) {\r
2800         DeleteObject( hPieceMask[index] );\r
2801     }\r
2802 \r
2803     hPieceMask[index] = hbm;\r
2804 \r
2805     /* Face */\r
2806     hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2807 \r
2808     SelectObject( hdc, hbm );\r
2809 \r
2810     {\r
2811         HDC dc1 = CreateCompatibleDC( hdc_window );\r
2812         HDC dc2 = CreateCompatibleDC( hdc_window );\r
2813         HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2814 \r
2815         SelectObject( dc1, hPieceMask[index] );\r
2816         SelectObject( dc2, bm2 );\r
2817         FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );\r
2818         BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );\r
2819         \r
2820         /* \r
2821             Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves\r
2822             the piece background and deletes (makes transparent) the rest.\r
2823             Thanks to that mask, we are free to paint the background with the greates\r
2824             freedom, as we'll be able to mask off the unwanted parts when finished.\r
2825             We use this, to make gradients and give the pieces a "roundish" look.\r
2826         */\r
2827         SetPieceBackground( hdc, backColor, 2 );\r
2828         BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );\r
2829 \r
2830         DeleteDC( dc2 );\r
2831         DeleteDC( dc1 );\r
2832         DeleteObject( bm2 );\r
2833     }\r
2834 \r
2835     SetTextColor( hdc, foreColor );\r
2836     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2837 \r
2838     SelectObject( hdc, hbm_old );\r
2839 \r
2840     if( hPieceFace[index] != NULL ) {\r
2841         DeleteObject( hPieceFace[index] );\r
2842     }\r
2843 \r
2844     hPieceFace[index] = hbm;\r
2845 }\r
2846 \r
2847 static int TranslatePieceToFontPiece( int piece )\r
2848 {\r
2849     switch( piece ) {\r
2850     case BlackPawn:\r
2851         return PM_BP;\r
2852     case BlackKnight:\r
2853         return PM_BN;\r
2854     case BlackBishop:\r
2855         return PM_BB;\r
2856     case BlackRook:\r
2857         return PM_BR;\r
2858     case BlackQueen:\r
2859         return PM_BQ;\r
2860     case BlackKing:\r
2861         return PM_BK;\r
2862     case WhitePawn:\r
2863         return PM_WP;\r
2864     case WhiteKnight:\r
2865         return PM_WN;\r
2866     case WhiteBishop:\r
2867         return PM_WB;\r
2868     case WhiteRook:\r
2869         return PM_WR;\r
2870     case WhiteQueen:\r
2871         return PM_WQ;\r
2872     case WhiteKing:\r
2873         return PM_WK;\r
2874 \r
2875     case BlackAngel:\r
2876         return PM_BA;\r
2877     case BlackMarshall:\r
2878         return PM_BC;\r
2879     case BlackFerz:\r
2880         return PM_BF;\r
2881     case BlackNightrider:\r
2882         return PM_BH;\r
2883     case BlackAlfil:\r
2884         return PM_BE;\r
2885     case BlackWazir:\r
2886         return PM_BW;\r
2887     case BlackUnicorn:\r
2888         return PM_BU;\r
2889     case BlackCannon:\r
2890         return PM_BO;\r
2891     case BlackGrasshopper:\r
2892         return PM_BG;\r
2893     case BlackMan:\r
2894         return PM_BM;\r
2895     case BlackSilver:\r
2896         return PM_BSG;\r
2897     case BlackLance:\r
2898         return PM_BL;\r
2899     case BlackFalcon:\r
2900         return PM_BV;\r
2901     case BlackCobra:\r
2902         return PM_BS;\r
2903     case BlackCardinal:\r
2904         return PM_BAB;\r
2905     case BlackDragon:\r
2906         return PM_BD;\r
2907 \r
2908     case WhiteAngel:\r
2909         return PM_WA;\r
2910     case WhiteMarshall:\r
2911         return PM_WC;\r
2912     case WhiteFerz:\r
2913         return PM_WF;\r
2914     case WhiteNightrider:\r
2915         return PM_WH;\r
2916     case WhiteAlfil:\r
2917         return PM_WE;\r
2918     case WhiteWazir:\r
2919         return PM_WW;\r
2920     case WhiteUnicorn:\r
2921         return PM_WU;\r
2922     case WhiteCannon:\r
2923         return PM_WO;\r
2924     case WhiteGrasshopper:\r
2925         return PM_WG;\r
2926     case WhiteMan:\r
2927         return PM_WM;\r
2928     case WhiteSilver:\r
2929         return PM_WSG;\r
2930     case WhiteLance:\r
2931         return PM_WL;\r
2932     case WhiteFalcon:\r
2933         return PM_WV;\r
2934     case WhiteCobra:\r
2935         return PM_WS;\r
2936     case WhiteCardinal:\r
2937         return PM_WAB;\r
2938     case WhiteDragon:\r
2939         return PM_WD;\r
2940     }\r
2941 \r
2942     return 0;\r
2943 }\r
2944 \r
2945 void CreatePiecesFromFont()\r
2946 {\r
2947     LOGFONT lf;\r
2948     HDC hdc_window = NULL;\r
2949     HDC hdc = NULL;\r
2950     HFONT hfont_old;\r
2951     int fontHeight;\r
2952     int i;\r
2953 \r
2954     if( fontBitmapSquareSize < 0 ) {\r
2955         /* Something went seriously wrong in the past: do not try to recreate fonts! */\r
2956         return;\r
2957     }\r
2958 \r
2959     if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {\r
2960         fontBitmapSquareSize = -1;\r
2961         return;\r
2962     }\r
2963 \r
2964     if( fontBitmapSquareSize != squareSize ) {\r
2965         hdc_window = GetDC( hwndMain );\r
2966         hdc = CreateCompatibleDC( hdc_window );\r
2967 \r
2968         if( hPieceFont != NULL ) {\r
2969             DeleteObject( hPieceFont );\r
2970         }\r
2971         else {\r
2972             for( i=0; i<=(int)BlackKing; i++ ) {\r
2973                 hPieceMask[i] = NULL;\r
2974                 hPieceFace[i] = NULL;\r
2975             }\r
2976         }\r
2977 \r
2978         fontHeight = 75;\r
2979 \r
2980         if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {\r
2981             fontHeight = appData.fontPieceSize;\r
2982         }\r
2983 \r
2984         fontHeight = (fontHeight * squareSize) / 100;\r
2985 \r
2986         lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );\r
2987         lf.lfWidth = 0;\r
2988         lf.lfEscapement = 0;\r
2989         lf.lfOrientation = 0;\r
2990         lf.lfWeight = FW_NORMAL;\r
2991         lf.lfItalic = 0;\r
2992         lf.lfUnderline = 0;\r
2993         lf.lfStrikeOut = 0;\r
2994         lf.lfCharSet = DEFAULT_CHARSET;\r
2995         lf.lfOutPrecision = OUT_DEFAULT_PRECIS;\r
2996         lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
2997         lf.lfQuality = PROOF_QUALITY;\r
2998         lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;\r
2999         strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );\r
3000         lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';\r
3001 \r
3002         hPieceFont = CreateFontIndirect( &lf );\r
3003 \r
3004         if( hPieceFont == NULL ) {\r
3005             fontBitmapSquareSize = -2;\r
3006         }\r
3007         else {\r
3008             /* Setup font-to-piece character table */\r
3009             if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {\r
3010                 /* No (or wrong) global settings, try to detect the font */\r
3011                 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {\r
3012                     /* Alpha */\r
3013                     SetCharTable(pieceToFontChar, "phbrqkojntwl");\r
3014                 }\r
3015                 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {\r
3016                     /* DiagramTT* family */\r
3017                     SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");\r
3018                 }\r
3019                 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {\r
3020                     /* Fairy symbols */\r
3021                      SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");\r
3022                 }\r
3023                 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {\r
3024                     /* Good Companion (Some characters get warped as literal :-( */\r
3025                     char s[] = "1cmWG0ñueOS¯®oYI23wgQU";\r
3026                     s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;\r
3027                     SetCharTable(pieceToFontChar, s);\r
3028                 }\r
3029                 else {\r
3030                     /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */\r
3031                     SetCharTable(pieceToFontChar, "pnbrqkomvtwl");\r
3032                 }\r
3033             }\r
3034 \r
3035             /* Create bitmaps */\r
3036             hfont_old = SelectObject( hdc, hPieceFont );\r
3037 #if 0\r
3038             CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );\r
3039             CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );\r
3040             CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );\r
3041             CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );\r
3042             CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );\r
3043             CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );\r
3044             CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );\r
3045             CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );\r
3046             CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );\r
3047             CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );\r
3048             CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );\r
3049             CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );\r
3050 \r
3051             CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );\r
3052             CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );\r
3053             CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );\r
3054             CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );\r
3055             CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );\r
3056             CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );\r
3057             CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );\r
3058             CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );\r
3059             CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );\r
3060             CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );\r
3061             CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );\r
3062             CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );\r
3063             CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );\r
3064             CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );\r
3065             CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );\r
3066             CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );\r
3067             CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );\r
3068             CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );\r
3069             CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );\r
3070             CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );\r
3071             CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );\r
3072             CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );\r
3073             CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );\r
3074             CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );\r
3075             CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );\r
3076             CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );\r
3077             CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );\r
3078             CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );\r
3079             CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );\r
3080             CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );\r
3081             CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );\r
3082             CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );\r
3083 #else\r
3084             for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */\r
3085                 if(PieceToChar((ChessSquare)i) != '.')     /* skip unused pieces         */\r
3086                     CreatePieceMaskFromFont( hdc_window, hdc, i );\r
3087 #endif\r
3088             SelectObject( hdc, hfont_old );\r
3089 \r
3090             fontBitmapSquareSize = squareSize;\r
3091         }\r
3092     }\r
3093 \r
3094     if( hdc != NULL ) {\r
3095         DeleteDC( hdc );\r
3096     }\r
3097 \r
3098     if( hdc_window != NULL ) {\r
3099         ReleaseDC( hwndMain, hdc_window );\r
3100     }\r
3101 }\r
3102 \r
3103 HBITMAP\r
3104 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)\r
3105 {\r
3106   char name[128];\r
3107 \r
3108   sprintf(name, "%s%d%s", piece, squareSize, suffix);\r
3109   if (gameInfo.event &&\r
3110       strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&\r
3111       strcmp(name, "k80s") == 0) {\r
3112     strcpy(name, "tim");\r
3113   }\r
3114   return LoadBitmap(hinst, name);\r
3115 }\r
3116 \r
3117 \r
3118 /* Insert a color into the program's logical palette\r
3119    structure.  This code assumes the given color is\r
3120    the result of the RGB or PALETTERGB macro, and it\r
3121    knows how those macros work (which is documented).\r
3122 */\r
3123 VOID\r
3124 InsertInPalette(COLORREF color)\r
3125 {\r
3126   LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);\r
3127 \r
3128   if (pLogPal->palNumEntries++ >= PALETTESIZE) {\r
3129     DisplayFatalError("Too many colors", 0, 1);\r
3130     pLogPal->palNumEntries--;\r
3131     return;\r
3132   }\r
3133 \r
3134   pe->peFlags = (char) 0;\r
3135   pe->peRed = (char) (0xFF & color);\r
3136   pe->peGreen = (char) (0xFF & (color >> 8));\r
3137   pe->peBlue = (char) (0xFF & (color >> 16));\r
3138   return;\r
3139 }\r
3140 \r
3141 \r
3142 VOID\r
3143 InitDrawingColors()\r
3144 {\r
3145   if (pLogPal == NULL) {\r
3146     /* Allocate enough memory for a logical palette with\r
3147      * PALETTESIZE entries and set the size and version fields\r
3148      * of the logical palette structure.\r
3149      */\r
3150     pLogPal = (NPLOGPALETTE)\r
3151       LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +\r
3152                               (sizeof(PALETTEENTRY) * (PALETTESIZE))));\r
3153     pLogPal->palVersion    = 0x300;\r
3154   }\r
3155   pLogPal->palNumEntries = 0;\r
3156 \r
3157   InsertInPalette(lightSquareColor);\r
3158   InsertInPalette(darkSquareColor);\r
3159   InsertInPalette(whitePieceColor);\r
3160   InsertInPalette(blackPieceColor);\r
3161   InsertInPalette(highlightSquareColor);\r
3162   InsertInPalette(premoveHighlightColor);\r
3163 \r
3164   /*  create a logical color palette according the information\r
3165    *  in the LOGPALETTE structure.\r
3166    */\r
3167   hPal = CreatePalette((LPLOGPALETTE) pLogPal);\r
3168 \r
3169   lightSquareBrush = CreateSolidBrush(lightSquareColor);\r
3170   blackSquareBrush = CreateSolidBrush(blackPieceColor);\r
3171   darkSquareBrush = CreateSolidBrush(darkSquareColor);\r
3172   whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
3173   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
3174   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
3175   explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic\r
3176   /* [AS] Force rendering of the font-based pieces */\r
3177   if( fontBitmapSquareSize > 0 ) {\r
3178     fontBitmapSquareSize = 0;\r
3179   }\r
3180 }\r
3181 \r
3182 \r
3183 int\r
3184 BoardWidth(int boardSize, int n)\r