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