Integrate castling and e.p. rights into board array; bugfix for EditPosition
[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 struct {\r
879   char *argName;\r
880   ArgType argType;\r
881   /***\r
882   union {\r
883     String *pString;       // ArgString\r
884     int *pInt;             // ArgInt\r
885     float *pFloat;         // ArgFloat\r
886     Boolean *pBoolean;     // ArgBoolean\r
887     COLORREF *pColor;      // ArgColor\r
888     ColorClass cc;         // ArgAttribs\r
889     String *pFilename;     // ArgFilename\r
890     BoardSize *pBoardSize; // ArgBoardSize\r
891     int whichFont;         // ArgFont\r
892     DCB *pDCB;             // ArgCommSettings\r
893     String *pFilename;     // ArgSettingsFilename\r
894   } argLoc;\r
895   ***/\r
896   LPVOID argLoc;\r
897   BOOL save;\r
898 } ArgDescriptor;\r
899 \r
900 int junk;\r
901 ArgDescriptor argDescriptors[] = {\r
902   /* positional arguments */\r
903   { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
904   { "", ArgNone, NULL },\r
905   /* keyword arguments */\r
906   JAWS_ARGS\r
907   { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },\r
908   { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },\r
909   { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },\r
910   { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },\r
911   { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },\r
912   { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },\r
913   { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },\r
914   { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },\r
915   { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },\r
916   { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },\r
917   { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },\r
918   { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },\r
919   { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },\r
920   { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },\r
921   { "initString", ArgString, (LPVOID) &appData.initString, FALSE },\r
922   { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },\r
923   { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },\r
924   { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,\r
925     FALSE },\r
926   { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,\r
927     FALSE },\r
928   { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,\r
929     FALSE },\r
930   { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },\r
931   { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,\r
932     FALSE },\r
933   { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },\r
934   { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
935   { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
936   { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
937   { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
938   { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },\r
939   { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },\r
940   { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },\r
941   { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },\r
942   { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },\r
943   { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },\r
944   { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },\r
945   { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },\r
946   { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },\r
947   { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },\r
948   { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },\r
949   { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },\r
950   /*!!bitmapDirectory?*/\r
951   { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },\r
952   { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },\r
953   { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },\r
954   { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },\r
955   { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },\r
956   { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },\r
957   { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },\r
958   { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },\r
959   { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },\r
960   { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },\r
961   { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },\r
962   { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },\r
963   { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },\r
964   { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },\r
965   { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },\r
966   { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },\r
967   { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },\r
968   { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },\r
969   { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
970   { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
971   { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
972   { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
973   { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },\r
974   { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },\r
975   { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },\r
976   { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },\r
977   { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },\r
978   { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },\r
979   { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },\r
980   { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },\r
981   { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },\r
982   { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
983   { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
984   { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },\r
985   { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },\r
986   { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },\r
987   { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },\r
988   { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },\r
989   { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },\r
990   { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },\r
991   { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },\r
992   { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },\r
993   { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },\r
994   { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },\r
995   { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },\r
996   { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },\r
997   { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },\r
998   { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },\r
999   { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },\r
1000   { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },\r
1001   { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },\r
1002   { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },\r
1003   { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },\r
1004   { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },\r
1005   { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },\r
1006   { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },\r
1007   { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },\r
1008   { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },\r
1009   { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },\r
1010   { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },\r
1011   { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },\r
1012   { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },\r
1013   { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },\r
1014   { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },\r
1015   { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },\r
1016   { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },\r
1017   { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },\r
1018   { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },\r
1019   { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },\r
1020   { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },\r
1021   { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },\r
1022   { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },\r
1023   { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },\r
1024   { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },\r
1025   { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },\r
1026   { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },\r
1027   { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },\r
1028   { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },\r
1029   { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },\r
1030   { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },\r
1031   { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },\r
1032   { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },\r
1033   { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },\r
1034   { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },\r
1035   { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },\r
1036   { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },\r
1037   { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },\r
1038   { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },\r
1039   { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },\r
1040   { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },\r
1041   { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },\r
1042   { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },\r
1043   { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },\r
1044   { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, \r
1045     FALSE }, /* only so that old WinBoard.ini files from betas can be read */\r
1046   { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },\r
1047   { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },\r
1048   { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },\r
1049   { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },\r
1050   { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },\r
1051   { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },\r
1052   { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */\r
1053   { "boardSize", ArgBoardSize, (LPVOID) &boardSize,\r
1054     TRUE }, /* must come after all fonts */\r
1055   { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },\r
1056   { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,\r
1057     FALSE }, /* historical; kept only so old winboard.ini files will parse */\r
1058   { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },\r
1059   { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },\r
1060   { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },\r
1061   { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },\r
1062   { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },\r
1063   { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },\r
1064   { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },\r
1065   { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },\r
1066   { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },\r
1067   { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },\r
1068   { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },\r
1069   { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },\r
1070   { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },\r
1071   { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },\r
1072   { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },\r
1073   { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },\r
1074   { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },\r
1075   { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },\r
1076   { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },\r
1077   { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },\r
1078   { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },\r
1079   { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },\r
1080   { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },\r
1081   { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },\r
1082   { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },\r
1083   { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
1084   { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
1085   { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
1086   { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },\r
1087   { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
1088   { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
1089   { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
1090   { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },\r
1091   { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },\r
1092   { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },\r
1093   { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },\r
1094   { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },\r
1095   { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },\r
1096   { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },\r
1097   { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },\r
1098   { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },\r
1099   { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },\r
1100   { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },\r
1101   { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },\r
1102   { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },\r
1103   { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },\r
1104   { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },\r
1105   { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },\r
1106   { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },\r
1107   { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },\r
1108   { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },\r
1109   { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },\r
1110   { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },\r
1111   { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },\r
1112   { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },\r
1113   { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },\r
1114   { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },\r
1115   { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },\r
1116   { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },\r
1117   { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },\r
1118   { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },\r
1119   { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },\r
1120   { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},\r
1121   { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},\r
1122   { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},\r
1123   { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},\r
1124   { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},\r
1125   { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},\r
1126   { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},\r
1127   { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },\r
1128   { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },\r
1129   { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },\r
1130   { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },\r
1131   { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },\r
1132   { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },\r
1133   { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },\r
1134   { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },\r
1135   { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },\r
1136   { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },\r
1137   { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },\r
1138   { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },\r
1139   { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },\r
1140   { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },\r
1141   { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },\r
1142   { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },\r
1143   { "highlightLastMove", ArgBoolean,\r
1144     (LPVOID) &appData.highlightLastMove, TRUE },\r
1145   { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },\r
1146   { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },\r
1147   { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },\r
1148   { "highlightDragging", ArgBoolean,\r
1149     (LPVOID) &appData.highlightDragging, TRUE },\r
1150   { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },\r
1151   { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },\r
1152   { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },\r
1153   { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },\r
1154   { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },\r
1155   { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },\r
1156   { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },\r
1157   { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },\r
1158   { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },\r
1159   { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },\r
1160   { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },\r
1161   { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },\r
1162   { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },\r
1163   { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },\r
1164   { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },\r
1165   { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },\r
1166   { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },\r
1167   { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },\r
1168   { "soundShout", ArgFilename,\r
1169     (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },\r
1170   { "soundSShout", ArgFilename,\r
1171     (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },\r
1172   { "soundChannel1", ArgFilename,\r
1173     (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },\r
1174   { "soundChannel", ArgFilename,\r
1175     (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },\r
1176   { "soundKibitz", ArgFilename,\r
1177     (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },\r
1178   { "soundTell", ArgFilename,\r
1179     (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },\r
1180   { "soundChallenge", ArgFilename,\r
1181     (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },\r
1182   { "soundRequest", ArgFilename,\r
1183     (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },\r
1184   { "soundSeek", ArgFilename,\r
1185     (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },\r
1186   { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },\r
1187   { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },\r
1188   { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },\r
1189   { "soundIcsLoss", ArgFilename, \r
1190     (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },\r
1191   { "soundIcsDraw", ArgFilename, \r
1192     (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },\r
1193   { "soundIcsUnfinished", ArgFilename, \r
1194     (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},\r
1195   { "soundIcsAlarm", ArgFilename, \r
1196     (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },\r
1197   { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },\r
1198   { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },\r
1199   { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },\r
1200   { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },\r
1201   { "reuseChessPrograms", ArgBoolean,\r
1202     (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */\r
1203   { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },\r
1204   { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },\r
1205   { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
1206   { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
1207   { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },\r
1208   { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
1209   { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
1210   { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },\r
1211   { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },\r
1212   { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },\r
1213   { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },\r
1214   { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },\r
1215   { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },\r
1216   { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },\r
1217   { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,\r
1218     TRUE },\r
1219   { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,\r
1220     TRUE },\r
1221   { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
1222   { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
1223   { "variant", ArgString, (LPVOID) &appData.variant, FALSE },\r
1224   { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },\r
1225   { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },\r
1226   { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },\r
1227   { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },\r
1228   { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
1229   { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
1230   /* [AS] New features */\r
1231   { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },\r
1232   { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },\r
1233   { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },\r
1234   { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },\r
1235   { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },\r
1236   { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },\r
1237   { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },\r
1238   { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },\r
1239   { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },\r
1240   { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },\r
1241   { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },\r
1242   { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },\r
1243   { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },\r
1244   { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },\r
1245   { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },\r
1246   { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },\r
1247   { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },\r
1248   { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },\r
1249   { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },\r
1250   { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },\r
1251   { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },\r
1252   { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },\r
1253   { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },\r
1254   { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },\r
1255   { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },\r
1256   { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },\r
1257   { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },\r
1258   { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },\r
1259   { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },\r
1260   { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },\r
1261   { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },\r
1262   { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },\r
1263   { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },\r
1264   { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },\r
1265   { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },\r
1266   { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },\r
1267   { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },\r
1268   { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },\r
1269   { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
1270   { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
1271   { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
1272   { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
1273   { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
1274   { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
1275   { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },\r
1276   { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },\r
1277   { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },\r
1278   { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE }, \r
1279   { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },\r
1280   { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },\r
1281 \r
1282   /* [HGM] board-size, adjudication and misc. options */\r
1283   { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },\r
1284   { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },\r
1285   { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },\r
1286   { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },\r
1287   { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },\r
1288   { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },\r
1289   { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },\r
1290   { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },\r
1291   { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },\r
1292   { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },\r
1293   { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },\r
1294   { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },\r
1295   { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },\r
1296   { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },\r
1297   { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },\r
1298   { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },\r
1299   { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },\r
1300   { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },\r
1301   { "userName", ArgString, (LPVOID) &appData.userName, FALSE },\r
1302   { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },\r
1303   { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },\r
1304   { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },\r
1305   { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },\r
1306   { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },\r
1307   { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },\r
1308   { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },\r
1309   { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },\r
1310   { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },\r
1311   { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },\r
1312   { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },\r
1313   { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },\r
1314   { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },\r
1315   { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },\r
1316   { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },\r
1317 \r
1318 #ifdef ZIPPY\r
1319   { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
1320   { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },\r
1321   { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
1322   { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
1323   { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },\r
1324   { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },\r
1325   { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
1326   { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
1327   { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },\r
1328   { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },\r
1329   { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },\r
1330   { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },\r
1331   { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,\r
1332     FALSE },\r
1333   { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },\r
1334   { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },\r
1335   { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },\r
1336   { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
1337   { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
1338   { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },\r
1339   { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,\r
1340     FALSE },\r
1341   { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
1342   { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
1343   { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
1344   { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },\r
1345   { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },\r
1346   { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1347   { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1348   { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1349   { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1350   { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },\r
1351   { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },\r
1352   { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
1353   { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
1354   { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },\r
1355   { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },\r
1356   { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },\r
1357   { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },\r
1358   /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */\r
1359   { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },\r
1360 #endif\r
1361   /* [HGM] options for broadcasting and time odds */\r
1362   { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },\r
1363   { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },\r
1364   { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },\r
1365   { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },\r
1366   { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },\r
1367   { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },\r
1368   { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },\r
1369   { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },\r
1370   { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },\r
1371   { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },\r
1372   { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },\r
1373   { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE },\r
1374   { "wrapContinuationSequence", ArgString, (LPVOID) &appData.wrapContSeq, FALSE },\r
1375   { "useInternalWrap", ArgTrue, (LPVOID) &appData.useInternalWrap, FALSE }, /* noJoin usurps this if set */\r
1376   \r
1377   // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others\r
1378   { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed\r
1379   { "minY", ArgZ, (LPVOID) &minY, FALSE },\r
1380   { "winWidth",  ArgInt, (LPVOID) &wpMain.width,  TRUE }, // [HGM] placement: dummies to remember right & bottom\r
1381   { "winHeight", ArgInt, (LPVOID) &wpMain.height, TRUE }, //       for attaching auxiliary windows to them\r
1382   { "x", ArgInt, (LPVOID) &wpMain.x, TRUE },\r
1383   { "y", ArgInt, (LPVOID) &wpMain.y, TRUE },\r
1384   { "icsX", ArgX,   (LPVOID) &wpConsole.x, TRUE },\r
1385   { "icsY", ArgY,   (LPVOID) &wpConsole.y, TRUE },\r
1386   { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },\r
1387   { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },\r
1388   { "analysisX", ArgX,   (LPVOID) &dummy, FALSE }, // [HGM] placement: analysis window no longer exists\r
1389   { "analysisY", ArgY,   (LPVOID) &dummy, FALSE }, //       provided for compatibility with old ini files\r
1390   { "analysisW", ArgInt, (LPVOID) &dummy, FALSE },\r
1391   { "analysisH", ArgInt, (LPVOID) &dummy, FALSE },\r
1392   { "commentX", ArgX,   (LPVOID) &wpComment.x, TRUE },\r
1393   { "commentY", ArgY,   (LPVOID) &wpComment.y, TRUE },\r
1394   { "commentW", ArgInt, (LPVOID) &wpComment.width, TRUE },\r
1395   { "commentH", ArgInt, (LPVOID) &wpComment.height, TRUE },\r
1396   { "tagsX", ArgX,   (LPVOID) &wpTags.x, TRUE },\r
1397   { "tagsY", ArgY,   (LPVOID) &wpTags.y, TRUE },\r
1398   { "tagsW", ArgInt, (LPVOID) &wpTags.width, TRUE },\r
1399   { "tagsH", ArgInt, (LPVOID) &wpTags.height, TRUE },\r
1400   { "gameListX", ArgX,   (LPVOID) &wpGameList.x, TRUE },\r
1401   { "gameListY", ArgY,   (LPVOID) &wpGameList.y, TRUE },\r
1402   { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },\r
1403   { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },\r
1404   /* [AS] Layout stuff */\r
1405   { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },\r
1406   { "moveHistoryX", ArgX,   (LPVOID) &wpMoveHistory.x, TRUE },\r
1407   { "moveHistoryY", ArgY,   (LPVOID) &wpMoveHistory.y, TRUE },\r
1408   { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },\r
1409   { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },\r
1410 \r
1411   { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },\r
1412   { "evalGraphX", ArgX,   (LPVOID) &wpEvalGraph.x, TRUE },\r
1413   { "evalGraphY", ArgY,   (LPVOID) &wpEvalGraph.y, TRUE },\r
1414   { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },\r
1415   { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },\r
1416 \r
1417   { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },\r
1418   { "engineOutputX", ArgX,   (LPVOID) &wpEngineOutput.x, TRUE },\r
1419   { "engineOutputY", ArgY,   (LPVOID) &wpEngineOutput.y, TRUE },\r
1420   { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },\r
1421   { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },\r
1422 \r
1423   { NULL, ArgNone, NULL, FALSE }\r
1424 };\r
1425 \r
1426 \r
1427 /* Kludge for indirection files on command line */\r
1428 char* lastIndirectionFilename;\r
1429 ArgDescriptor argDescriptorIndirection =\r
1430 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };\r
1431 \r
1432 \r
1433 VOID\r
1434 ExitArgError(char *msg, char *badArg)\r
1435 {\r
1436   char buf[MSG_SIZ];\r
1437 \r
1438   sprintf(buf, "%s %s", msg, badArg);\r
1439   DisplayFatalError(buf, 0, 2);\r
1440   exit(2);\r
1441 }\r
1442 \r
1443 /* Command line font name parser.  NULL name means do nothing.\r
1444    Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"\r
1445    For backward compatibility, syntax without the colon is also\r
1446    accepted, but font names with digits in them won't work in that case.\r
1447 */\r
1448 VOID\r
1449 ParseFontName(char *name, MyFontParams *mfp)\r
1450 {\r
1451   char *p, *q;\r
1452   if (name == NULL) return;\r
1453   p = name;\r
1454   q = strchr(p, ':');\r
1455   if (q) {\r
1456     if (q - p >= sizeof(mfp->faceName))\r
1457       ExitArgError("Font name too long:", name);\r
1458     memcpy(mfp->faceName, p, q - p);\r
1459     mfp->faceName[q - p] = NULLCHAR;\r
1460     p = q + 1;\r
1461   } else {\r
1462     q = mfp->faceName;\r
1463     while (*p && !isdigit(*p)) {\r
1464       *q++ = *p++;\r
1465       if (q - mfp->faceName >= sizeof(mfp->faceName))\r
1466         ExitArgError("Font name too long:", name);\r
1467     }\r
1468     while (q > mfp->faceName && q[-1] == ' ') q--;\r
1469     *q = NULLCHAR;\r
1470   }\r
1471   if (!*p) ExitArgError("Font point size missing:", name);\r
1472   mfp->pointSize = (float) atof(p);\r
1473   mfp->bold = (strchr(p, 'b') != NULL);\r
1474   mfp->italic = (strchr(p, 'i') != NULL);\r
1475   mfp->underline = (strchr(p, 'u') != NULL);\r
1476   mfp->strikeout = (strchr(p, 's') != NULL);\r
1477   mfp->charset = DEFAULT_CHARSET;\r
1478   q = strchr(p, 'c');\r
1479   if (q)\r
1480     mfp->charset = (BYTE) atoi(q+1);\r
1481 }\r
1482 \r
1483 /* Color name parser.\r
1484    X version accepts X color names, but this one\r
1485    handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */\r
1486 COLORREF\r
1487 ParseColorName(char *name)\r
1488 {\r
1489   int red, green, blue, count;\r
1490   char buf[MSG_SIZ];\r
1491 \r
1492   count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);\r
1493   if (count != 3) {\r
1494     count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d", \r
1495       &red, &green, &blue);\r
1496   }\r
1497   if (count != 3) {\r
1498     sprintf(buf, "Can't parse color name %s", name);\r
1499     DisplayError(buf, 0);\r
1500     return RGB(0, 0, 0);\r
1501   }\r
1502   return PALETTERGB(red, green, blue);\r
1503 }\r
1504 \r
1505 \r
1506 void ParseAttribs(COLORREF *color, int *effects, char* argValue)\r
1507 {\r
1508   char *e = argValue;\r
1509   int eff = 0;\r
1510 \r
1511   while (*e) {\r
1512     if (*e == 'b')      eff |= CFE_BOLD;\r
1513     else if (*e == 'i') eff |= CFE_ITALIC;\r
1514     else if (*e == 'u') eff |= CFE_UNDERLINE;\r
1515     else if (*e == 's') eff |= CFE_STRIKEOUT;\r
1516     else if (*e == '#' || isdigit(*e)) break;\r
1517     e++;\r
1518   }\r
1519   *effects = eff;\r
1520   *color   = ParseColorName(e);\r
1521 }\r
1522 \r
1523 \r
1524 BoardSize\r
1525 ParseBoardSize(char *name)\r
1526 {\r
1527   BoardSize bs = SizeTiny;\r
1528   while (sizeInfo[bs].name != NULL) {\r
1529     if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;\r
1530     bs++;\r
1531   }\r
1532   ExitArgError("Unrecognized board size value", name);\r
1533   return bs; /* not reached */\r
1534 }\r
1535 \r
1536 \r
1537 char\r
1538 StringGet(void *getClosure)\r
1539 {\r
1540   char **p = (char **) getClosure;\r
1541   return *((*p)++);\r
1542 }\r
1543 \r
1544 char\r
1545 FileGet(void *getClosure)\r
1546 {\r
1547   int c;\r
1548   FILE* f = (FILE*) getClosure;\r
1549 \r
1550   c = getc(f);\r
1551   if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely\r
1552   if (c == EOF)\r
1553     return NULLCHAR;\r
1554   else\r
1555     return (char) c;\r
1556 }\r
1557 \r
1558 /* Parse settings file named "name". If file found, return the\r
1559    full name in fullname and return TRUE; else return FALSE */\r
1560 BOOLEAN\r
1561 ParseSettingsFile(char *name, char fullname[MSG_SIZ])\r
1562 {\r
1563   char *dummy;\r
1564   FILE *f;\r
1565   int ok; char buf[MSG_SIZ];\r
1566 \r
1567   ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);\r
1568   if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed\r
1569     sprintf(buf, "%s.ini", name);\r
1570     ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);\r
1571   }\r
1572   if (ok) {\r
1573     f = fopen(fullname, "r");\r
1574     if (f != NULL) {\r
1575       ParseArgs(FileGet, f);\r
1576       fclose(f);\r
1577       return TRUE;\r
1578     }\r
1579   }\r
1580   return FALSE;\r
1581 }\r
1582 \r
1583 VOID\r
1584 ParseArgs(GetFunc get, void *cl)\r
1585 {\r
1586   char argName[ARG_MAX];\r
1587   char argValue[ARG_MAX];\r
1588   ArgDescriptor *ad;\r
1589   char start;\r
1590   char *q;\r
1591   int i, octval;\r
1592   char ch;\r
1593   int posarg = 0;\r
1594 \r
1595   ch = get(cl);\r
1596   for (;;) {\r
1597     while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);\r
1598     if (ch == NULLCHAR) break;\r
1599     if (ch == ';') {\r
1600       /* Comment to end of line */\r
1601       ch = get(cl);\r
1602       while (ch != '\n' && ch != NULLCHAR) ch = get(cl);\r
1603       continue;\r
1604     } else if (ch == '/' || ch == '-') {\r
1605       /* Switch */\r
1606       q = argName;\r
1607       while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&\r
1608              ch != '\n' && ch != '\t') {\r
1609         *q++ = ch;\r
1610         ch = get(cl);\r
1611       }\r
1612       *q = NULLCHAR;\r
1613 \r
1614       for (ad = argDescriptors; ad->argName != NULL; ad++)\r
1615         if (strcmp(ad->argName, argName + 1) == 0) break;\r
1616 \r
1617       if (ad->argName == NULL)\r
1618         ExitArgError("Unrecognized argument", argName);\r
1619 \r
1620     } else if (ch == '@') {\r
1621       /* Indirection file */\r
1622       ad = &argDescriptorIndirection;\r
1623       ch = get(cl);\r
1624     } else {\r
1625       /* Positional argument */\r
1626       ad = &argDescriptors[posarg++];\r
1627       strcpy(argName, ad->argName);\r
1628     }\r
1629 \r
1630     if (ad->argType == ArgTrue) {\r
1631       *(Boolean *) ad->argLoc = TRUE;\r
1632       continue;\r
1633     }\r
1634     if (ad->argType == ArgFalse) {\r
1635       *(Boolean *) ad->argLoc = FALSE;\r
1636       continue;\r
1637     }\r
1638 \r
1639     while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);\r
1640     if (ch == NULLCHAR || ch == '\n') {\r
1641       ExitArgError("No value provided for argument", argName);\r
1642     }\r
1643     q = argValue;\r
1644     if (ch == '{') {\r
1645       // Quoting with { }.  No characters have to (or can) be escaped.\r
1646       // Thus the string cannot contain a '}' character.\r
1647       start = ch;\r
1648       ch = get(cl);\r
1649       while (start) {\r
1650         switch (ch) {\r
1651         case NULLCHAR:\r
1652           start = NULLCHAR;\r
1653           break;\r
1654           \r
1655         case '}':\r
1656           ch = get(cl);\r
1657           start = NULLCHAR;\r
1658           break;\r
1659 \r
1660         default:\r
1661           *q++ = ch;\r
1662           ch = get(cl);\r
1663           break;\r
1664         }\r
1665       }   \r
1666     } else if (ch == '\'' || ch == '"') {\r
1667       // Quoting with ' ' or " ", with \ as escape character.\r
1668       // Inconvenient for long strings that may contain Windows filenames.\r
1669       start = ch;\r
1670       ch = get(cl);\r
1671       while (start) {\r
1672         switch (ch) {\r
1673         case NULLCHAR:\r
1674           start = NULLCHAR;\r
1675           break;\r
1676 \r
1677         default:\r
1678         not_special:\r
1679           *q++ = ch;\r
1680           ch = get(cl);\r
1681           break;\r
1682 \r
1683         case '\'':\r
1684         case '\"':\r
1685           if (ch == start) {\r
1686             ch = get(cl);\r
1687             start = NULLCHAR;\r
1688             break;\r
1689           } else {\r
1690             goto not_special;\r
1691           }\r
1692 \r
1693         case '\\':\r
1694           if (ad->argType == ArgFilename\r
1695               || ad->argType == ArgSettingsFilename) {\r
1696               goto not_special;\r
1697           }\r
1698           ch = get(cl);\r
1699           switch (ch) {\r
1700           case NULLCHAR:\r
1701             ExitArgError("Incomplete \\ escape in value for", argName);\r
1702             break;\r
1703           case 'n':\r
1704             *q++ = '\n';\r
1705             ch = get(cl);\r
1706             break;\r
1707           case 'r':\r
1708             *q++ = '\r';\r
1709             ch = get(cl);\r
1710             break;\r
1711           case 't':\r
1712             *q++ = '\t';\r
1713             ch = get(cl);\r
1714             break;\r
1715           case 'b':\r
1716             *q++ = '\b';\r
1717             ch = get(cl);\r
1718             break;\r
1719           case 'f':\r
1720             *q++ = '\f';\r
1721             ch = get(cl);\r
1722             break;\r
1723           default:\r
1724             octval = 0;\r
1725             for (i = 0; i < 3; i++) {\r
1726               if (ch >= '0' && ch <= '7') {\r
1727                 octval = octval*8 + (ch - '0');\r
1728                 ch = get(cl);\r
1729               } else {\r
1730                 break;\r
1731               }\r
1732             }\r
1733             if (i > 0) {\r
1734               *q++ = (char) octval;\r
1735             } else {\r
1736               *q++ = ch;\r
1737               ch = get(cl);\r
1738             }\r
1739             break;\r
1740           }\r
1741           break;\r
1742         }\r
1743       }\r
1744     } else {\r
1745       while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {\r
1746         *q++ = ch;\r
1747         ch = get(cl);\r
1748       }\r
1749     }\r
1750     *q = NULLCHAR;\r
1751 \r
1752     switch (ad->argType) {\r
1753     case ArgInt:\r
1754       *(int *) ad->argLoc = atoi(argValue);\r
1755       break;\r
1756 \r
1757     case ArgX:\r
1758       *(int *) ad->argLoc = atoi(argValue) + wpMain.x; // [HGM] placement: translate stored relative to absolute \r
1759       break;\r
1760 \r
1761     case ArgY:\r
1762       *(int *) ad->argLoc = atoi(argValue) + wpMain.y; // (this is really kludgey, it should be done where used...)\r
1763       break;\r
1764 \r
1765     case ArgZ:\r
1766       *(int *) ad->argLoc = atoi(argValue);\r
1767       EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY); \r
1768       break;\r
1769 \r
1770     case ArgFloat:\r
1771       *(float *) ad->argLoc = (float) atof(argValue);\r
1772       break;\r
1773 \r
1774     case ArgString:\r
1775     case ArgFilename:\r
1776       *(char **) ad->argLoc = strdup(argValue);\r
1777       break;\r
1778 \r
1779     case ArgSettingsFilename:\r
1780       {\r
1781         char fullname[MSG_SIZ];\r
1782         if (ParseSettingsFile(argValue, fullname)) {\r
1783           if (ad->argLoc != NULL) {\r
1784             *(char **) ad->argLoc = strdup(fullname);\r
1785           }\r
1786         } else {\r
1787           if (ad->argLoc != NULL) {\r
1788           } else {\r
1789             ExitArgError("Failed to open indirection file", argValue);\r
1790           }\r
1791         }\r
1792       }\r
1793       break;\r
1794 \r
1795     case ArgBoolean:\r
1796       switch (argValue[0]) {\r
1797       case 't':\r
1798       case 'T':\r
1799         *(Boolean *) ad->argLoc = TRUE;\r
1800         break;\r
1801       case 'f':\r
1802       case 'F':\r
1803         *(Boolean *) ad->argLoc = FALSE;\r
1804         break;\r
1805       default:\r
1806         ExitArgError("Unrecognized boolean argument value", argValue);\r
1807         break;\r
1808       }\r
1809       break;\r
1810 \r
1811     case ArgColor:\r
1812       *(COLORREF *)ad->argLoc = ParseColorName(argValue);\r
1813       break;\r
1814 \r
1815     case ArgAttribs: {\r
1816       ColorClass cc = (ColorClass)ad->argLoc;\r
1817       ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);\r
1818       }\r
1819       break;\r
1820       \r
1821     case ArgBoardSize:\r
1822       *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);\r
1823       break;\r
1824 \r
1825     case ArgFont:\r
1826       ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);\r
1827       break;\r
1828 \r
1829     case ArgCommSettings:\r
1830       ParseCommSettings(argValue, &dcb);\r
1831       break;\r
1832 \r
1833     case ArgNone:\r
1834       ExitArgError("Unrecognized argument", argValue);\r
1835       break;\r
1836     case ArgTrue:\r
1837     case ArgFalse: ;\r
1838     }\r
1839   }\r
1840 }\r
1841 \r
1842 VOID\r
1843 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)\r
1844 {\r
1845   HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);\r
1846   lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);\r
1847   DeleteDC(hdc);\r
1848   lf->lfWidth = 0;\r
1849   lf->lfEscapement = 0;\r
1850   lf->lfOrientation = 0;\r
1851   lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;\r
1852   lf->lfItalic = mfp->italic;\r
1853   lf->lfUnderline = mfp->underline;\r
1854   lf->lfStrikeOut = mfp->strikeout;\r
1855   lf->lfCharSet = mfp->charset;\r
1856   lf->lfOutPrecision = OUT_DEFAULT_PRECIS;\r
1857   lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
1858   lf->lfQuality = DEFAULT_QUALITY;\r
1859   lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;\r
1860   strcpy(lf->lfFaceName, mfp->faceName);\r
1861 }\r
1862 \r
1863 VOID\r
1864 CreateFontInMF(MyFont *mf)\r
1865 {\r
1866   LFfromMFP(&mf->lf, &mf->mfp);\r
1867   if (mf->hf) DeleteObject(mf->hf);\r
1868   mf->hf = CreateFontIndirect(&mf->lf);\r
1869 }\r
1870 \r
1871 VOID\r
1872 SetDefaultTextAttribs()\r
1873 {\r
1874   ColorClass cc;\r
1875   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1876     ParseAttribs(&textAttribs[cc].color, \r
1877                  &textAttribs[cc].effects, \r
1878                  defaultTextAttribs[cc]);\r
1879   }\r
1880 }\r
1881 \r
1882 VOID\r
1883 SetDefaultSounds()\r
1884 {\r
1885   ColorClass cc;\r
1886   SoundClass sc;\r
1887   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1888     textAttribs[cc].sound.name = strdup("");\r
1889     textAttribs[cc].sound.data = NULL;\r
1890   }\r
1891   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
1892     sounds[sc].name = strdup("");\r
1893     sounds[sc].data = NULL;\r
1894   }\r
1895   sounds[(int)SoundBell].name = strdup(SOUND_BELL);\r
1896 }\r
1897 \r
1898 VOID\r
1899 LoadAllSounds()\r
1900 {\r
1901   ColorClass cc;\r
1902   SoundClass sc;\r
1903   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1904     MyLoadSound(&textAttribs[cc].sound);\r
1905   }\r
1906   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
1907     MyLoadSound(&sounds[sc]);\r
1908   }\r
1909 }\r
1910 \r
1911 VOID\r
1912 InitAppData(LPSTR lpCmdLine)\r
1913 {\r
1914   int i, j;\r
1915   char buf[ARG_MAX], currDir[MSG_SIZ];\r
1916   char *dummy, *p;\r
1917 \r
1918   programName = szAppName;\r
1919 \r
1920   /* Initialize to defaults */\r
1921   lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);\r
1922   darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);\r
1923   whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);\r
1924   blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);\r
1925   highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);\r
1926   premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);\r
1927   consoleBackgroundColor = ParseColorName(COLOR_BKGD);\r
1928   SetDefaultTextAttribs();\r
1929   SetDefaultSounds();\r
1930   appData.movesPerSession = MOVES_PER_SESSION;\r
1931   appData.initString = INIT_STRING;\r
1932   appData.secondInitString = INIT_STRING;\r
1933   appData.firstComputerString = COMPUTER_STRING;\r
1934   appData.secondComputerString = COMPUTER_STRING;\r
1935   appData.firstChessProgram = FIRST_CHESS_PROGRAM;\r
1936   appData.secondChessProgram = SECOND_CHESS_PROGRAM;\r
1937   appData.firstPlaysBlack = FALSE;\r
1938   appData.noChessProgram = FALSE;\r
1939   chessProgram = FALSE;\r
1940   appData.firstHost = FIRST_HOST;\r
1941   appData.secondHost = SECOND_HOST;\r
1942   appData.firstDirectory = FIRST_DIRECTORY;\r
1943   appData.secondDirectory = SECOND_DIRECTORY;\r
1944   appData.bitmapDirectory = "";\r
1945   appData.remoteShell = REMOTE_SHELL;\r
1946   appData.remoteUser = "";\r
1947   appData.timeDelay = TIME_DELAY;\r
1948   appData.timeControl = TIME_CONTROL;\r
1949   appData.timeIncrement = TIME_INCREMENT;\r
1950   appData.icsActive = FALSE;\r
1951   appData.icsHost = "";\r
1952   appData.icsPort = ICS_PORT;\r
1953   appData.icsCommPort = ICS_COMM_PORT;\r
1954   appData.icsLogon = ICS_LOGON;\r
1955   appData.icsHelper = "";\r
1956   appData.useTelnet = FALSE;\r
1957   appData.telnetProgram = TELNET_PROGRAM;\r
1958   appData.gateway = "";\r
1959   appData.loadGameFile = "";\r
1960   appData.loadGameIndex = 0;\r
1961   appData.saveGameFile = "";\r
1962   appData.autoSaveGames = FALSE;\r
1963   appData.loadPositionFile = "";\r
1964   appData.loadPositionIndex = 1;\r
1965   appData.savePositionFile = "";\r
1966   appData.matchMode = FALSE;\r
1967   appData.matchGames = 0;\r
1968   appData.monoMode = FALSE;\r
1969   appData.debugMode = FALSE;\r
1970   appData.clockMode = TRUE;\r
1971   boardSize = (BoardSize) -1; /* determine by screen size */\r
1972   appData.Iconic = FALSE; /*unused*/\r
1973   appData.searchTime = "";\r
1974   appData.searchDepth = 0;\r
1975   appData.showCoords = FALSE;\r
1976   appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/\r
1977   appData.autoCallFlag = FALSE;\r
1978   appData.flipView = FALSE;\r
1979   appData.autoFlipView = TRUE;\r
1980   appData.cmailGameName = "";\r
1981   appData.alwaysPromoteToQueen = FALSE;\r
1982   appData.oldSaveStyle = FALSE;\r
1983   appData.quietPlay = FALSE;\r
1984   appData.showThinking = FALSE;\r
1985   appData.ponderNextMove = TRUE;\r
1986   appData.periodicUpdates = TRUE;\r
1987   appData.popupExitMessage = TRUE;\r
1988   appData.popupMoveErrors = FALSE;\r
1989   appData.autoObserve = FALSE;\r
1990   appData.autoComment = FALSE;\r
1991   appData.animate = TRUE;\r
1992   appData.animSpeed = 10;\r
1993   appData.animateDragging = TRUE;\r
1994   appData.highlightLastMove = TRUE;\r
1995   appData.getMoveList = TRUE;\r
1996   appData.testLegality = TRUE;\r
1997   appData.premove = TRUE;\r
1998   appData.premoveWhite = FALSE;\r
1999   appData.premoveWhiteText = "";\r
2000   appData.premoveBlack = FALSE;\r
2001   appData.premoveBlackText = "";\r
2002   appData.icsAlarm = TRUE;\r
2003   appData.icsAlarmTime = 5000;\r
2004   appData.autoRaiseBoard = TRUE;\r
2005   appData.localLineEditing = TRUE;\r
2006   appData.colorize = TRUE;\r
2007   appData.reuseFirst = TRUE;\r
2008   appData.reuseSecond = TRUE;\r
2009   appData.blindfold = FALSE;\r
2010   appData.icsEngineAnalyze = FALSE;\r
2011   memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +\r
2012   dcb.DCBlength = sizeof(DCB);\r
2013   dcb.BaudRate = 9600;\r
2014   dcb.fBinary = TRUE;\r
2015   dcb.fParity = FALSE;\r
2016   dcb.fOutxCtsFlow = FALSE;\r
2017   dcb.fOutxDsrFlow = FALSE;\r
2018   dcb.fDtrControl = DTR_CONTROL_ENABLE;\r
2019   dcb.fDsrSensitivity = FALSE;\r
2020   dcb.fTXContinueOnXoff = TRUE;\r
2021   dcb.fOutX = FALSE;\r
2022   dcb.fInX = FALSE;\r
2023   dcb.fNull = FALSE;\r
2024   dcb.fRtsControl = RTS_CONTROL_ENABLE;\r
2025   dcb.fAbortOnError = FALSE;\r
2026   dcb.ByteSize = 7;\r
2027   dcb.Parity = SPACEPARITY;\r
2028   dcb.StopBits = ONESTOPBIT;\r
2029   settingsFileName = SETTINGS_FILE;\r
2030   saveSettingsOnExit = TRUE;\r
2031   wpMain.x = CW_USEDEFAULT;\r
2032   wpMain.y = CW_USEDEFAULT;\r
2033   wpComment.x = CW_USEDEFAULT; \r
2034   wpComment.y = CW_USEDEFAULT; \r
2035   wpComment.width = CW_USEDEFAULT;\r
2036   wpComment.height = CW_USEDEFAULT;\r
2037   wpTags.x = CW_USEDEFAULT; \r
2038   wpTags.y = CW_USEDEFAULT; \r
2039   wpTags.width = CW_USEDEFAULT;\r
2040   wpTags.height = CW_USEDEFAULT;\r
2041   icsTextMenuString = ICS_TEXT_MENU_DEFAULT;\r
2042   icsNames = ICS_NAMES;\r
2043   firstChessProgramNames = FCP_NAMES;\r
2044   secondChessProgramNames = SCP_NAMES;\r
2045   appData.initialMode = "";\r
2046   appData.variant = "normal";\r
2047   appData.firstProtocolVersion = PROTOVER;\r
2048   appData.secondProtocolVersion = PROTOVER;\r
2049   appData.showButtonBar = TRUE;\r
2050 \r
2051    /* [AS] New properties (see comments in header file) */\r
2052   appData.firstScoreIsAbsolute = FALSE;\r
2053   appData.secondScoreIsAbsolute = FALSE;\r
2054   appData.saveExtendedInfoInPGN = FALSE;\r
2055   appData.hideThinkingFromHuman = FALSE;\r
2056   appData.liteBackTextureFile = "";\r
2057   appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
2058   appData.darkBackTextureFile = "";\r
2059   appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
2060   appData.renderPiecesWithFont = "";\r
2061   appData.fontToPieceTable = "";\r
2062   appData.fontBackColorWhite = 0;\r
2063   appData.fontForeColorWhite = 0;\r
2064   appData.fontBackColorBlack = 0;\r
2065   appData.fontForeColorBlack = 0;\r
2066   appData.fontPieceSize = 80;\r
2067   appData.overrideLineGap = 1;\r
2068   appData.adjudicateLossThreshold = 0;\r
2069   appData.delayBeforeQuit = 0;\r
2070   appData.delayAfterQuit = 0;\r
2071   appData.nameOfDebugFile = "winboard.debug";\r
2072   appData.pgnEventHeader = "Computer Chess Game";\r
2073   appData.defaultFrcPosition = -1;\r
2074   appData.gameListTags = GLT_DEFAULT_TAGS;\r
2075   appData.saveOutOfBookInfo = TRUE;\r
2076   appData.showEvalInMoveHistory = TRUE;\r
2077   appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );\r
2078   appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );\r
2079   appData.highlightMoveWithArrow = FALSE;\r
2080   appData.highlightArrowColor = ParseColorName( "#FFFF80" );\r
2081   appData.useStickyWindows = TRUE;\r
2082   appData.adjudicateDrawMoves = 0;\r
2083   appData.autoDisplayComment = TRUE;\r
2084   appData.autoDisplayTags = TRUE;\r
2085   appData.firstIsUCI = FALSE;\r
2086   appData.secondIsUCI = FALSE;\r
2087   appData.firstHasOwnBookUCI = TRUE;\r
2088   appData.secondHasOwnBookUCI = TRUE;\r
2089   appData.polyglotDir = "";\r
2090   appData.usePolyglotBook = FALSE;\r
2091   appData.polyglotBook = "";\r
2092   appData.defaultHashSize = 64;\r
2093   appData.defaultCacheSizeEGTB = 4;\r
2094   appData.defaultPathEGTB = "c:\\egtb";\r
2095   appData.firstOptions = "";\r
2096   appData.secondOptions = "";\r
2097 \r
2098   InitWindowPlacement( &wpGameList );\r
2099   InitWindowPlacement( &wpMoveHistory );\r
2100   InitWindowPlacement( &wpEvalGraph );\r
2101   InitWindowPlacement( &wpEngineOutput );\r
2102   InitWindowPlacement( &wpConsole );\r
2103 \r
2104   /* [HGM] User-selectable board size, adjudication control, miscellaneous */\r
2105   appData.NrFiles      = -1;\r
2106   appData.NrRanks      = -1;\r
2107   appData.holdingsSize = -1;\r
2108   appData.testClaims   = FALSE;\r
2109   appData.checkMates   = FALSE;\r
2110   appData.materialDraws= FALSE;\r
2111   appData.trivialDraws = FALSE;\r
2112   appData.ruleMoves    = 51;\r
2113   appData.drawRepeats  = 6;\r
2114   appData.matchPause   = 10000;\r
2115   appData.alphaRank    = FALSE;\r
2116   appData.allWhite     = FALSE;\r
2117   appData.upsideDown   = FALSE;\r
2118   appData.serverPause  = 15;\r
2119   appData.serverMovesName   = NULL;\r
2120   appData.suppressLoadMoves = FALSE;\r
2121   appData.firstTimeOdds  = 1;\r
2122   appData.secondTimeOdds = 1;\r
2123   appData.firstAccumulateTC  = 1; // combine previous and current sessions\r
2124   appData.secondAccumulateTC = 1;\r
2125   appData.firstNPS  = -1; // [HGM] nps: use wall-clock time\r
2126   appData.secondNPS = -1;\r
2127   appData.engineComments = 1;\r
2128   appData.smpCores = 1; // [HGM] SMP: max nr of cores\r
2129   appData.egtFormats = "";\r
2130 \r
2131 #ifdef ZIPPY\r
2132   appData.zippyTalk = ZIPPY_TALK;\r
2133   appData.zippyPlay = ZIPPY_PLAY;\r
2134   appData.zippyLines = ZIPPY_LINES;\r
2135   appData.zippyPinhead = ZIPPY_PINHEAD;\r
2136   appData.zippyPassword = ZIPPY_PASSWORD;\r
2137   appData.zippyPassword2 = ZIPPY_PASSWORD2;\r
2138   appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;\r
2139   appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;\r
2140   appData.zippyUseI = ZIPPY_USE_I;\r
2141   appData.zippyBughouse = ZIPPY_BUGHOUSE;\r
2142   appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;\r
2143   appData.zippyGameEnd = ZIPPY_GAME_END;\r
2144   appData.zippyGameStart = ZIPPY_GAME_START;\r
2145   appData.zippyAdjourn = ZIPPY_ADJOURN;\r
2146   appData.zippyAbort = ZIPPY_ABORT;\r
2147   appData.zippyVariants = ZIPPY_VARIANTS;\r
2148   appData.zippyMaxGames = ZIPPY_MAX_GAMES;\r
2149   appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;\r
2150 #endif\r
2151 \r
2152   /* Point font array elements to structures and\r
2153      parse default font names */\r
2154   for (i=0; i<NUM_FONTS; i++) {\r
2155     for (j=0; j<NUM_SIZES; j++) {\r
2156       font[j][i] = &fontRec[j][i];\r
2157       ParseFontName(font[j][i]->def, &font[j][i]->mfp);\r
2158     }\r
2159   }\r
2160   \r
2161   /* Parse default settings file if any */\r
2162   if (ParseSettingsFile(settingsFileName, buf)) {\r
2163     settingsFileName = strdup(buf);\r
2164   }\r
2165 \r
2166   /* Parse command line */\r
2167   ParseArgs(StringGet, &lpCmdLine);\r
2168 \r
2169   /* [HGM] make sure board size is acceptable */\r
2170   if(appData.NrFiles > BOARD_FILES ||\r
2171      appData.NrRanks > BOARD_RANKS   )\r
2172       DisplayFatalError("Recompile with BOARD_RANKS or BOARD_FILES, to support this size", 0, 2);\r
2173 \r
2174   /* [HGM] After parsing the options from the .ini file, and overruling them\r
2175    * with options from the command line, we now make an even higher priority\r
2176    * overrule by WB options attached to the engine command line. This so that\r
2177    * tournament managers can use WB options (such as /timeOdds) that follow\r
2178    * the engines.\r
2179    */\r
2180   if(appData.firstChessProgram != NULL) {\r
2181       char *p = StrStr(appData.firstChessProgram, "WBopt");\r
2182       static char *f = "first";\r
2183       char buf[MSG_SIZ], *q = buf;\r
2184       if(p != NULL) { // engine command line contains WinBoard options\r
2185           sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"\r
2186           ParseArgs(StringGet, &q);\r
2187           p[-1] = 0; // cut them offengine command line\r
2188       }\r
2189   }\r
2190   // now do same for second chess program\r
2191   if(appData.secondChessProgram != NULL) {\r
2192       char *p = StrStr(appData.secondChessProgram, "WBopt");\r
2193       static char *s = "second";\r
2194       char buf[MSG_SIZ], *q = buf;\r
2195       if(p != NULL) { // engine command line contains WinBoard options\r
2196           sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"\r
2197           ParseArgs(StringGet, &q);\r
2198           p[-1] = 0; // cut them offengine command line\r
2199       }\r
2200   }\r
2201 \r
2202 \r
2203   /* Propagate options that affect others */\r
2204   if (appData.matchMode || appData.matchGames) chessProgram = TRUE;\r
2205   if (appData.icsActive || appData.noChessProgram) {\r
2206      chessProgram = FALSE;  /* not local chess program mode */\r
2207   }\r
2208 \r
2209   /* Open startup dialog if needed */\r
2210   if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||\r
2211       (appData.icsActive && *appData.icsHost == NULLCHAR) ||\r
2212       (chessProgram && (*appData.firstChessProgram == NULLCHAR ||\r
2213                         *appData.secondChessProgram == NULLCHAR))) {\r
2214     FARPROC lpProc;\r
2215     \r
2216     lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);\r
2217     DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);\r
2218     FreeProcInstance(lpProc);\r
2219   }\r
2220 \r
2221   /* Make sure save files land in the right (?) directory */\r
2222   if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {\r
2223     appData.saveGameFile = strdup(buf);\r
2224   }\r
2225   if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {\r
2226     appData.savePositionFile = strdup(buf);\r
2227   }\r
2228 \r
2229   /* Finish initialization for fonts and sounds */\r
2230   for (i=0; i<NUM_FONTS; i++) {\r
2231     for (j=0; j<NUM_SIZES; j++) {\r
2232       CreateFontInMF(font[j][i]);\r
2233     }\r
2234   }\r
2235   /* xboard, and older WinBoards, controlled the move sound with the\r
2236      appData.ringBellAfterMoves option.  In the current WinBoard, we\r
2237      always turn the option on (so that the backend will call us),\r
2238      then let the user turn the sound off by setting it to silence if\r
2239      desired.  To accommodate old winboard.ini files saved by old\r
2240      versions of WinBoard, we also turn off the sound if the option\r
2241      was initially set to false. */\r
2242   if (!appData.ringBellAfterMoves) {\r
2243     sounds[(int)SoundMove].name = strdup("");\r
2244     appData.ringBellAfterMoves = TRUE;\r
2245   }\r
2246   GetCurrentDirectory(MSG_SIZ, currDir);\r
2247   SetCurrentDirectory(installDir);\r
2248   LoadAllSounds();\r
2249   SetCurrentDirectory(currDir);\r
2250 \r
2251   p = icsTextMenuString;\r
2252   if (p[0] == '@') {\r
2253     FILE* f = fopen(p + 1, "r");\r
2254     if (f == NULL) {\r
2255       DisplayFatalError(p + 1, errno, 2);\r
2256       return;\r
2257     }\r
2258     i = fread(buf, 1, sizeof(buf)-1, f);\r
2259     fclose(f);\r
2260     buf[i] = NULLCHAR;\r
2261     p = buf;\r
2262   }\r
2263   ParseIcsTextMenu(strdup(p));\r
2264 }\r
2265 \r
2266 \r
2267 VOID\r
2268 InitMenuChecks()\r
2269 {\r
2270   HMENU hmenu = GetMenu(hwndMain);\r
2271 \r
2272   (void) EnableMenuItem(hmenu, IDM_CommPort,\r
2273                         MF_BYCOMMAND|((appData.icsActive &&\r
2274                                        *appData.icsCommPort != NULLCHAR) ?\r
2275                                       MF_ENABLED : MF_GRAYED));\r
2276   (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,\r
2277                        MF_BYCOMMAND|(saveSettingsOnExit ?\r
2278                                      MF_CHECKED : MF_UNCHECKED));\r
2279 }\r
2280 \r
2281 // [HGM] args: these two cases taken out to stay in front-end\r
2282       void SaveFontArg(FILE *f, ArgDescriptor *ad)\r
2283       {\r
2284         int bs;\r
2285         for (bs=0; bs<NUM_SIZES; bs++) {\r
2286           MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;\r
2287           fprintf(f, "/size=%s ", sizeInfo[bs].name);\r
2288           fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",\r
2289             ad->argName, mfp->faceName, mfp->pointSize,\r
2290             mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",\r
2291             mfp->bold ? "b" : "",\r
2292             mfp->italic ? "i" : "",\r
2293             mfp->underline ? "u" : "",\r
2294             mfp->strikeout ? "s" : "",\r
2295             (int)mfp->charset);\r
2296         }\r
2297       }\r
2298 \r
2299       void SaveAttribsArg(FILE *f, ArgDescriptor *ad)\r
2300       {\r
2301         MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];\r
2302         fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,\r
2303           (ta->effects & CFE_BOLD) ? "b" : "",\r
2304           (ta->effects & CFE_ITALIC) ? "i" : "",\r
2305           (ta->effects & CFE_UNDERLINE) ? "u" : "",\r
2306           (ta->effects & CFE_STRIKEOUT) ? "s" : "",\r
2307           (ta->effects) ? " " : "",\r
2308           ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);\r
2309       }\r
2310 \r
2311 int MainWindowUp()\r
2312 { // [HGM] args: allows testing if main window is realized from back-end\r
2313   return hwndMain != NULL;\r
2314 }\r
2315 \r
2316 VOID\r
2317 SaveSettings(char* name)\r
2318 {\r
2319   FILE *f;\r
2320   ArgDescriptor *ad;\r
2321   char dir[MSG_SIZ];\r
2322 \r
2323   if (!MainWindowUp()) return;\r
2324 \r
2325   GetCurrentDirectory(MSG_SIZ, dir);\r
2326   SetCurrentDirectory(installDir);\r
2327   f = fopen(name, "w");\r
2328   SetCurrentDirectory(dir);\r
2329   if (f == NULL) {\r
2330     DisplayError(name, errno);\r
2331     return;\r
2332   }\r
2333   fprintf(f, ";\n");\r
2334   fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);\r
2335   fprintf(f, ";\n");\r
2336   fprintf(f, "; You can edit the values of options that are already set in this file,\n");\r
2337   fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");\r
2338   fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");\r
2339   fprintf(f, ";\n");\r
2340 \r
2341   GetActualPlacement(hwndMain, &wpMain);\r
2342   GetActualPlacement(hwndConsole, &wpConsole);\r
2343   GetActualPlacement(commentDialog, &wpComment);\r
2344   GetActualPlacement(editTagsDialog, &wpTags);\r
2345   GetActualPlacement(gameListDialog, &wpGameList);\r
2346 \r
2347   /* [AS] Move history */\r
2348   wpMoveHistory.visible = MoveHistoryIsUp();\r
2349   GetActualPlacement(moveHistoryDialog, &wpMoveHistory);\r
2350 \r
2351   /* [AS] Eval graph */\r
2352   wpEvalGraph.visible = EvalGraphIsUp();\r
2353   GetActualPlacement(evalGraphDialog, &wpEvalGraph);\r
2354 \r
2355   /* [AS] Engine output */\r
2356   wpEngineOutput.visible = EngineOutputIsUp();\r
2357   GetActualPlacement(engineOutputDialog, &wpEngineOutput);\r
2358 \r
2359   for (ad = argDescriptors; ad->argName != NULL; ad++) {\r
2360     if (!ad->save) continue;\r
2361     switch (ad->argType) {\r
2362     case ArgString:\r
2363       {\r
2364         char *p = *(char **)ad->argLoc;\r
2365         if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {\r
2366           /* Quote multiline values or \-containing values\r
2367              with { } if possible */\r
2368           fprintf(f, "/%s={%s}\n", ad->argName, p);\r
2369         } else {\r
2370           /* Else quote with " " */\r
2371           fprintf(f, "/%s=\"", ad->argName);\r
2372           while (*p) {\r
2373             if (*p == '\n') fprintf(f, "\n");\r
2374             else if (*p == '\r') fprintf(f, "\\r");\r
2375             else if (*p == '\t') fprintf(f, "\\t");\r
2376             else if (*p == '\b') fprintf(f, "\\b");\r
2377             else if (*p == '\f') fprintf(f, "\\f");\r
2378             else if (*p < ' ') fprintf(f, "\\%03o", *p);\r
2379             else if (*p == '\"') fprintf(f, "\\\"");\r
2380             else if (*p == '\\') fprintf(f, "\\\\");\r
2381             else putc(*p, f);\r
2382             p++;\r
2383           }\r
2384           fprintf(f, "\"\n");\r
2385         }\r
2386       }\r
2387       break;\r
2388     case ArgInt:\r
2389     case ArgZ:\r
2390       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);\r
2391       break;\r
2392     case ArgX:\r
2393       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - wpMain.x); // [HGM] placement: stor relative value\r
2394       break;\r
2395     case ArgY:\r
2396       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - wpMain.y);\r
2397       break;\r
2398     case ArgFloat:\r
2399       fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);\r
2400       break;\r
2401     case ArgBoolean:\r
2402       fprintf(f, "/%s=%s\n", ad->argName, \r
2403         (*(Boolean *)ad->argLoc) ? "true" : "false");\r
2404       break;\r
2405     case ArgTrue:\r
2406       if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
2407       break;\r
2408     case ArgFalse:\r
2409       if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
2410       break;\r
2411     case ArgColor:\r
2412       {\r
2413         COLORREF color = *(COLORREF *)ad->argLoc;\r
2414         fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName, \r
2415           color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
2416       }\r
2417       break;\r
2418     case ArgAttribs:\r
2419       SaveAttribsArg(f, ad);\r
2420       break;\r
2421     case ArgFilename:\r
2422       if (strchr(*(char **)ad->argLoc, '\"')) {\r
2423         fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);\r
2424       } else {\r
2425         fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);\r
2426       }\r
2427       break;\r
2428     case ArgBoardSize:\r
2429       fprintf(f, "/%s=%s\n", ad->argName,\r
2430               sizeInfo[*(BoardSize *)ad->argLoc].name);\r
2431       break;\r
2432     case ArgFont:\r
2433       SaveFontArg(f, ad);\r
2434       break;\r
2435     case ArgCommSettings:\r
2436       PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);\r
2437     case ArgNone:\r
2438     case ArgSettingsFilename: ;\r
2439     }\r
2440   }\r
2441   fclose(f);\r
2442 }\r
2443 \r
2444 \r
2445 \r
2446 /*---------------------------------------------------------------------------*\\r
2447  *\r
2448  * GDI board drawing routines\r
2449  *\r
2450 \*---------------------------------------------------------------------------*/\r
2451 \r
2452 /* [AS] Draw square using background texture */\r
2453 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )\r
2454 {\r
2455     XFORM   x;\r
2456 \r
2457     if( mode == 0 ) {\r
2458         return; /* Should never happen! */\r
2459     }\r
2460 \r
2461     SetGraphicsMode( dst, GM_ADVANCED );\r
2462 \r
2463     switch( mode ) {\r
2464     case 1:\r
2465         /* Identity */\r
2466         break;\r
2467     case 2:\r
2468         /* X reflection */\r
2469         x.eM11 = -1.0;\r
2470         x.eM12 = 0;\r
2471         x.eM21 = 0;\r
2472         x.eM22 = 1.0;\r
2473         x.eDx = (FLOAT) dw + dx - 1;\r
2474         x.eDy = 0;\r
2475         dx = 0;\r
2476         SetWorldTransform( dst, &x );\r
2477         break;\r
2478     case 3:\r
2479         /* Y reflection */\r
2480         x.eM11 = 1.0;\r
2481         x.eM12 = 0;\r
2482         x.eM21 = 0;\r
2483         x.eM22 = -1.0;\r
2484         x.eDx = 0;\r
2485         x.eDy = (FLOAT) dh + dy - 1;\r
2486         dy = 0;\r
2487         SetWorldTransform( dst, &x );\r
2488         break;\r
2489     case 4:\r
2490         /* X/Y flip */\r
2491         x.eM11 = 0;\r
2492         x.eM12 = 1.0;\r
2493         x.eM21 = 1.0;\r
2494         x.eM22 = 0;\r
2495         x.eDx = (FLOAT) dx;\r
2496         x.eDy = (FLOAT) dy;\r
2497         dx = 0;\r
2498         dy = 0;\r
2499         SetWorldTransform( dst, &x );\r
2500         break;\r
2501     }\r
2502 \r
2503     BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );\r
2504 \r
2505     x.eM11 = 1.0;\r
2506     x.eM12 = 0;\r
2507     x.eM21 = 0;\r
2508     x.eM22 = 1.0;\r
2509     x.eDx = 0;\r
2510     x.eDy = 0;\r
2511     SetWorldTransform( dst, &x );\r
2512 \r
2513     ModifyWorldTransform( dst, 0, MWT_IDENTITY );\r
2514 }\r
2515 \r
2516 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */\r
2517 enum {\r
2518     PM_WP = (int) WhitePawn, \r
2519     PM_WN = (int) WhiteKnight, \r
2520     PM_WB = (int) WhiteBishop, \r
2521     PM_WR = (int) WhiteRook, \r
2522     PM_WQ = (int) WhiteQueen, \r
2523     PM_WF = (int) WhiteFerz, \r
2524     PM_WW = (int) WhiteWazir, \r
2525     PM_WE = (int) WhiteAlfil, \r
2526     PM_WM = (int) WhiteMan, \r
2527     PM_WO = (int) WhiteCannon, \r
2528     PM_WU = (int) WhiteUnicorn, \r
2529     PM_WH = (int) WhiteNightrider, \r
2530     PM_WA = (int) WhiteAngel, \r
2531     PM_WC = (int) WhiteMarshall, \r
2532     PM_WAB = (int) WhiteCardinal, \r
2533     PM_WD = (int) WhiteDragon, \r
2534     PM_WL = (int) WhiteLance, \r
2535     PM_WS = (int) WhiteCobra, \r
2536     PM_WV = (int) WhiteFalcon, \r
2537     PM_WSG = (int) WhiteSilver, \r
2538     PM_WG = (int) WhiteGrasshopper, \r
2539     PM_WK = (int) WhiteKing,\r
2540     PM_BP = (int) BlackPawn, \r
2541     PM_BN = (int) BlackKnight, \r
2542     PM_BB = (int) BlackBishop, \r
2543     PM_BR = (int) BlackRook, \r
2544     PM_BQ = (int) BlackQueen, \r
2545     PM_BF = (int) BlackFerz, \r
2546     PM_BW = (int) BlackWazir, \r
2547     PM_BE = (int) BlackAlfil, \r
2548     PM_BM = (int) BlackMan,\r
2549     PM_BO = (int) BlackCannon, \r
2550     PM_BU = (int) BlackUnicorn, \r
2551     PM_BH = (int) BlackNightrider, \r
2552     PM_BA = (int) BlackAngel, \r
2553     PM_BC = (int) BlackMarshall, \r
2554     PM_BG = (int) BlackGrasshopper, \r
2555     PM_BAB = (int) BlackCardinal,\r
2556     PM_BD = (int) BlackDragon,\r
2557     PM_BL = (int) BlackLance,\r
2558     PM_BS = (int) BlackCobra,\r
2559     PM_BV = (int) BlackFalcon,\r
2560     PM_BSG = (int) BlackSilver,\r
2561     PM_BK = (int) BlackKing\r
2562 };\r
2563 \r
2564 static HFONT hPieceFont = NULL;\r
2565 static HBITMAP hPieceMask[(int) EmptySquare];\r
2566 static HBITMAP hPieceFace[(int) EmptySquare];\r
2567 static int fontBitmapSquareSize = 0;\r
2568 static char pieceToFontChar[(int) EmptySquare] =\r
2569                               { 'p', 'n', 'b', 'r', 'q', \r
2570                       'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',\r
2571                       'k', 'o', 'm', 'v', 't', 'w', \r
2572                       'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',\r
2573                                                               'l' };\r
2574 \r
2575 extern BOOL SetCharTable( char *table, const char * map );\r
2576 /* [HGM] moved to backend.c */\r
2577 \r
2578 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )\r
2579 {\r
2580     HBRUSH hbrush;\r
2581     BYTE r1 = GetRValue( color );\r
2582     BYTE g1 = GetGValue( color );\r
2583     BYTE b1 = GetBValue( color );\r
2584     BYTE r2 = r1 / 2;\r
2585     BYTE g2 = g1 / 2;\r
2586     BYTE b2 = b1 / 2;\r
2587     RECT rc;\r
2588 \r
2589     /* Create a uniform background first */\r
2590     hbrush = CreateSolidBrush( color );\r
2591     SetRect( &rc, 0, 0, squareSize, squareSize );\r
2592     FillRect( hdc, &rc, hbrush );\r
2593     DeleteObject( hbrush );\r
2594     \r
2595     if( mode == 1 ) {\r
2596         /* Vertical gradient, good for pawn, knight and rook, less for queen and king */\r
2597         int steps = squareSize / 2;\r
2598         int i;\r
2599 \r
2600         for( i=0; i<steps; i++ ) {\r
2601             BYTE r = r1 - (r1-r2) * i / steps;\r
2602             BYTE g = g1 - (g1-g2) * i / steps;\r
2603             BYTE b = b1 - (b1-b2) * i / steps;\r
2604 \r
2605             hbrush = CreateSolidBrush( RGB(r,g,b) );\r
2606             SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );\r
2607             FillRect( hdc, &rc, hbrush );\r
2608             DeleteObject(hbrush);\r
2609         }\r
2610     }\r
2611     else if( mode == 2 ) {\r
2612         /* Diagonal gradient, good more or less for every piece */\r
2613         POINT triangle[3];\r
2614         HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );\r
2615         HBRUSH hbrush_old;\r
2616         int steps = squareSize;\r
2617         int i;\r
2618 \r
2619         triangle[0].x = squareSize - steps;\r
2620         triangle[0].y = squareSize;\r
2621         triangle[1].x = squareSize;\r
2622         triangle[1].y = squareSize;\r
2623         triangle[2].x = squareSize;\r
2624         triangle[2].y = squareSize - steps;\r
2625 \r
2626         for( i=0; i<steps; i++ ) {\r
2627             BYTE r = r1 - (r1-r2) * i / steps;\r
2628             BYTE g = g1 - (g1-g2) * i / steps;\r
2629             BYTE b = b1 - (b1-b2) * i / steps;\r
2630 \r
2631             hbrush = CreateSolidBrush( RGB(r,g,b) );\r
2632             hbrush_old = SelectObject( hdc, hbrush );\r
2633             Polygon( hdc, triangle, 3 );\r
2634             SelectObject( hdc, hbrush_old );\r
2635             DeleteObject(hbrush);\r
2636             triangle[0].x++;\r
2637             triangle[2].y++;\r
2638         }\r
2639 \r
2640         SelectObject( hdc, hpen );\r
2641     }\r
2642 }\r
2643 \r
2644 /*\r
2645     [AS] The method I use to create the bitmaps it a bit tricky, but it\r
2646     seems to work ok. The main problem here is to find the "inside" of a chess\r
2647     piece: follow the steps as explained below.\r
2648 */\r
2649 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )\r
2650 {\r
2651     HBITMAP hbm;\r
2652     HBITMAP hbm_old;\r
2653     COLORREF chroma = RGB(0xFF,0x00,0xFF);\r
2654     RECT rc;\r
2655     SIZE sz;\r
2656     POINT pt;\r
2657     int backColor = whitePieceColor; \r
2658     int foreColor = blackPieceColor;\r
2659     \r
2660     if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {\r
2661         backColor = appData.fontBackColorWhite;\r
2662         foreColor = appData.fontForeColorWhite;\r
2663     }\r
2664     else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {\r
2665         backColor = appData.fontBackColorBlack;\r
2666         foreColor = appData.fontForeColorBlack;\r
2667     }\r
2668 \r
2669     /* Mask */\r
2670     hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2671 \r
2672     hbm_old = SelectObject( hdc, hbm );\r
2673 \r
2674     rc.left = 0;\r
2675     rc.top = 0;\r
2676     rc.right = squareSize;\r
2677     rc.bottom = squareSize;\r
2678 \r
2679     /* Step 1: background is now black */\r
2680     FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );\r
2681 \r
2682     GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );\r
2683 \r
2684     pt.x = (squareSize - sz.cx) / 2;\r
2685     pt.y = (squareSize - sz.cy) / 2;\r
2686 \r
2687     SetBkMode( hdc, TRANSPARENT );\r
2688     SetTextColor( hdc, chroma );\r
2689     /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */\r
2690     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2691 \r
2692     SelectObject( hdc, GetStockObject(WHITE_BRUSH) );\r
2693     /* Step 3: the area outside the piece is filled with white */\r
2694 //    FloodFill( hdc, 0, 0, chroma );\r
2695     ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );\r
2696     ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big\r
2697     ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );\r
2698     ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );\r
2699     SelectObject( hdc, GetStockObject(BLACK_BRUSH) );\r
2700     /* \r
2701         Step 4: this is the tricky part, the area inside the piece is filled with black,\r
2702         but if the start point is not inside the piece we're lost!\r
2703         There should be a better way to do this... if we could create a region or path\r
2704         from the fill operation we would be fine for example.\r
2705     */\r
2706 //    FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );\r
2707     ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );\r
2708 \r
2709     {   /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */\r
2710         HDC dc2 = CreateCompatibleDC( hdc_window );\r
2711         HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2712 \r
2713         SelectObject( dc2, bm2 );\r
2714         BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy\r
2715         BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2716         BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2717         BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2718         BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2719 \r
2720         DeleteDC( dc2 );\r
2721         DeleteObject( bm2 );\r
2722     }\r
2723 \r
2724     SetTextColor( hdc, 0 );\r
2725     /* \r
2726         Step 5: some fonts have "disconnected" areas that are skipped by the fill:\r
2727         draw the piece again in black for safety.\r
2728     */\r
2729     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2730 \r
2731     SelectObject( hdc, hbm_old );\r
2732 \r
2733     if( hPieceMask[index] != NULL ) {\r
2734         DeleteObject( hPieceMask[index] );\r
2735     }\r
2736 \r
2737     hPieceMask[index] = hbm;\r
2738 \r
2739     /* Face */\r
2740     hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2741 \r
2742     SelectObject( hdc, hbm );\r
2743 \r
2744     {\r
2745         HDC dc1 = CreateCompatibleDC( hdc_window );\r
2746         HDC dc2 = CreateCompatibleDC( hdc_window );\r
2747         HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2748 \r
2749         SelectObject( dc1, hPieceMask[index] );\r
2750         SelectObject( dc2, bm2 );\r
2751         FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );\r
2752         BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );\r
2753         \r
2754         /* \r
2755             Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves\r
2756             the piece background and deletes (makes transparent) the rest.\r
2757             Thanks to that mask, we are free to paint the background with the greates\r
2758             freedom, as we'll be able to mask off the unwanted parts when finished.\r
2759             We use this, to make gradients and give the pieces a "roundish" look.\r
2760         */\r
2761         SetPieceBackground( hdc, backColor, 2 );\r
2762         BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );\r
2763 \r
2764         DeleteDC( dc2 );\r
2765         DeleteDC( dc1 );\r
2766         DeleteObject( bm2 );\r
2767     }\r
2768 \r
2769     SetTextColor( hdc, foreColor );\r
2770     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2771 \r
2772     SelectObject( hdc, hbm_old );\r
2773 \r
2774     if( hPieceFace[index] != NULL ) {\r
2775         DeleteObject( hPieceFace[index] );\r
2776     }\r
2777 \r
2778     hPieceFace[index] = hbm;\r
2779 }\r
2780 \r
2781 static int TranslatePieceToFontPiece( int piece )\r
2782 {\r
2783     switch( piece ) {\r
2784     case BlackPawn:\r
2785         return PM_BP;\r
2786     case BlackKnight:\r
2787         return PM_BN;\r
2788     case BlackBishop:\r
2789         return PM_BB;\r
2790     case BlackRook:\r
2791         return PM_BR;\r
2792     case BlackQueen:\r
2793         return PM_BQ;\r
2794     case BlackKing:\r
2795         return PM_BK;\r
2796     case WhitePawn:\r
2797         return PM_WP;\r
2798     case WhiteKnight:\r
2799         return PM_WN;\r
2800     case WhiteBishop:\r
2801         return PM_WB;\r
2802     case WhiteRook:\r
2803         return PM_WR;\r
2804     case WhiteQueen:\r
2805         return PM_WQ;\r
2806     case WhiteKing:\r
2807         return PM_WK;\r
2808 \r
2809     case BlackAngel:\r
2810         return PM_BA;\r
2811     case BlackMarshall:\r
2812         return PM_BC;\r
2813     case BlackFerz:\r
2814         return PM_BF;\r
2815     case BlackNightrider:\r
2816         return PM_BH;\r
2817     case BlackAlfil:\r
2818         return PM_BE;\r
2819     case BlackWazir:\r
2820         return PM_BW;\r
2821     case BlackUnicorn:\r
2822         return PM_BU;\r
2823     case BlackCannon:\r
2824         return PM_BO;\r
2825     case BlackGrasshopper:\r
2826         return PM_BG;\r
2827     case BlackMan:\r
2828         return PM_BM;\r
2829     case BlackSilver:\r
2830         return PM_BSG;\r
2831     case BlackLance:\r
2832         return PM_BL;\r
2833     case BlackFalcon:\r
2834         return PM_BV;\r
2835     case BlackCobra:\r
2836         return PM_BS;\r
2837     case BlackCardinal:\r
2838         return PM_BAB;\r
2839     case BlackDragon:\r
2840         return PM_BD;\r
2841 \r
2842     case WhiteAngel:\r
2843         return PM_WA;\r
2844     case WhiteMarshall:\r
2845         return PM_WC;\r
2846     case WhiteFerz:\r
2847         return PM_WF;\r
2848     case WhiteNightrider:\r
2849         return PM_WH;\r
2850     case WhiteAlfil:\r
2851         return PM_WE;\r
2852     case WhiteWazir:\r
2853         return PM_WW;\r
2854     case WhiteUnicorn:\r
2855         return PM_WU;\r
2856     case WhiteCannon:\r
2857         return PM_WO;\r
2858     case WhiteGrasshopper:\r
2859         return PM_WG;\r
2860     case WhiteMan:\r
2861         return PM_WM;\r
2862     case WhiteSilver:\r
2863         return PM_WSG;\r
2864     case WhiteLance:\r
2865         return PM_WL;\r
2866     case WhiteFalcon:\r
2867         return PM_WV;\r
2868     case WhiteCobra:\r
2869         return PM_WS;\r
2870     case WhiteCardinal:\r
2871         return PM_WAB;\r
2872     case WhiteDragon:\r
2873         return PM_WD;\r
2874     }\r
2875 \r
2876     return 0;\r
2877 }\r
2878 \r
2879 void CreatePiecesFromFont()\r
2880 {\r
2881     LOGFONT lf;\r
2882     HDC hdc_window = NULL;\r
2883     HDC hdc = NULL;\r
2884     HFONT hfont_old;\r
2885     int fontHeight;\r
2886     int i;\r
2887 \r
2888     if( fontBitmapSquareSize < 0 ) {\r
2889         /* Something went seriously wrong in the past: do not try to recreate fonts! */\r
2890         return;\r
2891     }\r
2892 \r
2893     if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {\r
2894         fontBitmapSquareSize = -1;\r
2895         return;\r
2896     }\r
2897 \r
2898     if( fontBitmapSquareSize != squareSize ) {\r
2899         hdc_window = GetDC( hwndMain );\r
2900         hdc = CreateCompatibleDC( hdc_window );\r
2901 \r
2902         if( hPieceFont != NULL ) {\r
2903             DeleteObject( hPieceFont );\r
2904         }\r
2905         else {\r
2906             for( i=0; i<=(int)BlackKing; i++ ) {\r
2907                 hPieceMask[i] = NULL;\r
2908                 hPieceFace[i] = NULL;\r
2909             }\r
2910         }\r
2911 \r
2912         fontHeight = 75;\r
2913 \r
2914         if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {\r
2915             fontHeight = appData.fontPieceSize;\r
2916         }\r
2917 \r
2918         fontHeight = (fontHeight * squareSize) / 100;\r
2919 \r
2920         lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );\r
2921         lf.lfWidth = 0;\r
2922         lf.lfEscapement = 0;\r
2923         lf.lfOrientation = 0;\r
2924         lf.lfWeight = FW_NORMAL;\r
2925         lf.lfItalic = 0;\r
2926         lf.lfUnderline = 0;\r
2927         lf.lfStrikeOut = 0;\r
2928         lf.lfCharSet = DEFAULT_CHARSET;\r
2929         lf.lfOutPrecision = OUT_DEFAULT_PRECIS;\r
2930         lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
2931         lf.lfQuality = PROOF_QUALITY;\r
2932         lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;\r
2933         strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );\r
2934         lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';\r
2935 \r
2936         hPieceFont = CreateFontIndirect( &lf );\r
2937 \r
2938         if( hPieceFont == NULL ) {\r
2939             fontBitmapSquareSize = -2;\r
2940         }\r
2941         else {\r
2942             /* Setup font-to-piece character table */\r
2943             if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {\r
2944                 /* No (or wrong) global settings, try to detect the font */\r
2945                 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {\r
2946                     /* Alpha */\r
2947                     SetCharTable(pieceToFontChar, "phbrqkojntwl");\r
2948                 }\r
2949                 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {\r
2950                     /* DiagramTT* family */\r
2951                     SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");\r
2952                 }\r
2953                 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {\r
2954                     /* Fairy symbols */\r
2955                      SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");\r
2956                 }\r
2957                 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {\r
2958                     /* Good Companion (Some characters get warped as literal :-( */\r
2959                     char s[] = "1cmWG0??S??oYI23wgQU";\r
2960                     s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;\r
2961                     SetCharTable(pieceToFontChar, s);\r
2962                 }\r
2963                 else {\r
2964                     /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */\r
2965                     SetCharTable(pieceToFontChar, "pnbrqkomvtwl");\r
2966                 }\r
2967             }\r
2968 \r
2969             /* Create bitmaps */\r
2970             hfont_old = SelectObject( hdc, hPieceFont );\r
2971             for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */\r
2972                 if(PieceToChar((ChessSquare)i) != '.')     /* skip unused pieces         */\r
2973                     CreatePieceMaskFromFont( hdc_window, hdc, i );\r
2974 \r
2975             SelectObject( hdc, hfont_old );\r
2976 \r
2977             fontBitmapSquareSize = squareSize;\r
2978         }\r
2979     }\r
2980 \r
2981     if( hdc != NULL ) {\r
2982         DeleteDC( hdc );\r
2983     }\r
2984 \r
2985     if( hdc_window != NULL ) {\r
2986         ReleaseDC( hwndMain, hdc_window );\r
2987     }\r
2988 }\r
2989 \r
2990 HBITMAP\r
2991 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)\r
2992 {\r
2993   char name[128];\r
2994 \r
2995   sprintf(name, "%s%d%s", piece, squareSize, suffix);\r
2996   if (gameInfo.event &&\r
2997       strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&\r
2998       strcmp(name, "k80s") == 0) {\r
2999     strcpy(name, "tim");\r
3000   }\r
3001   return LoadBitmap(hinst, name);\r
3002 }\r
3003 \r
3004 \r
3005 /* Insert a color into the program's logical palette\r
3006    structure.  This code assumes the given color is\r
3007    the result of the RGB or PALETTERGB macro, and it\r
3008    knows how those macros work (which is documented).\r
3009 */\r
3010 VOID\r
3011 InsertInPalette(COLORREF color)\r
3012 {\r
3013   LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);\r
3014 \r
3015   if (pLogPal->palNumEntries++ >= PALETTESIZE) {\r
3016     DisplayFatalError("Too many colors", 0, 1);\r
3017     pLogPal->palNumEntries--;\r
3018     return;\r
3019   }\r
3020 \r
3021   pe->peFlags = (char) 0;\r
3022   pe->peRed = (char) (0xFF & color);\r
3023   pe->peGreen = (char) (0xFF & (color >> 8));\r
3024   pe->peBlue = (char) (0xFF & (color >> 16));\r
3025   return;\r
3026 }\r
3027 \r
3028 \r
3029 VOID\r
3030 InitDrawingColors()\r
3031 {\r
3032   if (pLogPal == NULL) {\r
3033     /* Allocate enough memory for a logical palette with\r
3034      * PALETTESIZE entries and set the size and version fields\r
3035      * of the logical palette structure.\r
3036      */\r
3037     pLogPal = (NPLOGPALETTE)\r
3038       LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +\r
3039                               (sizeof(PALETTEENTRY) * (PALETTESIZE))));\r
3040     pLogPal->palVersion    = 0x300;\r
3041   }\r
3042   pLogPal->palNumEntries = 0;\r
3043 \r
3044   InsertInPalette(lightSquareColor);\r
3045   InsertInPalette(darkSquareColor);\r
3046   InsertInPalette(whitePieceColor);\r
3047   InsertInPalette(blackPieceColor);\r
3048   InsertInPalette(highlightSquareColor);\r
3049   InsertInPalette(premoveHighlightColor);\r
3050 \r
3051   /*  create a logical color palette according the information\r
3052    *  in the LOGPALETTE structure.\r
3053    */\r
3054   hPal = CreatePalette((LPLOGPALETTE) pLogPal);\r
3055 \r
3056   lightSquareBrush = CreateSolidBrush(lightSquareColor);\r
3057   blackSquareBrush = CreateSolidBrush(blackPieceColor);\r
3058   darkSquareBrush = CreateSolidBrush(darkSquareColor);\r
3059   whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
3060   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
3061   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
3062   explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic\r
3063   /* [AS] Force rendering of the font-based pieces */\r
3064   if( fontBitmapSquareSize > 0 ) {\r
3065     fontBitmapSquareSize = 0;\r
3066   }\r
3067 }\r
3068 \r
3069 \r
3070 int\r
3071 BoardWidth(int boardSize, int n)\r
3072 { /* [HGM] argument n added to allow different width and height */\r
3073   int lineGap = sizeInfo[boardSize].lineGap;\r
3074 \r
3075   if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
3076       lineGap = appData.overrideLineGap;\r
3077   }\r
3078 \r
3079   return (n + 1) * lineGap +\r
3080           n * sizeInfo[boardSize].squareSize;\r
3081 }\r
3082 \r
3083 /* Respond to board resize by dragging edge */\r
3084 VOID\r
3085 ResizeBoard(int newSizeX, int newSizeY, int flags)\r
3086 {\r
3087   BoardSize newSize = NUM_SIZES - 1;\r
3088   static int recurse = 0;\r
3089   if (IsIconic(hwndMain)) return;\r
3090   if (recurse > 0) return;\r
3091   recurse++;\r
3092   while (newSize > 0) {\r
3093         InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects\r
3094         if(newSizeX >= sizeInfo[newSize].cliWidth &&\r
3095            newSizeY >= sizeInfo[newSize].cliHeight) break;\r
3096     newSize--;\r
3097   } \r
3098   boardSize = newSize;\r
3099   InitDrawingSizes(boardSize, flags);\r
3100   recurse--;\r
3101 }\r
3102 \r
3103 \r
3104 \r
3105 VOID\r
3106 InitDrawingSizes(BoardSize boardSize, int flags)\r
3107 {\r
3108   int i, boardWidth, boardHeight; /* [HGM] height treated separately */\r
3109   ChessSquare piece;\r
3110   static int oldBoardSize = -1, oldTinyLayout = 0;\r
3111   HDC hdc;\r
3112   SIZE clockSize, messageSize;\r
3113   HFONT oldFont;\r
3114   char buf[MSG_SIZ];\r
3115   char *str;\r
3116   HMENU hmenu = GetMenu(hwndMain);\r
3117   RECT crect, wrect, oldRect;\r
3118   int offby;\r
3119   LOGBRUSH logbrush;\r
3120 \r
3121   int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only\r
3122   if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }\r
3123 \r
3124   /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */\r
3125   if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;\r
3126 \r
3127   oldRect.left = wpMain.x; //[HGM] placement: remember previous window params\r
3128   oldRect.top = wpMain.y;\r
3129   oldRect.right = wpMain.x + wpMain.width;\r
3130   oldRect.bottom = wpMain.y + wpMain.height;\r
3131 \r
3132   tinyLayout = sizeInfo[boardSize].tinyLayout;\r
3133   smallLayout = sizeInfo[boardSize].smallLayout;\r
3134   squareSize = sizeInfo[boardSize].squareSize;\r
3135   lineGap = sizeInfo[boardSize].lineGap;\r
3136   minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted  */\r
3137 \r
3138   if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
3139       lineGap = appData.overrideLineGap;\r
3140   }\r
3141 \r
3142   if (tinyLayout != oldTinyLayout) {\r
3143     long style = GetWindowLong(hwndMain, GWL_STYLE);\r
3144     if (tinyLayout) {\r
3145       style &= ~WS_SYSMENU;\r
3146       InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,\r
3147                  "&Minimize\tCtrl+F4");\r
3148     } else {\r
3149       style |= WS_SYSMENU;\r
3150       RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);\r
3151     }\r
3152     SetWindowLong(hwndMain, GWL_STYLE, style);\r
3153 \r
3154     for (i=0; menuBarText[tinyLayout][i]; i++) {\r
3155       ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP, \r
3156         (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);\r
3157     }\r
3158     DrawMenuBar(hwndMain);\r
3159   }\r
3160 \r
3161   boardWidth  = BoardWidth(boardSize, BOARD_WIDTH);\r
3162   boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);\r
3163 \r
3164   /* Get text area sizes */\r
3165   hdc = GetDC(hwndMain);\r
3166   if (appData.clockMode) {\r
3167     sprintf(buf, "White: %s", TimeString(23*60*60*1000L));\r
3168   } else {\r
3169     sprintf(buf, "White");\r
3170   }\r
3171   oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
3172   GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);\r
3173   SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
3174   str = "We only care about the height here";\r
3175   GetTextExtentPoint(hdc, str, strlen(str), &messageSize);\r
3176   SelectObject(hdc, oldFont);\r
3177   ReleaseDC(hwndMain, hdc);\r
3178 \r
3179   /* Compute where everything goes */\r
3180   if((first.programLogo || second.programLogo) && !tinyLayout) {\r
3181         /* [HGM] logo: if either logo is on, reserve space for it */\r
3182         logoHeight =  2*clockSize.cy;\r
3183         leftLogoRect.left   = OUTER_MARGIN;\r
3184         leftLogoRect.right  = leftLogoRect.left + 4*clockSize.cy;\r
3185         leftLogoRect.top    = OUTER_MARGIN;\r
3186         leftLogoRect.bottom = OUTER_MARGIN + logoHeight;\r
3187 \r
3188         rightLogoRect.right  = OUTER_MARGIN + boardWidth;\r
3189         rightLogoRect.left   = rightLogoRect.right - 4*clockSize.cy;\r
3190         rightLogoRect.top    = OUTER_MARGIN;\r
3191         rightLogoRect.bottom = OUTER_MARGIN + logoHeight;\r
3192 \r
3193 \r
3194     whiteRect.left = leftLogoRect.right;\r
3195     whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;\r
3196     whiteRect.top = OUTER_MARGIN;\r
3197     whiteRect.bottom = whiteRect.top + logoHeight;\r
3198 \r
3199     blackRect.right = rightLogoRect.left;\r
3200     blackRect.left = whiteRect.right + INNER_MARGIN;\r
3201     blackRect.top = whiteRect.top;\r
3202     blackRect.bottom = whiteRect.bottom;\r
3203   } else {\r
3204     whiteRect.left = OUTER_MARGIN;\r
3205     whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;\r
3206     whiteRect.top = OUTER_MARGIN;\r
3207     whiteRect.bottom = whiteRect.top + clockSize.cy;\r
3208 \r
3209     blackRect.left = whiteRect.right + INNER_MARGIN;\r
3210     blackRect.right = blackRect.left + boardWidth/2 - 1;\r
3211     blackRect.top = whiteRect.top;\r
3212     blackRect.bottom = whiteRect.bottom;\r
3213   }\r
3214 \r
3215   messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;\r
3216   if (appData.showButtonBar) {\r
3217     messageRect.right = OUTER_MARGIN + boardWidth         // [HGM] logo: expressed independent of clock placement\r
3218       - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;\r
3219   } else {\r
3220     messageRect.right = OUTER_MARGIN + boardWidth;\r
3221   }\r
3222   messageRect.top = whiteRect.bottom + INNER_MARGIN;\r
3223   messageRect.bottom = messageRect.top + messageSize.cy;\r
3224 \r
3225   boardRect.left = OUTER_MARGIN;\r
3226   boardRect.right = boardRect.left + boardWidth;\r
3227   boardRect.top = messageRect.bottom + INNER_MARGIN;\r
3228   boardRect.bottom = boardRect.top + boardHeight;\r
3229 \r
3230   sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;\r
3231   sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;\r
3232   oldBoardSize = boardSize;\r
3233   oldTinyLayout = tinyLayout;\r
3234   winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;\r
3235   winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +\r
3236     GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;\r
3237   if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only\r
3238   wpMain.width = winW;  // [HGM] placement: set through temporary which can used by initial sizing choice\r
3239   wpMain.height = winH; //       without disturbing window attachments\r
3240   GetWindowRect(hwndMain, &wrect);\r
3241   SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,\r
3242                SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
3243 \r
3244   // [HGM] placement: let attached windows follow size change.\r
3245   ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );\r
3246   ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );\r
3247   ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );\r
3248   ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );\r
3249   ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );\r
3250 \r
3251   /* compensate if menu bar wrapped */\r
3252   GetClientRect(hwndMain, &crect);\r
3253   offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;\r
3254   wpMain.height += offby;\r
3255   switch (flags) {\r
3256   case WMSZ_TOPLEFT:\r
3257     SetWindowPos(hwndMain, NULL, \r
3258                  wrect.right - wpMain.width, wrect.bottom - wpMain.height, \r
3259                  wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);\r
3260     break;\r
3261 \r
3262   case WMSZ_TOPRIGHT:\r
3263   case WMSZ_TOP:\r
3264     SetWindowPos(hwndMain, NULL, \r
3265                  wrect.left, wrect.bottom - wpMain.height, \r
3266                  wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);\r
3267     break;\r
3268 \r
3269   case WMSZ_BOTTOMLEFT:\r
3270   case WMSZ_LEFT:\r
3271     SetWindowPos(hwndMain, NULL, \r
3272                  wrect.right - wpMain.width, wrect.top, \r
3273                  wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);\r
3274     break;\r
3275 \r
3276   case WMSZ_BOTTOMRIGHT:\r
3277   case WMSZ_BOTTOM:\r
3278   case WMSZ_RIGHT:\r
3279   default:\r
3280     SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,\r
3281                SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
3282     break;\r
3283   }\r
3284 \r
3285   hwndPause = NULL;\r
3286   for (i = 0; i < N_BUTTONS; i++) {\r
3287     if (buttonDesc[i].hwnd != NULL) {\r
3288       DestroyWindow(buttonDesc[i].hwnd);\r
3289       buttonDesc[i].hwnd = NULL;\r
3290     }\r
3291     if (appData.showButtonBar) {\r
3292       buttonDesc[i].hwnd =\r
3293         CreateWindow("BUTTON", buttonDesc[i].label,\r
3294                      WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,\r
3295                      boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),\r
3296                      messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,\r
3297                      (HMENU) buttonDesc[i].id,\r
3298                      (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);\r
3299       if (tinyLayout) {\r
3300         SendMessage(buttonDesc[i].hwnd, WM_SETFONT, \r
3301                     (WPARAM)font[boardSize][MESSAGE_FONT]->hf,\r
3302                     MAKELPARAM(FALSE, 0));\r
3303       }\r
3304       if (buttonDesc[i].id == IDM_Pause)\r
3305         hwndPause = buttonDesc[i].hwnd;\r
3306       buttonDesc[i].wndproc = (WNDPROC)\r
3307         SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);\r
3308     }\r
3309   }\r
3310   if (gridPen != NULL) DeleteObject(gridPen);\r
3311   if (highlightPen != NULL) DeleteObject(highlightPen);\r
3312   if (premovePen != NULL) DeleteObject(premovePen);\r
3313   if (lineGap != 0) {\r
3314     logbrush.lbStyle = BS_SOLID;\r
3315     logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */\r
3316     gridPen =\r
3317       ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
3318                    lineGap, &logbrush, 0, NULL);\r
3319     logbrush.lbColor = highlightSquareColor;\r
3320     highlightPen =\r
3321       ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
3322                    lineGap, &logbrush, 0, NULL);\r
3323 \r
3324     logbrush.lbColor = premoveHighlightColor; \r
3325     premovePen =\r
3326       ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
3327                    lineGap, &logbrush, 0, NULL);\r
3328 \r
3329     /* [HGM] Loop had to be split in part for vert. and hor. lines */\r
3330     for (i = 0; i < BOARD_HEIGHT + 1; i++) {\r
3331       gridEndpoints[i*2].x = boardRect.left + lineGap / 2;\r
3332       gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =\r
3333         boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));\r
3334       gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +\r
3335         BOARD_WIDTH * (squareSize + lineGap);\r
3336       gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
3337     }\r
3338     for (i = 0; i < BOARD_WIDTH + 1; i++) {\r
3339       gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;\r
3340       gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =\r
3341         gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +\r
3342         lineGap / 2 + (i * (squareSize + lineGap));\r
3343       gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =\r
3344         boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);\r
3345       gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
3346     }\r
3347   }\r
3348 \r
3349   /* [HGM] Licensing requirement */\r
3350 #ifdef GOTHIC\r
3351   if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else\r
3352 #endif\r
3353 #ifdef FALCON\r
3354   if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else\r
3355 #endif\r
3356   GothicPopUp( "", VariantNormal);\r
3357 \r
3358 \r
3359 /*  if (boardSize == oldBoardSize) return; [HGM] variant might have changed */\r
3360 \r
3361   /* Load piece bitmaps for this board size */\r
3362   for (i=0; i<=2; i++) {\r
3363     for (piece = WhitePawn;\r
3364          (int) piece < (int) BlackPawn;\r
3365          piece = (ChessSquare) ((int) piece + 1)) {\r
3366       if (pieceBitmap[i][piece] != NULL)\r
3367         DeleteObject(pieceBitmap[i][piece]);\r
3368     }\r
3369   }\r
3370 \r
3371   fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */\r
3372   // Orthodox Chess pieces\r
3373   pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");\r
3374   pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");\r
3375   pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");\r
3376   pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");\r
3377   pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");\r
3378   pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");\r
3379   pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");\r
3380   pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");\r
3381   pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");\r
3382   pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");\r
3383   pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");\r
3384   pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");\r
3385   pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");\r
3386   pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");\r
3387   pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");\r
3388   if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {\r
3389     // in Shogi, Hijack the unused Queen for Lance\r
3390     pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
3391     pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
3392     pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
3393   } else {\r
3394     pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");\r
3395     pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");\r
3396     pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");\r
3397   }\r
3398 \r
3399   if(squareSize <= 72 && squareSize >= 33) { \r
3400     /* A & C are available in most sizes now */\r
3401     if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like\r
3402       pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");\r
3403       pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");\r
3404       pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");\r
3405       pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
3406       pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
3407       pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
3408       pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
3409       pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
3410       pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
3411       pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
3412       pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
3413       pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
3414     } else { // Smirf-like\r
3415       pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");\r
3416       pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");\r
3417       pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");\r
3418     }\r
3419     if(gameInfo.variant == VariantGothic) { // Vortex-like\r
3420       pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
3421       pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
3422       pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
3423     } else { // WinBoard standard\r
3424       pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");\r
3425       pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");\r
3426       pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");\r
3427     }\r
3428   }\r
3429 \r
3430 \r
3431   if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */\r
3432     pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");\r
3433     pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");\r
3434     pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");\r
3435     pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");\r
3436     pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");\r
3437     pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3438     pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");\r
3439     pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");\r
3440     pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");\r
3441     pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");\r
3442     pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");\r
3443     pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");\r
3444     pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");\r
3445     pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");\r
3446     pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");\r
3447     pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");\r
3448     pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");\r
3449     pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");\r
3450     pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");\r
3451     pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");\r
3452     pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");\r
3453     pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");\r
3454     pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");\r
3455     pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");\r
3456     pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
3457     pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
3458     pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
3459     pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");\r
3460     pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");\r
3461     pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");\r
3462 \r
3463     if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */\r
3464       pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");\r
3465       pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");\r
3466       pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3467       pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");\r
3468       pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");\r
3469       pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3470       pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");\r
3471       pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");\r
3472       pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3473       pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");\r
3474       pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");\r
3475       pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3476     } else {\r
3477       pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");\r
3478       pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");\r
3479       pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");\r
3480       pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");\r
3481       pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");\r
3482       pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");\r
3483       pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
3484       pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
3485       pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
3486       pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");\r
3487       pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");\r
3488       pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");\r
3489     }\r
3490 \r
3491   } else { /* other size, no special bitmaps available. Use smaller symbols */\r
3492     if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;\r
3493     else  minorSize = sizeInfo[(int)boardSize - 2].squareSize;\r
3494     pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");\r
3495     pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");\r
3496     pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");\r
3497     pieceBitmap[0][WhiteCardinal]   = DoLoadBitmap(hInst, "b", minorSize, "s");\r
3498     pieceBitmap[1][WhiteCardinal]   = DoLoadBitmap(hInst, "b", minorSize, "o");\r
3499     pieceBitmap[2][WhiteCardinal]   = DoLoadBitmap(hInst, "b", minorSize, "w");\r
3500     pieceBitmap[0][WhiteDragon]   = DoLoadBitmap(hInst, "r", minorSize, "s");\r
3501     pieceBitmap[1][WhiteDragon]   = DoLoadBitmap(hInst, "r", minorSize, "o");\r
3502     pieceBitmap[2][WhiteDragon]   = DoLoadBitmap(hInst, "r", minorSize, "w");\r
3503     pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");\r
3504     pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");\r
3505     pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");\r
3506   }\r
3507 \r
3508 \r
3509   if(gameInfo.variant == VariantShogi && squareSize == 58)\r
3510   /* special Shogi support in this size */\r
3511   { for (i=0; i<=2; i++) { /* replace all bitmaps */\r
3512       for (piece = WhitePawn;\r
3513            (int) piece < (int) BlackPawn;\r
3514            piece = (ChessSquare) ((int) piece + 1)) {\r
3515         if (pieceBitmap[i][piece] != NULL)\r
3516           DeleteObject(pieceBitmap[i][piece]);\r
3517       }\r
3518     }\r
3519   pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");\r
3520   pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");\r
3521   pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");\r
3522   pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");\r
3523   pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");\r
3524   pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");\r
3525   pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");\r
3526   pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");\r
3527   pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");\r
3528   pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");\r
3529   pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");\r
3530   pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");\r
3531   pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");\r
3532   pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");\r
3533   pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");\r
3534   pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");\r
3535   pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");\r
3536   pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");\r
3537   pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");\r
3538   pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");\r
3539   pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");\r
3540   pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");\r
3541   pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");\r
3542   pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");\r
3543   pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");\r
3544   pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");\r
3545   pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");\r
3546   pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");\r
3547   pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");\r
3548   pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");\r
3549   pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
3550   pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
3551   pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");\r
3552   pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");\r
3553   pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
3554   pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
3555   pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");\r
3556   pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");\r
3557   pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
3558   pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
3559   pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");\r
3560   pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
3561   minorSize = 0;\r
3562   }\r
3563 }\r
3564 \r
3565 HBITMAP\r
3566 PieceBitmap(ChessSquare p, int kind)\r
3567 {\r
3568   if ((int) p >= (int) BlackPawn)\r
3569     p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);\r
3570 \r
3571   return pieceBitmap[kind][(int) p];\r
3572 }\r
3573 \r
3574 /***************************************************************/\r
3575 \r
3576 #define MIN(a,b) (((a) < (b)) ? (a) : (b))\r
3577 #define MAX(a,b) (((a) > (b)) ? (a) : (b))\r
3578 /*\r
3579 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))\r
3580 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))\r
3581 */\r
3582 \r
3583 VOID\r
3584 SquareToPos(int row, int column, int * x, int * y)\r
3585 {\r
3586   if (flipView) {\r
3587     *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);\r
3588     *y = boardRect.top + lineGap + row * (squareSize + lineGap);\r
3589   } else {\r
3590     *x = boardRect.left + lineGap + column * (squareSize + lineGap);\r
3591     *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);\r
3592   }\r
3593 }\r
3594 \r
3595 VOID\r
3596 DrawCoordsOnDC(HDC hdc)\r
3597 {\r
3598   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
3599   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
3600   char str[2] = { NULLCHAR, NULLCHAR };\r
3601   int oldMode, oldAlign, x, y, start, i;\r
3602   HFONT oldFont;\r
3603   HBRUSH oldBrush;\r
3604 \r
3605   if (!appData.showCoords)\r
3606     return;\r
3607 \r
3608   start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;\r
3609 \r
3610   oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));\r
3611   oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));\r
3612   oldAlign = GetTextAlign(hdc);\r
3613   oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);\r
3614 \r
3615   y = boardRect.top + lineGap;\r
3616   x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);\r
3617 \r
3618   SetTextAlign(hdc, TA_LEFT|TA_TOP);\r
3619   for (i = 0; i < BOARD_HEIGHT; i++) {\r
3620     str[0] = files[start + i];\r
3621     ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);\r
3622     y += squareSize + lineGap;\r
3623   }\r
3624 \r
3625   start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;\r
3626 \r
3627   SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);\r
3628   for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {\r
3629     str[0] = ranks[start + i];\r
3630     ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);\r
3631     x += squareSize + lineGap;\r
3632   }    \r
3633 \r
3634   SelectObject(hdc, oldBrush);\r
3635   SetBkMode(hdc, oldMode);\r
3636   SetTextAlign(hdc, oldAlign);\r
3637   SelectObject(hdc, oldFont);\r
3638 }\r
3639 \r
3640 VOID\r
3641 DrawGridOnDC(HDC hdc)\r