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