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