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