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