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