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