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