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