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