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