cleanup: removed "#if 0" from source
[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 \r
1396   // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others\r
1397   { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed\r
1398   { "minY", ArgZ, (LPVOID) &minY, FALSE },\r
1399   { "winWidth",  ArgInt, (LPVOID) &winWidth,  TRUE }, // [HGM] placement: dummies to remember right & bottom\r
1400   { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, //       for attaching auxiliary windows to them\r
1401   { "x", ArgInt, (LPVOID) &boardX, TRUE },\r
1402   { "y", ArgInt, (LPVOID) &boardY, TRUE },\r
1403   { "icsX", ArgX,   (LPVOID) &wpConsole.x, TRUE },\r
1404   { "icsY", ArgY,   (LPVOID) &wpConsole.y, TRUE },\r
1405   { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },\r
1406   { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },\r
1407   { "analysisX", ArgX,   (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists\r
1408   { "analysisY", ArgY,   (LPVOID) &analysisY, FALSE }, //       provided for compatibility with old ini files\r
1409   { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },\r
1410   { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },\r
1411   { "commentX", ArgX,   (LPVOID) &commentX, TRUE },\r
1412   { "commentY", ArgY,   (LPVOID) &commentY, TRUE },\r
1413   { "commentW", ArgInt, (LPVOID) &commentW, TRUE },\r
1414   { "commentH", ArgInt, (LPVOID) &commentH, TRUE },\r
1415   { "tagsX", ArgX,   (LPVOID) &editTagsX, TRUE },\r
1416   { "tagsY", ArgY,   (LPVOID) &editTagsY, TRUE },\r
1417   { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },\r
1418   { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },\r
1419   { "gameListX", ArgX,   (LPVOID) &wpGameList.x, TRUE },\r
1420   { "gameListY", ArgY,   (LPVOID) &wpGameList.y, TRUE },\r
1421   { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },\r
1422   { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },\r
1423   /* [AS] Layout stuff */\r
1424   { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },\r
1425   { "moveHistoryX", ArgX,   (LPVOID) &wpMoveHistory.x, TRUE },\r
1426   { "moveHistoryY", ArgY,   (LPVOID) &wpMoveHistory.y, TRUE },\r
1427   { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },\r
1428   { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },\r
1429 \r
1430   { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },\r
1431   { "evalGraphX", ArgX,   (LPVOID) &wpEvalGraph.x, TRUE },\r
1432   { "evalGraphY", ArgY,   (LPVOID) &wpEvalGraph.y, TRUE },\r
1433   { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },\r
1434   { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },\r
1435 \r
1436   { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },\r
1437   { "engineOutputX", ArgX,   (LPVOID) &wpEngineOutput.x, TRUE },\r
1438   { "engineOutputY", ArgY,   (LPVOID) &wpEngineOutput.y, TRUE },\r
1439   { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },\r
1440   { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },\r
1441 \r
1442   { NULL, ArgNone, NULL, FALSE }\r
1443 };\r
1444 \r
1445 \r
1446 /* Kludge for indirection files on command line */\r
1447 char* lastIndirectionFilename;\r
1448 ArgDescriptor argDescriptorIndirection =\r
1449 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };\r
1450 \r
1451 \r
1452 VOID\r
1453 ExitArgError(char *msg, char *badArg)\r
1454 {\r
1455   char buf[MSG_SIZ];\r
1456 \r
1457   sprintf(buf, "%s %s", msg, badArg);\r
1458   DisplayFatalError(buf, 0, 2);\r
1459   exit(2);\r
1460 }\r
1461 \r
1462 /* Command line font name parser.  NULL name means do nothing.\r
1463    Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"\r
1464    For backward compatibility, syntax without the colon is also\r
1465    accepted, but font names with digits in them won't work in that case.\r
1466 */\r
1467 VOID\r
1468 ParseFontName(char *name, MyFontParams *mfp)\r
1469 {\r
1470   char *p, *q;\r
1471   if (name == NULL) return;\r
1472   p = name;\r
1473   q = strchr(p, ':');\r
1474   if (q) {\r
1475     if (q - p >= sizeof(mfp->faceName))\r
1476       ExitArgError("Font name too long:", name);\r
1477     memcpy(mfp->faceName, p, q - p);\r
1478     mfp->faceName[q - p] = NULLCHAR;\r
1479     p = q + 1;\r
1480   } else {\r
1481     q = mfp->faceName;\r
1482     while (*p && !isdigit(*p)) {\r
1483       *q++ = *p++;\r
1484       if (q - mfp->faceName >= sizeof(mfp->faceName))\r
1485         ExitArgError("Font name too long:", name);\r
1486     }\r
1487     while (q > mfp->faceName && q[-1] == ' ') q--;\r
1488     *q = NULLCHAR;\r
1489   }\r
1490   if (!*p) ExitArgError("Font point size missing:", name);\r
1491   mfp->pointSize = (float) atof(p);\r
1492   mfp->bold = (strchr(p, 'b') != NULL);\r
1493   mfp->italic = (strchr(p, 'i') != NULL);\r
1494   mfp->underline = (strchr(p, 'u') != NULL);\r
1495   mfp->strikeout = (strchr(p, 's') != NULL);\r
1496 }\r
1497 \r
1498 /* Color name parser.\r
1499    X version accepts X color names, but this one\r
1500    handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */\r
1501 COLORREF\r
1502 ParseColorName(char *name)\r
1503 {\r
1504   int red, green, blue, count;\r
1505   char buf[MSG_SIZ];\r
1506 \r
1507   count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);\r
1508   if (count != 3) {\r
1509     count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d", \r
1510       &red, &green, &blue);\r
1511   }\r
1512   if (count != 3) {\r
1513     sprintf(buf, "Can't parse color name %s", name);\r
1514     DisplayError(buf, 0);\r
1515     return RGB(0, 0, 0);\r
1516   }\r
1517   return PALETTERGB(red, green, blue);\r
1518 }\r
1519 \r
1520 \r
1521 void ParseAttribs(COLORREF *color, int *effects, char* argValue)\r
1522 {\r
1523   char *e = argValue;\r
1524   int eff = 0;\r
1525 \r
1526   while (*e) {\r
1527     if (*e == 'b')      eff |= CFE_BOLD;\r
1528     else if (*e == 'i') eff |= CFE_ITALIC;\r
1529     else if (*e == 'u') eff |= CFE_UNDERLINE;\r
1530     else if (*e == 's') eff |= CFE_STRIKEOUT;\r
1531     else if (*e == '#' || isdigit(*e)) break;\r
1532     e++;\r
1533   }\r
1534   *effects = eff;\r
1535   *color   = ParseColorName(e);\r
1536 }\r
1537 \r
1538 \r
1539 BoardSize\r
1540 ParseBoardSize(char *name)\r
1541 {\r
1542   BoardSize bs = SizeTiny;\r
1543   while (sizeInfo[bs].name != NULL) {\r
1544     if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;\r
1545     bs++;\r
1546   }\r
1547   ExitArgError("Unrecognized board size value", name);\r
1548   return bs; /* not reached */\r
1549 }\r
1550 \r
1551 \r
1552 char\r
1553 StringGet(void *getClosure)\r
1554 {\r
1555   char **p = (char **) getClosure;\r
1556   return *((*p)++);\r
1557 }\r
1558 \r
1559 char\r
1560 FileGet(void *getClosure)\r
1561 {\r
1562   int c;\r
1563   FILE* f = (FILE*) getClosure;\r
1564 \r
1565   c = getc(f);\r
1566   if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely\r
1567   if (c == EOF)\r
1568     return NULLCHAR;\r
1569   else\r
1570     return (char) c;\r
1571 }\r
1572 \r
1573 /* Parse settings file named "name". If file found, return the\r
1574    full name in fullname and return TRUE; else return FALSE */\r
1575 BOOLEAN\r
1576 ParseSettingsFile(char *name, char fullname[MSG_SIZ])\r
1577 {\r
1578   char *dummy;\r
1579   FILE *f;\r
1580   int ok; char buf[MSG_SIZ];\r
1581 \r
1582   ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);\r
1583   if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed\r
1584     sprintf(buf, "%s.ini", name);\r
1585     ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);\r
1586   }\r
1587   if (ok) {\r
1588     f = fopen(fullname, "r");\r
1589     if (f != NULL) {\r
1590       ParseArgs(FileGet, f);\r
1591       fclose(f);\r
1592       return TRUE;\r
1593     }\r
1594   }\r
1595   return FALSE;\r
1596 }\r
1597 \r
1598 VOID\r
1599 ParseArgs(GetFunc get, void *cl)\r
1600 {\r
1601   char argName[ARG_MAX];\r
1602   char argValue[ARG_MAX];\r
1603   ArgDescriptor *ad;\r
1604   char start;\r
1605   char *q;\r
1606   int i, octval;\r
1607   char ch;\r
1608   int posarg = 0;\r
1609 \r
1610   ch = get(cl);\r
1611   for (;;) {\r
1612     while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);\r
1613     if (ch == NULLCHAR) break;\r
1614     if (ch == ';') {\r
1615       /* Comment to end of line */\r
1616       ch = get(cl);\r
1617       while (ch != '\n' && ch != NULLCHAR) ch = get(cl);\r
1618       continue;\r
1619     } else if (ch == '/' || ch == '-') {\r
1620       /* Switch */\r
1621       q = argName;\r
1622       while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&\r
1623              ch != '\n' && ch != '\t') {\r
1624         *q++ = ch;\r
1625         ch = get(cl);\r
1626       }\r
1627       *q = NULLCHAR;\r
1628 \r
1629       for (ad = argDescriptors; ad->argName != NULL; ad++)\r
1630         if (strcmp(ad->argName, argName + 1) == 0) break;\r
1631 \r
1632       if (ad->argName == NULL)\r
1633         ExitArgError("Unrecognized argument", argName);\r
1634 \r
1635     } else if (ch == '@') {\r
1636       /* Indirection file */\r
1637       ad = &argDescriptorIndirection;\r
1638       ch = get(cl);\r
1639     } else {\r
1640       /* Positional argument */\r
1641       ad = &argDescriptors[posarg++];\r
1642       strcpy(argName, ad->argName);\r
1643     }\r
1644 \r
1645     if (ad->argType == ArgTrue) {\r
1646       *(Boolean *) ad->argLoc = TRUE;\r
1647       continue;\r
1648     }\r
1649     if (ad->argType == ArgFalse) {\r
1650       *(Boolean *) ad->argLoc = FALSE;\r
1651       continue;\r
1652     }\r
1653 \r
1654     while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);\r
1655     if (ch == NULLCHAR || ch == '\n') {\r
1656       ExitArgError("No value provided for argument", argName);\r
1657     }\r
1658     q = argValue;\r
1659     if (ch == '{') {\r
1660       // Quoting with { }.  No characters have to (or can) be escaped.\r
1661       // Thus the string cannot contain a '}' character.\r
1662       start = ch;\r
1663       ch = get(cl);\r
1664       while (start) {\r
1665         switch (ch) {\r
1666         case NULLCHAR:\r
1667           start = NULLCHAR;\r
1668           break;\r
1669           \r
1670         case '}':\r
1671           ch = get(cl);\r
1672           start = NULLCHAR;\r
1673           break;\r
1674 \r
1675         default:\r
1676           *q++ = ch;\r
1677           ch = get(cl);\r
1678           break;\r
1679         }\r
1680       }   \r
1681     } else if (ch == '\'' || ch == '"') {\r
1682       // Quoting with ' ' or " ", with \ as escape character.\r
1683       // Inconvenient for long strings that may contain Windows filenames.\r
1684       start = ch;\r
1685       ch = get(cl);\r
1686       while (start) {\r
1687         switch (ch) {\r
1688         case NULLCHAR:\r
1689           start = NULLCHAR;\r
1690           break;\r
1691 \r
1692         default:\r
1693         not_special:\r
1694           *q++ = ch;\r
1695           ch = get(cl);\r
1696           break;\r
1697 \r
1698         case '\'':\r
1699         case '\"':\r
1700           if (ch == start) {\r
1701             ch = get(cl);\r
1702             start = NULLCHAR;\r
1703             break;\r
1704           } else {\r
1705             goto not_special;\r
1706           }\r
1707 \r
1708         case '\\':\r
1709           if (ad->argType == ArgFilename\r
1710               || ad->argType == ArgSettingsFilename) {\r
1711               goto not_special;\r
1712           }\r
1713           ch = get(cl);\r
1714           switch (ch) {\r
1715           case NULLCHAR:\r
1716             ExitArgError("Incomplete \\ escape in value for", argName);\r
1717             break;\r
1718           case 'n':\r
1719             *q++ = '\n';\r
1720             ch = get(cl);\r
1721             break;\r
1722           case 'r':\r
1723             *q++ = '\r';\r
1724             ch = get(cl);\r
1725             break;\r
1726           case 't':\r
1727             *q++ = '\t';\r
1728             ch = get(cl);\r
1729             break;\r
1730           case 'b':\r
1731             *q++ = '\b';\r
1732             ch = get(cl);\r
1733             break;\r
1734           case 'f':\r
1735             *q++ = '\f';\r
1736             ch = get(cl);\r
1737             break;\r
1738           default:\r
1739             octval = 0;\r
1740             for (i = 0; i < 3; i++) {\r
1741               if (ch >= '0' && ch <= '7') {\r
1742                 octval = octval*8 + (ch - '0');\r
1743                 ch = get(cl);\r
1744               } else {\r
1745                 break;\r
1746               }\r
1747             }\r
1748             if (i > 0) {\r
1749               *q++ = (char) octval;\r
1750             } else {\r
1751               *q++ = ch;\r
1752               ch = get(cl);\r
1753             }\r
1754             break;\r
1755           }\r
1756           break;\r
1757         }\r
1758       }\r
1759     } else {\r
1760       while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {\r
1761         *q++ = ch;\r
1762         ch = get(cl);\r
1763       }\r
1764     }\r
1765     *q = NULLCHAR;\r
1766 \r
1767     switch (ad->argType) {\r
1768     case ArgInt:\r
1769       *(int *) ad->argLoc = atoi(argValue);\r
1770       break;\r
1771 \r
1772     case ArgX:\r
1773       *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute \r
1774       break;\r
1775 \r
1776     case ArgY:\r
1777       *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)\r
1778       break;\r
1779 \r
1780     case ArgZ:\r
1781       *(int *) ad->argLoc = atoi(argValue);\r
1782       EnsureOnScreen(&boardX, &boardY, minX, minY); \r
1783       break;\r
1784 \r
1785     case ArgFloat:\r
1786       *(float *) ad->argLoc = (float) atof(argValue);\r
1787       break;\r
1788 \r
1789     case ArgString:\r
1790     case ArgFilename:\r
1791       *(char **) ad->argLoc = strdup(argValue);\r
1792       break;\r
1793 \r
1794     case ArgSettingsFilename:\r
1795       {\r
1796         char fullname[MSG_SIZ];\r
1797         if (ParseSettingsFile(argValue, fullname)) {\r
1798           if (ad->argLoc != NULL) {\r
1799             *(char **) ad->argLoc = strdup(fullname);\r
1800           }\r
1801         } else {\r
1802           if (ad->argLoc != NULL) {\r
1803           } else {\r
1804             ExitArgError("Failed to open indirection file", argValue);\r
1805           }\r
1806         }\r
1807       }\r
1808       break;\r
1809 \r
1810     case ArgBoolean:\r
1811       switch (argValue[0]) {\r
1812       case 't':\r
1813       case 'T':\r
1814         *(Boolean *) ad->argLoc = TRUE;\r
1815         break;\r
1816       case 'f':\r
1817       case 'F':\r
1818         *(Boolean *) ad->argLoc = FALSE;\r
1819         break;\r
1820       default:\r
1821         ExitArgError("Unrecognized boolean argument value", argValue);\r
1822         break;\r
1823       }\r
1824       break;\r
1825 \r
1826     case ArgColor:\r
1827       *(COLORREF *)ad->argLoc = ParseColorName(argValue);\r
1828       break;\r
1829 \r
1830     case ArgAttribs: {\r
1831       ColorClass cc = (ColorClass)ad->argLoc;\r
1832       ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);\r
1833       }\r
1834       break;\r
1835       \r
1836     case ArgBoardSize:\r
1837       *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);\r
1838       break;\r
1839 \r
1840     case ArgFont:\r
1841       ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);\r
1842       break;\r
1843 \r
1844     case ArgCommSettings:\r
1845       ParseCommSettings(argValue, &dcb);\r
1846       break;\r
1847 \r
1848     case ArgNone:\r
1849       ExitArgError("Unrecognized argument", argValue);\r
1850       break;\r
1851     case ArgTrue:\r
1852     case ArgFalse: ;\r
1853     }\r
1854   }\r
1855 }\r
1856 \r
1857 VOID\r
1858 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)\r
1859 {\r
1860   HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);\r
1861   lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);\r
1862   DeleteDC(hdc);\r
1863   lf->lfWidth = 0;\r
1864   lf->lfEscapement = 0;\r
1865   lf->lfOrientation = 0;\r
1866   lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;\r
1867   lf->lfItalic = mfp->italic;\r
1868   lf->lfUnderline = mfp->underline;\r
1869   lf->lfStrikeOut = mfp->strikeout;\r
1870   lf->lfCharSet = DEFAULT_CHARSET;\r
1871   lf->lfOutPrecision = OUT_DEFAULT_PRECIS;\r
1872   lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
1873   lf->lfQuality = DEFAULT_QUALITY;\r
1874   lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;\r
1875   strcpy(lf->lfFaceName, mfp->faceName);\r
1876 }\r
1877 \r
1878 VOID\r
1879 CreateFontInMF(MyFont *mf)\r
1880 {\r
1881   LFfromMFP(&mf->lf, &mf->mfp);\r
1882   if (mf->hf) DeleteObject(mf->hf);\r
1883   mf->hf = CreateFontIndirect(&mf->lf);\r
1884 }\r
1885 \r
1886 VOID\r
1887 SetDefaultTextAttribs()\r
1888 {\r
1889   ColorClass cc;\r
1890   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1891     ParseAttribs(&textAttribs[cc].color, \r
1892                  &textAttribs[cc].effects, \r
1893                  defaultTextAttribs[cc]);\r
1894   }\r
1895 }\r
1896 \r
1897 VOID\r
1898 SetDefaultSounds()\r
1899 {\r
1900   ColorClass cc;\r
1901   SoundClass sc;\r
1902   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1903     textAttribs[cc].sound.name = strdup("");\r
1904     textAttribs[cc].sound.data = NULL;\r
1905   }\r
1906   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
1907     sounds[sc].name = strdup("");\r
1908     sounds[sc].data = NULL;\r
1909   }\r
1910   sounds[(int)SoundBell].name = strdup(SOUND_BELL);\r
1911 }\r
1912 \r
1913 VOID\r
1914 LoadAllSounds()\r
1915 {\r
1916   ColorClass cc;\r
1917   SoundClass sc;\r
1918   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1919     MyLoadSound(&textAttribs[cc].sound);\r
1920   }\r
1921   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
1922     MyLoadSound(&sounds[sc]);\r
1923   }\r
1924 }\r
1925 \r
1926 VOID\r
1927 InitAppData(LPSTR lpCmdLine)\r
1928 {\r
1929   int i, j;\r
1930   char buf[ARG_MAX], currDir[MSG_SIZ];\r
1931   char *dummy, *p;\r
1932 \r
1933   programName = szAppName;\r
1934 \r
1935   /* Initialize to defaults */\r
1936   lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);\r
1937   darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);\r
1938   whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);\r
1939   blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);\r
1940   highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);\r
1941   premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);\r
1942   consoleBackgroundColor = ParseColorName(COLOR_BKGD);\r
1943   SetDefaultTextAttribs();\r
1944   SetDefaultSounds();\r
1945   appData.movesPerSession = MOVES_PER_SESSION;\r
1946   appData.initString = INIT_STRING;\r
1947   appData.secondInitString = INIT_STRING;\r
1948   appData.firstComputerString = COMPUTER_STRING;\r
1949   appData.secondComputerString = COMPUTER_STRING;\r
1950   appData.firstChessProgram = FIRST_CHESS_PROGRAM;\r
1951   appData.secondChessProgram = SECOND_CHESS_PROGRAM;\r
1952   appData.firstPlaysBlack = FALSE;\r
1953   appData.noChessProgram = FALSE;\r
1954   chessProgram = FALSE;\r
1955   appData.firstHost = FIRST_HOST;\r
1956   appData.secondHost = SECOND_HOST;\r
1957   appData.firstDirectory = FIRST_DIRECTORY;\r
1958   appData.secondDirectory = SECOND_DIRECTORY;\r
1959   appData.bitmapDirectory = "";\r
1960   appData.remoteShell = REMOTE_SHELL;\r
1961   appData.remoteUser = "";\r
1962   appData.timeDelay = TIME_DELAY;\r
1963   appData.timeControl = TIME_CONTROL;\r
1964   appData.timeIncrement = TIME_INCREMENT;\r
1965   appData.icsActive = FALSE;\r
1966   appData.icsHost = "";\r
1967   appData.icsPort = ICS_PORT;\r
1968   appData.icsCommPort = ICS_COMM_PORT;\r
1969   appData.icsLogon = ICS_LOGON;\r
1970   appData.icsHelper = "";\r
1971   appData.useTelnet = FALSE;\r
1972   appData.telnetProgram = TELNET_PROGRAM;\r
1973   appData.gateway = "";\r
1974   appData.loadGameFile = "";\r
1975   appData.loadGameIndex = 0;\r
1976   appData.saveGameFile = "";\r
1977   appData.autoSaveGames = FALSE;\r
1978   appData.loadPositionFile = "";\r
1979   appData.loadPositionIndex = 1;\r
1980   appData.savePositionFile = "";\r
1981   appData.matchMode = FALSE;\r
1982   appData.matchGames = 0;\r
1983   appData.monoMode = FALSE;\r
1984   appData.debugMode = FALSE;\r
1985   appData.clockMode = TRUE;\r
1986   boardSize = (BoardSize) -1; /* determine by screen size */\r
1987   appData.Iconic = FALSE; /*unused*/\r
1988   appData.searchTime = "";\r
1989   appData.searchDepth = 0;\r
1990   appData.showCoords = FALSE;\r
1991   appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/\r
1992   appData.autoCallFlag = FALSE;\r
1993   appData.flipView = FALSE;\r
1994   appData.autoFlipView = TRUE;\r
1995   appData.cmailGameName = "";\r
1996   appData.alwaysPromoteToQueen = FALSE;\r
1997   appData.oldSaveStyle = FALSE;\r
1998   appData.quietPlay = FALSE;\r
1999   appData.showThinking = FALSE;\r
2000   appData.ponderNextMove = TRUE;\r
2001   appData.periodicUpdates = TRUE;\r
2002   appData.popupExitMessage = TRUE;\r
2003   appData.popupMoveErrors = FALSE;\r
2004   appData.autoObserve = FALSE;\r
2005   appData.autoComment = FALSE;\r
2006   appData.animate = TRUE;\r
2007   appData.animSpeed = 10;\r
2008   appData.animateDragging = TRUE;\r
2009   appData.highlightLastMove = TRUE;\r
2010   appData.getMoveList = TRUE;\r
2011   appData.testLegality = TRUE;\r
2012   appData.premove = TRUE;\r
2013   appData.premoveWhite = FALSE;\r
2014   appData.premoveWhiteText = "";\r
2015   appData.premoveBlack = FALSE;\r
2016   appData.premoveBlackText = "";\r
2017   appData.icsAlarm = TRUE;\r
2018   appData.icsAlarmTime = 5000;\r
2019   appData.autoRaiseBoard = TRUE;\r
2020   appData.localLineEditing = TRUE;\r
2021   appData.colorize = TRUE;\r
2022   appData.reuseFirst = TRUE;\r
2023   appData.reuseSecond = TRUE;\r
2024   appData.blindfold = FALSE;\r
2025   appData.icsEngineAnalyze = FALSE;\r
2026   memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +\r
2027   dcb.DCBlength = sizeof(DCB);\r
2028   dcb.BaudRate = 9600;\r
2029   dcb.fBinary = TRUE;\r
2030   dcb.fParity = FALSE;\r
2031   dcb.fOutxCtsFlow = FALSE;\r
2032   dcb.fOutxDsrFlow = FALSE;\r
2033   dcb.fDtrControl = DTR_CONTROL_ENABLE;\r
2034   dcb.fDsrSensitivity = FALSE;\r
2035   dcb.fTXContinueOnXoff = TRUE;\r
2036   dcb.fOutX = FALSE;\r
2037   dcb.fInX = FALSE;\r
2038   dcb.fNull = FALSE;\r
2039   dcb.fRtsControl = RTS_CONTROL_ENABLE;\r
2040   dcb.fAbortOnError = FALSE;\r
2041   dcb.ByteSize = 7;\r
2042   dcb.Parity = SPACEPARITY;\r
2043   dcb.StopBits = ONESTOPBIT;\r
2044   settingsFileName = SETTINGS_FILE;\r
2045   saveSettingsOnExit = TRUE;\r
2046   boardX = CW_USEDEFAULT;\r
2047   boardY = CW_USEDEFAULT;\r
2048   analysisX = CW_USEDEFAULT; \r
2049   analysisY = CW_USEDEFAULT; \r
2050   analysisW = CW_USEDEFAULT;\r
2051   analysisH = CW_USEDEFAULT;\r
2052   commentX = CW_USEDEFAULT; \r
2053   commentY = CW_USEDEFAULT; \r
2054   commentW = CW_USEDEFAULT;\r
2055   commentH = CW_USEDEFAULT;\r
2056   editTagsX = CW_USEDEFAULT; \r
2057   editTagsY = CW_USEDEFAULT; \r
2058   editTagsW = CW_USEDEFAULT;\r
2059   editTagsH = CW_USEDEFAULT;\r
2060   icsTextMenuString = ICS_TEXT_MENU_DEFAULT;\r
2061   icsNames = ICS_NAMES;\r
2062   firstChessProgramNames = FCP_NAMES;\r
2063   secondChessProgramNames = SCP_NAMES;\r
2064   appData.initialMode = "";\r
2065   appData.variant = "normal";\r
2066   appData.firstProtocolVersion = PROTOVER;\r
2067   appData.secondProtocolVersion = PROTOVER;\r
2068   appData.showButtonBar = TRUE;\r
2069 \r
2070    /* [AS] New properties (see comments in header file) */\r
2071   appData.firstScoreIsAbsolute = FALSE;\r
2072   appData.secondScoreIsAbsolute = FALSE;\r
2073   appData.saveExtendedInfoInPGN = FALSE;\r
2074   appData.hideThinkingFromHuman = FALSE;\r
2075   appData.liteBackTextureFile = "";\r
2076   appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
2077   appData.darkBackTextureFile = "";\r
2078   appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
2079   appData.renderPiecesWithFont = "";\r
2080   appData.fontToPieceTable = "";\r
2081   appData.fontBackColorWhite = 0;\r
2082   appData.fontForeColorWhite = 0;\r
2083   appData.fontBackColorBlack = 0;\r
2084   appData.fontForeColorBlack = 0;\r
2085   appData.fontPieceSize = 80;\r
2086   appData.overrideLineGap = 1;\r
2087   appData.adjudicateLossThreshold = 0;\r
2088   appData.delayBeforeQuit = 0;\r
2089   appData.delayAfterQuit = 0;\r
2090   appData.nameOfDebugFile = "winboard.debug";\r
2091   appData.pgnEventHeader = "Computer Chess Game";\r
2092   appData.defaultFrcPosition = -1;\r
2093   appData.gameListTags = GLT_DEFAULT_TAGS;\r
2094   appData.saveOutOfBookInfo = TRUE;\r
2095   appData.showEvalInMoveHistory = TRUE;\r
2096   appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );\r
2097   appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );\r
2098   appData.highlightMoveWithArrow = FALSE;\r
2099   appData.highlightArrowColor = ParseColorName( "#FFFF80" );\r
2100   appData.useStickyWindows = TRUE;\r
2101   appData.adjudicateDrawMoves = 0;\r
2102   appData.autoDisplayComment = TRUE;\r
2103   appData.autoDisplayTags = TRUE;\r
2104   appData.firstIsUCI = FALSE;\r
2105   appData.secondIsUCI = FALSE;\r
2106   appData.firstHasOwnBookUCI = TRUE;\r
2107   appData.secondHasOwnBookUCI = TRUE;\r
2108   appData.polyglotDir = "";\r
2109   appData.usePolyglotBook = FALSE;\r
2110   appData.polyglotBook = "";\r
2111   appData.defaultHashSize = 64;\r
2112   appData.defaultCacheSizeEGTB = 4;\r
2113   appData.defaultPathEGTB = "c:\\egtb";\r
2114   appData.firstOptions = "";\r
2115   appData.secondOptions = "";\r
2116 \r
2117   InitWindowPlacement( &wpGameList );\r
2118   InitWindowPlacement( &wpMoveHistory );\r
2119   InitWindowPlacement( &wpEvalGraph );\r
2120   InitWindowPlacement( &wpEngineOutput );\r
2121   InitWindowPlacement( &wpConsole );\r
2122 \r
2123   /* [HGM] User-selectable board size, adjudication control, miscellaneous */\r
2124   appData.NrFiles      = -1;\r
2125   appData.NrRanks      = -1;\r
2126   appData.holdingsSize = -1;\r
2127   appData.testClaims   = FALSE;\r
2128   appData.checkMates   = FALSE;\r
2129   appData.materialDraws= FALSE;\r
2130   appData.trivialDraws = FALSE;\r
2131   appData.ruleMoves    = 51;\r
2132   appData.drawRepeats  = 6;\r
2133   appData.matchPause   = 10000;\r
2134   appData.alphaRank    = FALSE;\r
2135   appData.allWhite     = FALSE;\r
2136   appData.upsideDown   = FALSE;\r
2137   appData.serverPause  = 15;\r
2138   appData.serverMovesName   = NULL;\r
2139   appData.suppressLoadMoves = FALSE;\r
2140   appData.firstTimeOdds  = 1;\r
2141   appData.secondTimeOdds = 1;\r
2142   appData.firstAccumulateTC  = 1; // combine previous and current sessions\r
2143   appData.secondAccumulateTC = 1;\r
2144   appData.firstNPS  = -1; // [HGM] nps: use wall-clock time\r
2145   appData.secondNPS = -1;\r
2146   appData.engineComments = 1;\r
2147   appData.smpCores = 1; // [HGM] SMP: max nr of cores\r
2148   appData.egtFormats = "";\r
2149 \r
2150 #ifdef ZIPPY\r
2151   appData.zippyTalk = ZIPPY_TALK;\r
2152   appData.zippyPlay = ZIPPY_PLAY;\r
2153   appData.zippyLines = ZIPPY_LINES;\r
2154   appData.zippyPinhead = ZIPPY_PINHEAD;\r
2155   appData.zippyPassword = ZIPPY_PASSWORD;\r
2156   appData.zippyPassword2 = ZIPPY_PASSWORD2;\r
2157   appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;\r
2158   appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;\r
2159   appData.zippyUseI = ZIPPY_USE_I;\r
2160   appData.zippyBughouse = ZIPPY_BUGHOUSE;\r
2161   appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;\r
2162   appData.zippyGameEnd = ZIPPY_GAME_END;\r
2163   appData.zippyGameStart = ZIPPY_GAME_START;\r
2164   appData.zippyAdjourn = ZIPPY_ADJOURN;\r
2165   appData.zippyAbort = ZIPPY_ABORT;\r
2166   appData.zippyVariants = ZIPPY_VARIANTS;\r
2167   appData.zippyMaxGames = ZIPPY_MAX_GAMES;\r
2168   appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;\r
2169 #endif\r
2170 \r
2171   /* Point font array elements to structures and\r
2172      parse default font names */\r
2173   for (i=0; i<NUM_FONTS; i++) {\r
2174     for (j=0; j<NUM_SIZES; j++) {\r
2175       font[j][i] = &fontRec[j][i];\r
2176       ParseFontName(font[j][i]->def, &font[j][i]->mfp);\r
2177     }\r
2178   }\r
2179   \r
2180   /* Parse default settings file if any */\r
2181   if (ParseSettingsFile(settingsFileName, buf)) {\r
2182     settingsFileName = strdup(buf);\r
2183   }\r
2184 \r
2185   /* Parse command line */\r
2186   ParseArgs(StringGet, &lpCmdLine);\r
2187 \r
2188   /* [HGM] make sure board size is acceptable */\r
2189   if(appData.NrFiles > BOARD_SIZE ||\r
2190      appData.NrRanks > BOARD_SIZE   )\r
2191       DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);\r
2192 \r
2193   /* [HGM] After parsing the options from the .ini file, and overruling them\r
2194    * with options from the command line, we now make an even higher priority\r
2195    * overrule by WB options attached to the engine command line. This so that\r
2196    * tournament managers can use WB options (such as /timeOdds) that follow\r
2197    * the engines.\r
2198    */\r
2199   if(appData.firstChessProgram != NULL) {\r
2200       char *p = StrStr(appData.firstChessProgram, "WBopt");\r
2201       static char *f = "first";\r
2202       char buf[MSG_SIZ], *q = buf;\r
2203       if(p != NULL) { // engine command line contains WinBoard options\r
2204           sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"\r
2205           ParseArgs(StringGet, &q);\r
2206           p[-1] = 0; // cut them offengine command line\r
2207       }\r
2208   }\r
2209   // now do same for second chess program\r
2210   if(appData.secondChessProgram != NULL) {\r
2211       char *p = StrStr(appData.secondChessProgram, "WBopt");\r
2212       static char *s = "second";\r
2213       char buf[MSG_SIZ], *q = buf;\r
2214       if(p != NULL) { // engine command line contains WinBoard options\r
2215           sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"\r
2216           ParseArgs(StringGet, &q);\r
2217           p[-1] = 0; // cut them offengine command line\r
2218       }\r
2219   }\r
2220 \r
2221 \r
2222   /* Propagate options that affect others */\r
2223   if (appData.matchMode || appData.matchGames) chessProgram = TRUE;\r
2224   if (appData.icsActive || appData.noChessProgram) {\r
2225      chessProgram = FALSE;  /* not local chess program mode */\r
2226   }\r
2227 \r
2228   /* Open startup dialog if needed */\r
2229   if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||\r
2230       (appData.icsActive && *appData.icsHost == NULLCHAR) ||\r
2231       (chessProgram && (*appData.firstChessProgram == NULLCHAR ||\r
2232                         *appData.secondChessProgram == NULLCHAR))) {\r
2233     FARPROC lpProc;\r
2234     \r
2235     lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);\r
2236     DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);\r
2237     FreeProcInstance(lpProc);\r
2238   }\r
2239 \r
2240   /* Make sure save files land in the right (?) directory */\r
2241   if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {\r
2242     appData.saveGameFile = strdup(buf);\r
2243   }\r
2244   if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {\r
2245     appData.savePositionFile = strdup(buf);\r
2246   }\r
2247 \r
2248   /* Finish initialization for fonts and sounds */\r
2249   for (i=0; i<NUM_FONTS; i++) {\r
2250     for (j=0; j<NUM_SIZES; j++) {\r
2251       CreateFontInMF(font[j][i]);\r
2252     }\r
2253   }\r
2254   /* xboard, and older WinBoards, controlled the move sound with the\r
2255      appData.ringBellAfterMoves option.  In the current WinBoard, we\r
2256      always turn the option on (so that the backend will call us),\r
2257      then let the user turn the sound off by setting it to silence if\r
2258      desired.  To accommodate old winboard.ini files saved by old\r
2259      versions of WinBoard, we also turn off the sound if the option\r
2260      was initially set to false. */\r
2261   if (!appData.ringBellAfterMoves) {\r
2262     sounds[(int)SoundMove].name = strdup("");\r
2263     appData.ringBellAfterMoves = TRUE;\r
2264   }\r
2265   GetCurrentDirectory(MSG_SIZ, currDir);\r
2266   SetCurrentDirectory(installDir);\r
2267   LoadAllSounds();\r
2268   SetCurrentDirectory(currDir);\r
2269 \r
2270   p = icsTextMenuString;\r
2271   if (p[0] == '@') {\r
2272     FILE* f = fopen(p + 1, "r");\r
2273     if (f == NULL) {\r
2274       DisplayFatalError(p + 1, errno, 2);\r
2275       return;\r
2276     }\r
2277     i = fread(buf, 1, sizeof(buf)-1, f);\r
2278     fclose(f);\r
2279     buf[i] = NULLCHAR;\r
2280     p = buf;\r
2281   }\r
2282   ParseIcsTextMenu(strdup(p));\r
2283 }\r
2284 \r
2285 \r
2286 VOID\r
2287 InitMenuChecks()\r
2288 {\r
2289   HMENU hmenu = GetMenu(hwndMain);\r
2290 \r
2291   (void) EnableMenuItem(hmenu, IDM_CommPort,\r
2292                         MF_BYCOMMAND|((appData.icsActive &&\r
2293                                        *appData.icsCommPort != NULLCHAR) ?\r
2294                                       MF_ENABLED : MF_GRAYED));\r
2295   (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,\r
2296                        MF_BYCOMMAND|(saveSettingsOnExit ?\r
2297                                      MF_CHECKED : MF_UNCHECKED));\r
2298 }\r
2299 \r
2300 \r
2301 VOID\r
2302 SaveSettings(char* name)\r
2303 {\r
2304   FILE *f;\r
2305   ArgDescriptor *ad;\r
2306   WINDOWPLACEMENT wp;\r
2307   char dir[MSG_SIZ];\r
2308 \r
2309   if (!hwndMain) return;\r
2310 \r
2311   GetCurrentDirectory(MSG_SIZ, dir);\r
2312   SetCurrentDirectory(installDir);\r
2313   f = fopen(name, "w");\r
2314   SetCurrentDirectory(dir);\r
2315   if (f == NULL) {\r
2316     DisplayError(name, errno);\r
2317     return;\r
2318   }\r
2319   fprintf(f, ";\n");\r
2320   fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);\r
2321   fprintf(f, ";\n");\r
2322   fprintf(f, "; You can edit the values of options that are already set in this file,\n");\r
2323   fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");\r
2324   fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");\r
2325   fprintf(f, ";\n");\r
2326 \r
2327   wp.length = sizeof(WINDOWPLACEMENT);\r
2328   GetWindowPlacement(hwndMain, &wp);\r
2329   boardX = wp.rcNormalPosition.left;\r
2330   boardY = wp.rcNormalPosition.top;\r
2331 \r
2332   if (hwndConsole) {\r
2333     GetWindowPlacement(hwndConsole, &wp);\r
2334     wpConsole.x = wp.rcNormalPosition.left;\r
2335     wpConsole.y = wp.rcNormalPosition.top;\r
2336     wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2337     wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2338   }\r
2339 \r
2340   if (analysisDialog) {\r
2341     GetWindowPlacement(analysisDialog, &wp);\r
2342     analysisX = wp.rcNormalPosition.left;\r
2343     analysisY = wp.rcNormalPosition.top;\r
2344     analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2345     analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2346   }\r
2347 \r
2348   if (commentDialog) {\r
2349     GetWindowPlacement(commentDialog, &wp);\r
2350     commentX = wp.rcNormalPosition.left;\r
2351     commentY = wp.rcNormalPosition.top;\r
2352     commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2353     commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2354   }\r
2355 \r
2356   if (editTagsDialog) {\r
2357     GetWindowPlacement(editTagsDialog, &wp);\r
2358     editTagsX = wp.rcNormalPosition.left;\r
2359     editTagsY = wp.rcNormalPosition.top;\r
2360     editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2361     editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2362   }\r
2363 \r
2364   if (gameListDialog) {\r
2365     GetWindowPlacement(gameListDialog, &wp);\r
2366     wpGameList.x = wp.rcNormalPosition.left;\r
2367     wpGameList.y = wp.rcNormalPosition.top;\r
2368     wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2369     wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2370   }\r
2371 \r
2372   /* [AS] Move history */\r
2373   wpMoveHistory.visible = MoveHistoryIsUp();\r
2374   \r
2375   if( moveHistoryDialog ) {\r
2376     GetWindowPlacement(moveHistoryDialog, &wp);\r
2377     wpMoveHistory.x = wp.rcNormalPosition.left;\r
2378     wpMoveHistory.y = wp.rcNormalPosition.top;\r
2379     wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2380     wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2381   }\r
2382 \r
2383   /* [AS] Eval graph */\r
2384   wpEvalGraph.visible = EvalGraphIsUp();\r
2385 \r
2386   if( evalGraphDialog ) {\r
2387     GetWindowPlacement(evalGraphDialog, &wp);\r
2388     wpEvalGraph.x = wp.rcNormalPosition.left;\r
2389     wpEvalGraph.y = wp.rcNormalPosition.top;\r
2390     wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2391     wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2392   }\r
2393 \r
2394   /* [AS] Engine output */\r
2395   wpEngineOutput.visible = EngineOutputIsUp();\r
2396 \r
2397   if( engineOutputDialog ) {\r
2398     GetWindowPlacement(engineOutputDialog, &wp);\r
2399     wpEngineOutput.x = wp.rcNormalPosition.left;\r
2400     wpEngineOutput.y = wp.rcNormalPosition.top;\r
2401     wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2402     wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2403   }\r
2404 \r
2405   for (ad = argDescriptors; ad->argName != NULL; ad++) {\r
2406     if (!ad->save) continue;\r
2407     switch (ad->argType) {\r
2408     case ArgString:\r
2409       {\r
2410         char *p = *(char **)ad->argLoc;\r
2411         if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {\r
2412           /* Quote multiline values or \-containing values\r
2413              with { } if possible */\r
2414           fprintf(f, "/%s={%s}\n", ad->argName, p);\r
2415         } else {\r
2416           /* Else quote with " " */\r
2417           fprintf(f, "/%s=\"", ad->argName);\r
2418           while (*p) {\r
2419             if (*p == '\n') fprintf(f, "\n");\r
2420             else if (*p == '\r') fprintf(f, "\\r");\r
2421             else if (*p == '\t') fprintf(f, "\\t");\r
2422             else if (*p == '\b') fprintf(f, "\\b");\r
2423             else if (*p == '\f') fprintf(f, "\\f");\r
2424             else if (*p < ' ') fprintf(f, "\\%03o", *p);\r
2425             else if (*p == '\"') fprintf(f, "\\\"");\r
2426             else if (*p == '\\') fprintf(f, "\\\\");\r
2427             else putc(*p, f);\r
2428             p++;\r
2429           }\r
2430           fprintf(f, "\"\n");\r
2431         }\r
2432       }\r
2433       break;\r
2434     case ArgInt:\r
2435     case ArgZ:\r
2436       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);\r
2437       break;\r
2438     case ArgX:\r
2439       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value\r
2440       break;\r
2441     case ArgY:\r
2442       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);\r
2443       break;\r
2444     case ArgFloat:\r
2445       fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);\r
2446       break;\r
2447     case ArgBoolean:\r
2448       fprintf(f, "/%s=%s\n", ad->argName, \r
2449         (*(Boolean *)ad->argLoc) ? "true" : "false");\r
2450       break;\r
2451     case ArgTrue:\r
2452       if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
2453       break;\r
2454     case ArgFalse:\r
2455       if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
2456       break;\r
2457     case ArgColor:\r
2458       {\r
2459         COLORREF color = *(COLORREF *)ad->argLoc;\r
2460         fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName, \r
2461           color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
2462       }\r
2463       break;\r
2464     case ArgAttribs:\r
2465       {\r
2466         MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];\r
2467         fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,\r
2468           (ta->effects & CFE_BOLD) ? "b" : "",\r
2469           (ta->effects & CFE_ITALIC) ? "i" : "",\r
2470           (ta->effects & CFE_UNDERLINE) ? "u" : "",\r
2471           (ta->effects & CFE_STRIKEOUT) ? "s" : "",\r
2472           (ta->effects) ? " " : "",\r
2473           ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);\r
2474       }\r
2475       break;\r
2476     case ArgFilename:\r
2477       if (strchr(*(char **)ad->argLoc, '\"')) {\r
2478         fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);\r
2479       } else {\r
2480         fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);\r
2481       }\r
2482       break;\r
2483     case ArgBoardSize:\r
2484       fprintf(f, "/%s=%s\n", ad->argName,\r
2485               sizeInfo[*(BoardSize *)ad->argLoc].name);\r
2486       break;\r
2487     case ArgFont:\r
2488       {\r
2489         int bs;\r
2490         for (bs=0; bs<NUM_SIZES; bs++) {\r
2491           MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;\r
2492           fprintf(f, "/size=%s ", sizeInfo[bs].name);\r
2493           fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",\r
2494             ad->argName, mfp->faceName, mfp->pointSize,\r
2495             mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",\r
2496             mfp->bold ? "b" : "",\r
2497             mfp->italic ? "i" : "",\r
2498             mfp->underline ? "u" : "",\r
2499             mfp->strikeout ? "s" : "");\r
2500         }\r
2501       }\r
2502       break;\r
2503     case ArgCommSettings:\r
2504       PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);\r
2505     case ArgNone:\r
2506     case ArgSettingsFilename: ;\r
2507     }\r
2508   }\r
2509   fclose(f);\r
2510 }\r
2511 \r
2512 \r
2513 \r
2514 /*---------------------------------------------------------------------------*\\r
2515  *\r
2516  * GDI board drawing routines\r
2517  *\r
2518 \*---------------------------------------------------------------------------*/\r
2519 \r
2520 /* [AS] Draw square using background texture */\r
2521 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )\r
2522 {\r
2523     XFORM   x;\r
2524 \r
2525     if( mode == 0 ) {\r
2526         return; /* Should never happen! */\r
2527     }\r
2528 \r
2529     SetGraphicsMode( dst, GM_ADVANCED );\r
2530 \r
2531     switch( mode ) {\r
2532     case 1:\r
2533         /* Identity */\r
2534         break;\r
2535     case 2:\r
2536         /* X reflection */\r
2537         x.eM11 = -1.0;\r
2538         x.eM12 = 0;\r
2539         x.eM21 = 0;\r
2540         x.eM22 = 1.0;\r
2541         x.eDx = (FLOAT) dw + dx - 1;\r
2542         x.eDy = 0;\r
2543         dx = 0;\r
2544         SetWorldTransform( dst, &x );\r
2545         break;\r
2546     case 3:\r
2547         /* Y reflection */\r
2548         x.eM11 = 1.0;\r
2549         x.eM12 = 0;\r
2550         x.eM21 = 0;\r
2551         x.eM22 = -1.0;\r
2552         x.eDx = 0;\r
2553         x.eDy = (FLOAT) dh + dy - 1;\r
2554         dy = 0;\r
2555         SetWorldTransform( dst, &x );\r
2556         break;\r
2557     case 4:\r
2558         /* X/Y flip */\r
2559         x.eM11 = 0;\r
2560         x.eM12 = 1.0;\r
2561         x.eM21 = 1.0;\r
2562         x.eM22 = 0;\r
2563         x.eDx = (FLOAT) dx;\r
2564         x.eDy = (FLOAT) dy;\r
2565         dx = 0;\r
2566         dy = 0;\r
2567         SetWorldTransform( dst, &x );\r
2568         break;\r
2569     }\r
2570 \r
2571     BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );\r
2572 \r
2573     x.eM11 = 1.0;\r
2574     x.eM12 = 0;\r
2575     x.eM21 = 0;\r
2576     x.eM22 = 1.0;\r
2577     x.eDx = 0;\r
2578     x.eDy = 0;\r
2579     SetWorldTransform( dst, &x );\r
2580 \r
2581     ModifyWorldTransform( dst, 0, MWT_IDENTITY );\r
2582 }\r
2583 \r
2584 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */\r
2585 enum {\r
2586     PM_WP = (int) WhitePawn, \r
2587     PM_WN = (int) WhiteKnight, \r
2588     PM_WB = (int) WhiteBishop, \r
2589     PM_WR = (int) WhiteRook, \r
2590     PM_WQ = (int) WhiteQueen, \r
2591     PM_WF = (int) WhiteFerz, \r
2592     PM_WW = (int) WhiteWazir, \r
2593     PM_WE = (int) WhiteAlfil, \r
2594     PM_WM = (int) WhiteMan, \r
2595     PM_WO = (int) WhiteCannon, \r
2596     PM_WU = (int) WhiteUnicorn, \r
2597     PM_WH = (int) WhiteNightrider, \r
2598     PM_WA = (int) WhiteAngel, \r
2599     PM_WC = (int) WhiteMarshall, \r
2600     PM_WAB = (int) WhiteCardinal, \r
2601     PM_WD = (int) WhiteDragon, \r
2602     PM_WL = (int) WhiteLance, \r
2603     PM_WS = (int) WhiteCobra, \r
2604     PM_WV = (int) WhiteFalcon, \r
2605     PM_WSG = (int) WhiteSilver, \r
2606     PM_WG = (int) WhiteGrasshopper, \r
2607     PM_WK = (int) WhiteKing,\r
2608     PM_BP = (int) BlackPawn, \r
2609     PM_BN = (int) BlackKnight, \r
2610     PM_BB = (int) BlackBishop, \r
2611     PM_BR = (int) BlackRook, \r
2612     PM_BQ = (int) BlackQueen, \r
2613     PM_BF = (int) BlackFerz, \r
2614     PM_BW = (int) BlackWazir, \r
2615     PM_BE = (int) BlackAlfil, \r
2616     PM_BM = (int) BlackMan,\r
2617     PM_BO = (int) BlackCannon, \r
2618     PM_BU = (int) BlackUnicorn, \r
2619     PM_BH = (int) BlackNightrider, \r
2620     PM_BA = (int) BlackAngel, \r
2621     PM_BC = (int) BlackMarshall, \r
2622     PM_BG = (int) BlackGrasshopper, \r
2623     PM_BAB = (int) BlackCardinal,\r
2624     PM_BD = (int) BlackDragon,\r
2625     PM_BL = (int) BlackLance,\r
2626     PM_BS = (int) BlackCobra,\r
2627     PM_BV = (int) BlackFalcon,\r
2628     PM_BSG = (int) BlackSilver,\r
2629     PM_BK = (int) BlackKing\r
2630 };\r
2631 \r
2632 static HFONT hPieceFont = NULL;\r
2633 static HBITMAP hPieceMask[(int) EmptySquare];\r
2634 static HBITMAP hPieceFace[(int) EmptySquare];\r
2635 static int fontBitmapSquareSize = 0;\r
2636 static char pieceToFontChar[(int) EmptySquare] =\r
2637                               { 'p', 'n', 'b', 'r', 'q', \r
2638                       'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',\r
2639                       'k', 'o', 'm', 'v', 't', 'w', \r
2640                       'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',\r
2641                                                               'l' };\r
2642 \r
2643 extern BOOL SetCharTable( char *table, const char * map );\r
2644 /* [HGM] moved to backend.c */\r
2645 \r
2646 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )\r
2647 {\r
2648     HBRUSH hbrush;\r
2649     BYTE r1 = GetRValue( color );\r
2650     BYTE g1 = GetGValue( color );\r
2651     BYTE b1 = GetBValue( color );\r
2652     BYTE r2 = r1 / 2;\r
2653     BYTE g2 = g1 / 2;\r
2654     BYTE b2 = b1 / 2;\r
2655     RECT rc;\r
2656 \r
2657     /* Create a uniform background first */\r
2658     hbrush = CreateSolidBrush( color );\r
2659     SetRect( &rc, 0, 0, squareSize, squareSize );\r
2660     FillRect( hdc, &rc, hbrush );\r
2661     DeleteObject( hbrush );\r
2662     \r
2663     if( mode == 1 ) {\r
2664         /* Vertical gradient, good for pawn, knight and rook, less for queen and king */\r
2665         int steps = squareSize / 2;\r
2666         int i;\r
2667 \r
2668         for( i=0; i<steps; i++ ) {\r
2669             BYTE r = r1 - (r1-r2) * i / steps;\r
2670             BYTE g = g1 - (g1-g2) * i / steps;\r
2671             BYTE b = b1 - (b1-b2) * i / steps;\r
2672 \r
2673             hbrush = CreateSolidBrush( RGB(r,g,b) );\r
2674             SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );\r
2675             FillRect( hdc, &rc, hbrush );\r
2676             DeleteObject(hbrush);\r
2677         }\r
2678     }\r
2679     else if( mode == 2 ) {\r
2680         /* Diagonal gradient, good more or less for every piece */\r
2681         POINT triangle[3];\r
2682         HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );\r
2683         HBRUSH hbrush_old;\r
2684         int steps = squareSize;\r
2685         int i;\r
2686 \r
2687         triangle[0].x = squareSize - steps;\r
2688         triangle[0].y = squareSize;\r
2689         triangle[1].x = squareSize;\r
2690         triangle[1].y = squareSize;\r
2691         triangle[2].x = squareSize;\r
2692         triangle[2].y = squareSize - steps;\r
2693 \r
2694         for( i=0; i<steps; i++ ) {\r
2695             BYTE r = r1 - (r1-r2) * i / steps;\r
2696             BYTE g = g1 - (g1-g2) * i / steps;\r
2697             BYTE b = b1 - (b1-b2) * i / steps;\r
2698 \r
2699             hbrush = CreateSolidBrush( RGB(r,g,b) );\r
2700             hbrush_old = SelectObject( hdc, hbrush );\r
2701             Polygon( hdc, triangle, 3 );\r
2702             SelectObject( hdc, hbrush_old );\r
2703             DeleteObject(hbrush);\r
2704             triangle[0].x++;\r
2705             triangle[2].y++;\r
2706         }\r
2707 \r
2708         SelectObject( hdc, hpen );\r
2709     }\r
2710 }\r
2711 \r
2712 /*\r
2713     [AS] The method I use to create the bitmaps it a bit tricky, but it\r
2714     seems to work ok. The main problem here is to find the "inside" of a chess\r
2715     piece: follow the steps as explained below.\r
2716 */\r
2717 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )\r
2718 {\r
2719     HBITMAP hbm;\r
2720     HBITMAP hbm_old;\r
2721     COLORREF chroma = RGB(0xFF,0x00,0xFF);\r
2722     RECT rc;\r
2723     SIZE sz;\r
2724     POINT pt;\r
2725     int backColor = whitePieceColor; \r
2726     int foreColor = blackPieceColor;\r
2727     \r
2728     if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {\r
2729         backColor = appData.fontBackColorWhite;\r
2730         foreColor = appData.fontForeColorWhite;\r
2731     }\r
2732     else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {\r
2733         backColor = appData.fontBackColorBlack;\r
2734         foreColor = appData.fontForeColorBlack;\r
2735     }\r
2736 \r
2737     /* Mask */\r
2738     hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2739 \r
2740     hbm_old = SelectObject( hdc, hbm );\r
2741 \r
2742     rc.left = 0;\r
2743     rc.top = 0;\r
2744     rc.right = squareSize;\r
2745     rc.bottom = squareSize;\r
2746 \r
2747     /* Step 1: background is now black */\r
2748     FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );\r
2749 \r
2750     GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );\r
2751 \r
2752     pt.x = (squareSize - sz.cx) / 2;\r
2753     pt.y = (squareSize - sz.cy) / 2;\r
2754 \r
2755     SetBkMode( hdc, TRANSPARENT );\r
2756     SetTextColor( hdc, chroma );\r
2757     /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */\r
2758     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2759 \r
2760     SelectObject( hdc, GetStockObject(WHITE_BRUSH) );\r
2761     /* Step 3: the area outside the piece is filled with white */\r
2762 //    FloodFill( hdc, 0, 0, chroma );\r
2763     ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );\r
2764     ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big\r
2765     ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );\r
2766     ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );\r
2767     SelectObject( hdc, GetStockObject(BLACK_BRUSH) );\r
2768     /* \r
2769         Step 4: this is the tricky part, the area inside the piece is filled with black,\r
2770         but if the start point is not inside the piece we're lost!\r
2771         There should be a better way to do this... if we could create a region or path\r
2772         from the fill operation we would be fine for example.\r
2773     */\r
2774 //    FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );\r
2775     ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );\r
2776 \r
2777     {   /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */\r
2778         HDC dc2 = CreateCompatibleDC( hdc_window );\r
2779         HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2780 \r
2781         SelectObject( dc2, bm2 );\r
2782         BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy\r
2783         BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2784         BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2785         BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2786         BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2787 \r
2788         DeleteDC( dc2 );\r
2789         DeleteObject( bm2 );\r
2790     }\r
2791 \r
2792     SetTextColor( hdc, 0 );\r
2793     /* \r
2794         Step 5: some fonts have "disconnected" areas that are skipped by the fill:\r
2795         draw the piece again in black for safety.\r
2796     */\r
2797     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2798 \r
2799     SelectObject( hdc, hbm_old );\r
2800 \r
2801     if( hPieceMask[index] != NULL ) {\r
2802         DeleteObject( hPieceMask[index] );\r
2803     }\r
2804 \r
2805     hPieceMask[index] = hbm;\r
2806 \r
2807     /* Face */\r
2808     hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2809 \r
2810     SelectObject( hdc, hbm );\r
2811 \r
2812     {\r
2813         HDC dc1 = CreateCompatibleDC( hdc_window );\r
2814         HDC dc2 = CreateCompatibleDC( hdc_window );\r
2815         HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2816 \r
2817         SelectObject( dc1, hPieceMask[index] );\r
2818         SelectObject( dc2, bm2 );\r
2819         FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );\r
2820         BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );\r
2821         \r
2822         /* \r
2823             Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves\r
2824             the piece background and deletes (makes transparent) the rest.\r
2825             Thanks to that mask, we are free to paint the background with the greates\r
2826             freedom, as we'll be able to mask off the unwanted parts when finished.\r
2827             We use this, to make gradients and give the pieces a "roundish" look.\r
2828         */\r
2829         SetPieceBackground( hdc, backColor, 2 );\r
2830         BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );\r
2831 \r
2832         DeleteDC( dc2 );\r
2833         DeleteDC( dc1 );\r
2834         DeleteObject( bm2 );\r
2835     }\r
2836 \r
2837     SetTextColor( hdc, foreColor );\r
2838     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2839 \r
2840     SelectObject( hdc, hbm_old );\r
2841 \r
2842     if( hPieceFace[index] != NULL ) {\r
2843         DeleteObject( hPieceFace[index] );\r
2844     }\r
2845 \r
2846     hPieceFace[index] = hbm;\r
2847 }\r
2848 \r
2849 static int TranslatePieceToFontPiece( int piece )\r
2850 {\r
2851     switch( piece ) {\r
2852     case BlackPawn:\r
2853         return PM_BP;\r
2854     case BlackKnight:\r
2855         return PM_BN;\r
2856     case BlackBishop:\r
2857         return PM_BB;\r
2858     case BlackRook:\r
2859         return PM_BR;\r
2860     case BlackQueen:\r
2861         return PM_BQ;\r
2862     case BlackKing:\r
2863         return PM_BK;\r
2864     case WhitePawn:\r
2865         return PM_WP;\r
2866     case WhiteKnight:\r
2867         return PM_WN;\r
2868     case WhiteBishop:\r
2869         return PM_WB;\r
2870     case WhiteRook:\r
2871         return PM_WR;\r
2872     case WhiteQueen:\r
2873         return PM_WQ;\r
2874     case WhiteKing:\r
2875         return PM_WK;\r
2876 \r
2877     case BlackAngel:\r
2878         return PM_BA;\r
2879     case BlackMarshall:\r
2880         return PM_BC;\r
2881     case BlackFerz:\r
2882         return PM_BF;\r
2883     case BlackNightrider:\r
2884         return PM_BH;\r
2885     case BlackAlfil:\r
2886         return PM_BE;\r
2887     case BlackWazir:\r
2888         return PM_BW;\r
2889     case BlackUnicorn:\r
2890         return PM_BU;\r
2891     case BlackCannon:\r
2892         return PM_BO;\r
2893     case BlackGrasshopper:\r
2894         return PM_BG;\r
2895     case BlackMan:\r
2896         return PM_BM;\r
2897     case BlackSilver:\r
2898         return PM_BSG;\r
2899     case BlackLance:\r
2900         return PM_BL;\r
2901     case BlackFalcon:\r
2902         return PM_BV;\r
2903     case BlackCobra:\r
2904         return PM_BS;\r
2905     case BlackCardinal:\r
2906         return PM_BAB;\r
2907     case BlackDragon:\r
2908         return PM_BD;\r
2909 \r
2910     case WhiteAngel:\r
2911         return PM_WA;\r
2912     case WhiteMarshall:\r
2913         return PM_WC;\r
2914     case WhiteFerz:\r
2915         return PM_WF;\r
2916     case WhiteNightrider:\r
2917         return PM_WH;\r
2918     case WhiteAlfil:\r
2919         return PM_WE;\r
2920     case WhiteWazir:\r
2921         return PM_WW;\r
2922     case WhiteUnicorn:\r
2923         return PM_WU;\r
2924     case WhiteCannon:\r
2925         return PM_WO;\r
2926     case WhiteGrasshopper:\r
2927         return PM_WG;\r
2928     case WhiteMan:\r
2929         return PM_WM;\r
2930     case WhiteSilver:\r
2931         return PM_WSG;\r
2932     case WhiteLance:\r
2933         return PM_WL;\r
2934     case WhiteFalcon:\r
2935         return PM_WV;\r
2936     case WhiteCobra:\r
2937         return PM_WS;\r
2938     case WhiteCardinal:\r
2939         return PM_WAB;\r
2940     case WhiteDragon:\r
2941         return PM_WD;\r
2942     }\r
2943 \r
2944     return 0;\r
2945 }\r
2946 \r
2947 void CreatePiecesFromFont()\r
2948 {\r
2949     LOGFONT lf;\r
2950     HDC hdc_window = NULL;\r
2951     HDC hdc = NULL;\r
2952     HFONT hfont_old;\r
2953     int fontHeight;\r
2954     int i;\r
2955 \r
2956     if( fontBitmapSquareSize < 0 ) {\r
2957         /* Something went seriously wrong in the past: do not try to recreate fonts! */\r
2958         return;\r
2959     }\r
2960 \r
2961     if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {\r
2962         fontBitmapSquareSize = -1;\r
2963         return;\r
2964     }\r
2965 \r
2966     if( fontBitmapSquareSize != squareSize ) {\r
2967         hdc_window = GetDC( hwndMain );\r
2968         hdc = CreateCompatibleDC( hdc_window );\r
2969 \r
2970         if( hPieceFont != NULL ) {\r
2971             DeleteObject( hPieceFont );\r
2972         }\r
2973         else {\r
2974             for( i=0; i<=(int)BlackKing; i++ ) {\r
2975                 hPieceMask[i] = NULL;\r
2976                 hPieceFace[i] = NULL;\r
2977             }\r
2978         }\r
2979 \r
2980         fontHeight = 75;\r
2981 \r
2982         if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {\r
2983             fontHeight = appData.fontPieceSize;\r
2984         }\r
2985 \r
2986         fontHeight = (fontHeight * squareSize) / 100;\r
2987 \r
2988         lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );\r
2989         lf.lfWidth = 0;\r
2990         lf.lfEscapement = 0;\r
2991         lf.lfOrientation = 0;\r
2992         lf.lfWeight = FW_NORMAL;\r
2993         lf.lfItalic = 0;\r
2994         lf.lfUnderline = 0;\r
2995         lf.lfStrikeOut = 0;\r
2996         lf.lfCharSet = DEFAULT_CHARSET;\r
2997         lf.lfOutPrecision = OUT_DEFAULT_PRECIS;\r
2998         lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
2999         lf.lfQuality = PROOF_QUALITY;\r
3000         lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;\r
3001         strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );\r
3002         lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';\r
3003 \r
3004         hPieceFont = CreateFontIndirect( &lf );\r
3005 \r
3006         if( hPieceFont == NULL ) {\r
3007             fontBitmapSquareSize = -2;\r
3008         }\r
3009         else {\r
3010             /* Setup font-to-piece character table */\r
3011             if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {\r
3012                 /* No (or wrong) global settings, try to detect the font */\r
3013                 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {\r
3014                     /* Alpha */\r
3015                     SetCharTable(pieceToFontChar, "phbrqkojntwl");\r
3016                 }\r
3017                 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {\r
3018                     /* DiagramTT* family */\r
3019                     SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");\r
3020                 }\r
3021                 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {\r
3022                     /* Fairy symbols */\r
3023                      SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");\r
3024                 }\r
3025                 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {\r
3026                     /* Good Companion (Some characters get warped as literal :-( */\r
3027                     char s[] = "1cmWG0ñueOS¯®oYI23wgQU";\r
3028                     s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;\r
3029                     SetCharTable(pieceToFontChar, s);\r
3030                 }\r
3031                 else {\r
3032                     /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */\r
3033                     SetCharTable(pieceToFontChar, "pnbrqkomvtwl");\r
3034                 }\r
3035             }\r
3036 \r
3037             /* Create bitmaps */\r
3038             hfont_old = SelectObject( hdc, hPieceFont );\r
3039             for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */\r
3040                 if(PieceToChar((ChessSquare)i) != '.')     /* skip unused pieces         */\r
3041                     CreatePieceMaskFromFont( hdc_window, hdc, i );\r
3042 \r
3043             SelectObject( hdc, hfont_old );\r
3044 \r
3045             fontBitmapSquareSize = squareSize;\r
3046         }\r
3047     }\r
3048 \r
3049     if( hdc != NULL ) {\r
3050         DeleteDC( hdc );\r
3051     }\r
3052 \r
3053     if( hdc_window != NULL ) {\r
3054         ReleaseDC( hwndMain, hdc_window );\r
3055     }\r
3056 }\r
3057 \r
3058 HBITMAP\r
3059 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)\r
3060 {\r
3061   char name[128];\r
3062 \r
3063   sprintf(name, "%s%d%s", piece, squareSize, suffix);\r
3064   if (gameInfo.event &&\r
3065       strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&\r
3066       strcmp(name, "k80s") == 0) {\r
3067     strcpy(name, "tim");\r
3068   }\r
3069   return LoadBitmap(hinst, name);\r
3070 }\r
3071 \r
3072 \r
3073 /* Insert a color into the program's logical palette\r
3074    structure.  This code assumes the given color is\r
3075    the result of the RGB or PALETTERGB macro, and it\r
3076    knows how those macros work (which is documented).\r
3077 */\r
3078 VOID\r
3079 InsertInPalette(COLORREF color)\r
3080 {\r
3081   LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);\r
3082 \r
3083   if (pLogPal->palNumEntries++ >= PALETTESIZE) {\r
3084     DisplayFatalError("Too many colors", 0, 1);\r
3085     pLogPal->palNumEntries--;\r
3086     return;\r
3087   }\r
3088 \r
3089   pe->peFlags = (char) 0;\r
3090   pe->peRed = (char) (0xFF & color);\r
3091   pe->peGreen = (char) (0xFF & (color >> 8));\r
3092   pe->peBlue = (char) (0xFF & (color >> 16));\r
3093   return;\r
3094 }\r
3095 \r
3096 \r
3097 VOID\r
3098 InitDrawingColors()\r
3099 {\r
3100   if (pLogPal == NULL) {\r
3101     /* Allocate enough memory for a logical palette with\r
3102      * PALETTESIZE entries and set the size and version fields\r
3103      * of the logical palette structure.\r
3104      */\r
3105     pLogPal = (NPLOGPALETTE)\r
3106       LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +\r
3107                               (sizeof(PALETTEENTRY) * (PALETTESIZE))));\r
3108     pLogPal->palVersion    = 0x300;\r
3109   }\r
3110   pLogPal->palNumEntries = 0;\r
3111 \r
3112   InsertInPalette(lightSquareColor);\r
3113   InsertInPalette(darkSquareColor);\r
3114   InsertInPalette(whitePieceColor);\r
3115   InsertInPalette(blackPieceColor);\r
3116   InsertInPalette(highlightSquareColor);\r
3117   InsertInPalette(premoveHighlightColor);\r
3118 \r
3119   /*  create a logical color palette according the information\r
3120    *  in the LOGPALETTE structure.\r
3121    */\r
3122   hPal = CreatePalette((LPLOGPALETTE) pLogPal);\r
3123 \r
3124   lightSquareBrush = CreateSolidBrush(lightSquareColor);\r
3125   blackSquareBrush = CreateSolidBrush(blackPieceColor);\r
3126   darkSquareBrush = CreateSolidBrush(darkSquareColor);\r
3127   whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
3128   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
3129   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
3130   explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic\r
3131   /* [AS] Force rendering of the font-based pieces */\r
3132   if( fontBitmapSquareSize > 0 ) {\r
3133     fontBitmapSquareSize = 0;\r
3134   }\r
3135 }\r
3136 \r
3137 \r
3138 int\r
3139 BoardWidth(int boardSize, int n)\r
3140 { /* [HGM] argument n added to allow different width and height */\r
3141   int lineGap = sizeInfo[boardSize].lineGap;\r
3142 \r
3143   if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
3144       lineGap = appData.overrideLineGap;\r
3145   }\r
3146 \r
3147   return (n + 1) * lineGap +\r
3148           n * sizeInfo[boardSize].squareSize;\r
3149 }\r
3150 \r
3151 /* Respond to board resize by dragging edge */\r
3152 VOID\r
3153 ResizeBoard(int newSizeX, int newSizeY, int flags)\r
3154 {\r
3155   BoardSize newSize = NUM_SIZES - 1;\r
3156   static int recurse = 0;\r
3157   if (IsIconic(hwndMain)) return;\r
3158   if (recurse > 0) return;\r
3159   recurse++;\r
3160   while (newSize > 0) {\r
3161         InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects\r
3162         if(newSizeX >= sizeInfo[newSize].cliWidth &&\r
3163            newSizeY >= sizeInfo[newSize].cliHeight) break;\r
3164     newSize--;\r
3165   } \r
3166   boardSize = newSize;\r
3167   InitDrawingSizes(boardSize, flags);\r
3168   recurse--;\r
3169 }\r
3170 \r
3171 \r
3172 \r
3173 VOID\r
3174 InitDrawingSizes(BoardSize boardSize, int flags)\r
3175 {\r
3176   int i, boardWidth, boardHeight; /* [HGM] height treated separately */\r
3177   ChessSquare piece;\r
3178   static int oldBoardSize = -1, oldTinyLayout = 0;\r
3179   HDC hdc;\r
3180   SIZE clockSize, messageSize;\r
3181   HFONT oldFont;\r
3182   char buf[MSG_SIZ];\r
3183   char *str;\r
3184   HMENU hmenu = GetMenu(hwndMain);\r
3185   RECT crect, wrect, oldRect;\r
3186   int offby;\r
3187   LOGBRUSH logbrush;\r
3188 \r
3189   int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only\r
3190   if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }\r
3191 \r
3192   /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */\r
3193   if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;\r
3194 \r
3195   oldRect.left = boardX; //[HGM] placement: remember previous window params\r
3196   oldRect.top = boardY;\r