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