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