changes from H.G. Muller; version 4.3.14
[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 );\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   { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },\r
1177   { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },\r
1178   { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },\r
1179   { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },\r
1180   { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },\r
1181   { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },\r
1182   { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },\r
1183   { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },\r
1184   { "userName", ArgString, (LPVOID) &appData.userName, FALSE },\r
1185 \r
1186 #ifdef ZIPPY\r
1187   { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
1188   { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },\r
1189   { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
1190   { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
1191   { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },\r
1192   { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },\r
1193   { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
1194   { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
1195   { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },\r
1196   { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },\r
1197   { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },\r
1198   { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },\r
1199   { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,\r
1200     FALSE },\r
1201   { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },\r
1202   { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },\r
1203   { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },\r
1204   { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
1205   { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
1206   { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },\r
1207   { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,\r
1208     FALSE },\r
1209   { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
1210   { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
1211   { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
1212   { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },\r
1213   { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },\r
1214   { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1215   { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1216   { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1217   { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1218   { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },\r
1219   { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },\r
1220   { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
1221   { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
1222   { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },\r
1223   { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },\r
1224   { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },\r
1225   /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */\r
1226   { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },\r
1227 #endif\r
1228   /* [HGM] options for broadcasting and time odds */\r
1229   { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },\r
1230   { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },\r
1231   { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },\r
1232   { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },\r
1233   { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },\r
1234   { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },\r
1235   { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },\r
1236   { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },\r
1237   { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },\r
1238   { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },\r
1239   { NULL, ArgNone, NULL, FALSE }\r
1240 };\r
1241 \r
1242 \r
1243 /* Kludge for indirection files on command line */\r
1244 char* lastIndirectionFilename;\r
1245 ArgDescriptor argDescriptorIndirection =\r
1246 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };\r
1247 \r
1248 \r
1249 VOID\r
1250 ExitArgError(char *msg, char *badArg)\r
1251 {\r
1252   char buf[MSG_SIZ];\r
1253 \r
1254   sprintf(buf, "%s %s", msg, badArg);\r
1255   DisplayFatalError(buf, 0, 2);\r
1256   exit(2);\r
1257 }\r
1258 \r
1259 /* Command line font name parser.  NULL name means do nothing.\r
1260    Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"\r
1261    For backward compatibility, syntax without the colon is also\r
1262    accepted, but font names with digits in them won't work in that case.\r
1263 */\r
1264 VOID\r
1265 ParseFontName(char *name, MyFontParams *mfp)\r
1266 {\r
1267   char *p, *q;\r
1268   if (name == NULL) return;\r
1269   p = name;\r
1270   q = strchr(p, ':');\r
1271   if (q) {\r
1272     if (q - p >= sizeof(mfp->faceName))\r
1273       ExitArgError("Font name too long:", name);\r
1274     memcpy(mfp->faceName, p, q - p);\r
1275     mfp->faceName[q - p] = NULLCHAR;\r
1276     p = q + 1;\r
1277   } else {\r
1278     q = mfp->faceName;\r
1279     while (*p && !isdigit(*p)) {\r
1280       *q++ = *p++;\r
1281       if (q - mfp->faceName >= sizeof(mfp->faceName))\r
1282         ExitArgError("Font name too long:", name);\r
1283     }\r
1284     while (q > mfp->faceName && q[-1] == ' ') q--;\r
1285     *q = NULLCHAR;\r
1286   }\r
1287   if (!*p) ExitArgError("Font point size missing:", name);\r
1288   mfp->pointSize = (float) atof(p);\r
1289   mfp->bold = (strchr(p, 'b') != NULL);\r
1290   mfp->italic = (strchr(p, 'i') != NULL);\r
1291   mfp->underline = (strchr(p, 'u') != NULL);\r
1292   mfp->strikeout = (strchr(p, 's') != NULL);\r
1293 }\r
1294 \r
1295 /* Color name parser.\r
1296    X version accepts X color names, but this one\r
1297    handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */\r
1298 COLORREF\r
1299 ParseColorName(char *name)\r
1300 {\r
1301   int red, green, blue, count;\r
1302   char buf[MSG_SIZ];\r
1303 \r
1304   count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);\r
1305   if (count != 3) {\r
1306     count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d", \r
1307       &red, &green, &blue);\r
1308   }\r
1309   if (count != 3) {\r
1310     sprintf(buf, "Can't parse color name %s", name);\r
1311     DisplayError(buf, 0);\r
1312     return RGB(0, 0, 0);\r
1313   }\r
1314   return PALETTERGB(red, green, blue);\r
1315 }\r
1316 \r
1317 \r
1318 void ParseAttribs(COLORREF *color, int *effects, char* argValue)\r
1319 {\r
1320   char *e = argValue;\r
1321   int eff = 0;\r
1322 \r
1323   while (*e) {\r
1324     if (*e == 'b')      eff |= CFE_BOLD;\r
1325     else if (*e == 'i') eff |= CFE_ITALIC;\r
1326     else if (*e == 'u') eff |= CFE_UNDERLINE;\r
1327     else if (*e == 's') eff |= CFE_STRIKEOUT;\r
1328     else if (*e == '#' || isdigit(*e)) break;\r
1329     e++;\r
1330   }\r
1331   *effects = eff;\r
1332   *color   = ParseColorName(e);\r
1333 }\r
1334 \r
1335 \r
1336 BoardSize\r
1337 ParseBoardSize(char *name)\r
1338 {\r
1339   BoardSize bs = SizeTiny;\r
1340   while (sizeInfo[bs].name != NULL) {\r
1341     if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;\r
1342     bs++;\r
1343   }\r
1344   ExitArgError("Unrecognized board size value", name);\r
1345   return bs; /* not reached */\r
1346 }\r
1347 \r
1348 \r
1349 char\r
1350 StringGet(void *getClosure)\r
1351 {\r
1352   char **p = (char **) getClosure;\r
1353   return *((*p)++);\r
1354 }\r
1355 \r
1356 char\r
1357 FileGet(void *getClosure)\r
1358 {\r
1359   int c;\r
1360   FILE* f = (FILE*) getClosure;\r
1361 \r
1362   c = getc(f);\r
1363   if (c == EOF)\r
1364     return NULLCHAR;\r
1365   else\r
1366     return (char) c;\r
1367 }\r
1368 \r
1369 /* Parse settings file named "name". If file found, return the\r
1370    full name in fullname and return TRUE; else return FALSE */\r
1371 BOOLEAN\r
1372 ParseSettingsFile(char *name, char fullname[MSG_SIZ])\r
1373 {\r
1374   char *dummy;\r
1375   FILE *f;\r
1376 \r
1377   if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {\r
1378     f = fopen(fullname, "r");\r
1379     if (f != NULL) {\r
1380       ParseArgs(FileGet, f);\r
1381       fclose(f);\r
1382       return TRUE;\r
1383     }\r
1384   }\r
1385   return FALSE;\r
1386 }\r
1387 \r
1388 VOID\r
1389 ParseArgs(GetFunc get, void *cl)\r
1390 {\r
1391   char argName[ARG_MAX];\r
1392   char argValue[ARG_MAX];\r
1393   ArgDescriptor *ad;\r
1394   char start;\r
1395   char *q;\r
1396   int i, octval;\r
1397   char ch;\r
1398   int posarg = 0;\r
1399 \r
1400   ch = get(cl);\r
1401   for (;;) {\r
1402     while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);\r
1403     if (ch == NULLCHAR) break;\r
1404     if (ch == ';') {\r
1405       /* Comment to end of line */\r
1406       ch = get(cl);\r
1407       while (ch != '\n' && ch != NULLCHAR) ch = get(cl);\r
1408       continue;\r
1409     } else if (ch == '/' || ch == '-') {\r
1410       /* Switch */\r
1411       q = argName;\r
1412       while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&\r
1413              ch != '\n' && ch != '\t') {\r
1414         *q++ = ch;\r
1415         ch = get(cl);\r
1416       }\r
1417       *q = NULLCHAR;\r
1418 \r
1419       for (ad = argDescriptors; ad->argName != NULL; ad++)\r
1420         if (strcmp(ad->argName, argName + 1) == 0) break;\r
1421 \r
1422       if (ad->argName == NULL)\r
1423         ExitArgError("Unrecognized argument", argName);\r
1424 \r
1425     } else if (ch == '@') {\r
1426       /* Indirection file */\r
1427       ad = &argDescriptorIndirection;\r
1428       ch = get(cl);\r
1429     } else {\r
1430       /* Positional argument */\r
1431       ad = &argDescriptors[posarg++];\r
1432       strcpy(argName, ad->argName);\r
1433     }\r
1434 \r
1435     if (ad->argType == ArgTrue) {\r
1436       *(Boolean *) ad->argLoc = TRUE;\r
1437       continue;\r
1438     }\r
1439     if (ad->argType == ArgFalse) {\r
1440       *(Boolean *) ad->argLoc = FALSE;\r
1441       continue;\r
1442     }\r
1443 \r
1444     while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);\r
1445     if (ch == NULLCHAR || ch == '\n') {\r
1446       ExitArgError("No value provided for argument", argName);\r
1447     }\r
1448     q = argValue;\r
1449     if (ch == '{') {\r
1450       // Quoting with { }.  No characters have to (or can) be escaped.\r
1451       // Thus the string cannot contain a '}' character.\r
1452       start = ch;\r
1453       ch = get(cl);\r
1454       while (start) {\r
1455         switch (ch) {\r
1456         case NULLCHAR:\r
1457           start = NULLCHAR;\r
1458           break;\r
1459           \r
1460         case '}':\r
1461           ch = get(cl);\r
1462           start = NULLCHAR;\r
1463           break;\r
1464 \r
1465         default:\r
1466           *q++ = ch;\r
1467           ch = get(cl);\r
1468           break;\r
1469         }\r
1470       }   \r
1471     } else if (ch == '\'' || ch == '"') {\r
1472       // Quoting with ' ' or " ", with \ as escape character.\r
1473       // Inconvenient for long strings that may contain Windows filenames.\r
1474       start = ch;\r
1475       ch = get(cl);\r
1476       while (start) {\r
1477         switch (ch) {\r
1478         case NULLCHAR:\r
1479           start = NULLCHAR;\r
1480           break;\r
1481 \r
1482         default:\r
1483         not_special:\r
1484           *q++ = ch;\r
1485           ch = get(cl);\r
1486           break;\r
1487 \r
1488         case '\'':\r
1489         case '\"':\r
1490           if (ch == start) {\r
1491             ch = get(cl);\r
1492             start = NULLCHAR;\r
1493             break;\r
1494           } else {\r
1495             goto not_special;\r
1496           }\r
1497 \r
1498         case '\\':\r
1499           if (ad->argType == ArgFilename\r
1500               || ad->argType == ArgSettingsFilename) {\r
1501               goto not_special;\r
1502           }\r
1503           ch = get(cl);\r
1504           switch (ch) {\r
1505           case NULLCHAR:\r
1506             ExitArgError("Incomplete \\ escape in value for", argName);\r
1507             break;\r
1508           case 'n':\r
1509             *q++ = '\n';\r
1510             ch = get(cl);\r
1511             break;\r
1512           case 'r':\r
1513             *q++ = '\r';\r
1514             ch = get(cl);\r
1515             break;\r
1516           case 't':\r
1517             *q++ = '\t';\r
1518             ch = get(cl);\r
1519             break;\r
1520           case 'b':\r
1521             *q++ = '\b';\r
1522             ch = get(cl);\r
1523             break;\r
1524           case 'f':\r
1525             *q++ = '\f';\r
1526             ch = get(cl);\r
1527             break;\r
1528           default:\r
1529             octval = 0;\r
1530             for (i = 0; i < 3; i++) {\r
1531               if (ch >= '0' && ch <= '7') {\r
1532                 octval = octval*8 + (ch - '0');\r
1533                 ch = get(cl);\r
1534               } else {\r
1535                 break;\r
1536               }\r
1537             }\r
1538             if (i > 0) {\r
1539               *q++ = (char) octval;\r
1540             } else {\r
1541               *q++ = ch;\r
1542               ch = get(cl);\r
1543             }\r
1544             break;\r
1545           }\r
1546           break;\r
1547         }\r
1548       }\r
1549     } else {\r
1550       while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {\r
1551         *q++ = ch;\r
1552         ch = get(cl);\r
1553       }\r
1554     }\r
1555     *q = NULLCHAR;\r
1556 \r
1557     switch (ad->argType) {\r
1558     case ArgInt:\r
1559       *(int *) ad->argLoc = atoi(argValue);\r
1560       break;\r
1561 \r
1562     case ArgFloat:\r
1563       *(float *) ad->argLoc = (float) atof(argValue);\r
1564       break;\r
1565 \r
1566     case ArgString:\r
1567     case ArgFilename:\r
1568       *(char **) ad->argLoc = strdup(argValue);\r
1569       break;\r
1570 \r
1571     case ArgSettingsFilename:\r
1572       {\r
1573         char fullname[MSG_SIZ];\r
1574         if (ParseSettingsFile(argValue, fullname)) {\r
1575           if (ad->argLoc != NULL) {\r
1576             *(char **) ad->argLoc = strdup(fullname);\r
1577           }\r
1578         } else {\r
1579           if (ad->argLoc != NULL) {\r
1580           } else {\r
1581             ExitArgError("Failed to open indirection file", argValue);\r
1582           }\r
1583         }\r
1584       }\r
1585       break;\r
1586 \r
1587     case ArgBoolean:\r
1588       switch (argValue[0]) {\r
1589       case 't':\r
1590       case 'T':\r
1591         *(Boolean *) ad->argLoc = TRUE;\r
1592         break;\r
1593       case 'f':\r
1594       case 'F':\r
1595         *(Boolean *) ad->argLoc = FALSE;\r
1596         break;\r
1597       default:\r
1598         ExitArgError("Unrecognized boolean argument value", argValue);\r
1599         break;\r
1600       }\r
1601       break;\r
1602 \r
1603     case ArgColor:\r
1604       *(COLORREF *)ad->argLoc = ParseColorName(argValue);\r
1605       break;\r
1606 \r
1607     case ArgAttribs: {\r
1608       ColorClass cc = (ColorClass)ad->argLoc;\r
1609       ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);\r
1610       }\r
1611       break;\r
1612       \r
1613     case ArgBoardSize:\r
1614       *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);\r
1615       break;\r
1616 \r
1617     case ArgFont:\r
1618       ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);\r
1619       break;\r
1620 \r
1621     case ArgCommSettings:\r
1622       ParseCommSettings(argValue, &dcb);\r
1623       break;\r
1624 \r
1625     case ArgNone:\r
1626       ExitArgError("Unrecognized argument", argValue);\r
1627       break;\r
1628     }\r
1629   }\r
1630 }\r
1631 \r
1632 VOID\r
1633 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)\r
1634 {\r
1635   HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);\r
1636   lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);\r
1637   DeleteDC(hdc);\r
1638   lf->lfWidth = 0;\r
1639   lf->lfEscapement = 0;\r
1640   lf->lfOrientation = 0;\r
1641   lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;\r
1642   lf->lfItalic = mfp->italic;\r
1643   lf->lfUnderline = mfp->underline;\r
1644   lf->lfStrikeOut = mfp->strikeout;\r
1645   lf->lfCharSet = DEFAULT_CHARSET;\r
1646   lf->lfOutPrecision = OUT_DEFAULT_PRECIS;\r
1647   lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
1648   lf->lfQuality = DEFAULT_QUALITY;\r
1649   lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;\r
1650   strcpy(lf->lfFaceName, mfp->faceName);\r
1651 }\r
1652 \r
1653 VOID\r
1654 CreateFontInMF(MyFont *mf)\r
1655 {\r
1656   LFfromMFP(&mf->lf, &mf->mfp);\r
1657   if (mf->hf) DeleteObject(mf->hf);\r
1658   mf->hf = CreateFontIndirect(&mf->lf);\r
1659 }\r
1660 \r
1661 VOID\r
1662 SetDefaultTextAttribs()\r
1663 {\r
1664   ColorClass cc;\r
1665   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1666     ParseAttribs(&textAttribs[cc].color, \r
1667                  &textAttribs[cc].effects, \r
1668                  defaultTextAttribs[cc]);\r
1669   }\r
1670 }\r
1671 \r
1672 VOID\r
1673 SetDefaultSounds()\r
1674 {\r
1675   ColorClass cc;\r
1676   SoundClass sc;\r
1677   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1678     textAttribs[cc].sound.name = strdup("");\r
1679     textAttribs[cc].sound.data = NULL;\r
1680   }\r
1681   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
1682     sounds[sc].name = strdup("");\r
1683     sounds[sc].data = NULL;\r
1684   }\r
1685   sounds[(int)SoundBell].name = strdup(SOUND_BELL);\r
1686 }\r
1687 \r
1688 VOID\r
1689 LoadAllSounds()\r
1690 {\r
1691   ColorClass cc;\r
1692   SoundClass sc;\r
1693   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1694     MyLoadSound(&textAttribs[cc].sound);\r
1695   }\r
1696   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
1697     MyLoadSound(&sounds[sc]);\r
1698   }\r
1699 }\r
1700 \r
1701 VOID\r
1702 InitAppData(LPSTR lpCmdLine)\r
1703 {\r
1704   int i, j;\r
1705   char buf[ARG_MAX], currDir[MSG_SIZ];\r
1706   char *dummy, *p;\r
1707 \r
1708   programName = szAppName;\r
1709 \r
1710   /* Initialize to defaults */\r
1711   lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);\r
1712   darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);\r
1713   whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);\r
1714   blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);\r
1715   highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);\r
1716   premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);\r
1717   consoleBackgroundColor = ParseColorName(COLOR_BKGD);\r
1718   SetDefaultTextAttribs();\r
1719   SetDefaultSounds();\r
1720   appData.movesPerSession = MOVES_PER_SESSION;\r
1721   appData.initString = INIT_STRING;\r
1722   appData.secondInitString = INIT_STRING;\r
1723   appData.firstComputerString = COMPUTER_STRING;\r
1724   appData.secondComputerString = COMPUTER_STRING;\r
1725   appData.firstChessProgram = FIRST_CHESS_PROGRAM;\r
1726   appData.secondChessProgram = SECOND_CHESS_PROGRAM;\r
1727   appData.firstPlaysBlack = FALSE;\r
1728   appData.noChessProgram = FALSE;\r
1729   chessProgram = FALSE;\r
1730   appData.firstHost = FIRST_HOST;\r
1731   appData.secondHost = SECOND_HOST;\r
1732   appData.firstDirectory = FIRST_DIRECTORY;\r
1733   appData.secondDirectory = SECOND_DIRECTORY;\r
1734   appData.bitmapDirectory = "";\r
1735   appData.remoteShell = REMOTE_SHELL;\r
1736   appData.remoteUser = "";\r
1737   appData.timeDelay = TIME_DELAY;\r
1738   appData.timeControl = TIME_CONTROL;\r
1739   appData.timeIncrement = TIME_INCREMENT;\r
1740   appData.icsActive = FALSE;\r
1741   appData.icsHost = "";\r
1742   appData.icsPort = ICS_PORT;\r
1743   appData.icsCommPort = ICS_COMM_PORT;\r
1744   appData.icsLogon = ICS_LOGON;\r
1745   appData.icsHelper = "";\r
1746   appData.useTelnet = FALSE;\r
1747   appData.telnetProgram = TELNET_PROGRAM;\r
1748   appData.gateway = "";\r
1749   appData.loadGameFile = "";\r
1750   appData.loadGameIndex = 0;\r
1751   appData.saveGameFile = "";\r
1752   appData.autoSaveGames = FALSE;\r
1753   appData.loadPositionFile = "";\r
1754   appData.loadPositionIndex = 1;\r
1755   appData.savePositionFile = "";\r
1756   appData.matchMode = FALSE;\r
1757   appData.matchGames = 0;\r
1758   appData.monoMode = FALSE;\r
1759   appData.debugMode = FALSE;\r
1760   appData.clockMode = TRUE;\r
1761   boardSize = (BoardSize) -1; /* determine by screen size */\r
1762   appData.Iconic = FALSE; /*unused*/\r
1763   appData.searchTime = "";\r
1764   appData.searchDepth = 0;\r
1765   appData.showCoords = FALSE;\r
1766   appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/\r
1767   appData.autoCallFlag = FALSE;\r
1768   appData.flipView = FALSE;\r
1769   appData.autoFlipView = TRUE;\r
1770   appData.cmailGameName = "";\r
1771   appData.alwaysPromoteToQueen = FALSE;\r
1772   appData.oldSaveStyle = FALSE;\r
1773   appData.quietPlay = FALSE;\r
1774   appData.showThinking = FALSE;\r
1775   appData.ponderNextMove = TRUE;\r
1776   appData.periodicUpdates = TRUE;\r
1777   appData.popupExitMessage = TRUE;\r
1778   appData.popupMoveErrors = FALSE;\r
1779   appData.autoObserve = FALSE;\r
1780   appData.autoComment = FALSE;\r
1781   appData.animate = TRUE;\r
1782   appData.animSpeed = 10;\r
1783   appData.animateDragging = TRUE;\r
1784   appData.highlightLastMove = TRUE;\r
1785   appData.getMoveList = TRUE;\r
1786   appData.testLegality = TRUE;\r
1787   appData.premove = TRUE;\r
1788   appData.premoveWhite = FALSE;\r
1789   appData.premoveWhiteText = "";\r
1790   appData.premoveBlack = FALSE;\r
1791   appData.premoveBlackText = "";\r
1792   appData.icsAlarm = TRUE;\r
1793   appData.icsAlarmTime = 5000;\r
1794   appData.autoRaiseBoard = TRUE;\r
1795   appData.localLineEditing = TRUE;\r
1796   appData.colorize = TRUE;\r
1797   appData.reuseFirst = TRUE;\r
1798   appData.reuseSecond = TRUE;\r
1799   appData.blindfold = FALSE;\r
1800   dcb.DCBlength = sizeof(DCB);\r
1801   dcb.BaudRate = 9600;\r
1802   dcb.fBinary = TRUE;\r
1803   dcb.fParity = FALSE;\r
1804   dcb.fOutxCtsFlow = FALSE;\r
1805   dcb.fOutxDsrFlow = FALSE;\r
1806   dcb.fDtrControl = DTR_CONTROL_ENABLE;\r
1807   dcb.fDsrSensitivity = FALSE;\r
1808   dcb.fTXContinueOnXoff = TRUE;\r
1809   dcb.fOutX = FALSE;\r
1810   dcb.fInX = FALSE;\r
1811   dcb.fNull = FALSE;\r
1812   dcb.fRtsControl = RTS_CONTROL_ENABLE;\r
1813   dcb.fAbortOnError = FALSE;\r
1814   dcb.wReserved = 0;\r
1815   dcb.ByteSize = 7;\r
1816   dcb.Parity = SPACEPARITY;\r
1817   dcb.StopBits = ONESTOPBIT;\r
1818   settingsFileName = SETTINGS_FILE;\r
1819   saveSettingsOnExit = TRUE;\r
1820   boardX = CW_USEDEFAULT;\r
1821   boardY = CW_USEDEFAULT;\r
1822   consoleX = CW_USEDEFAULT; \r
1823   consoleY = CW_USEDEFAULT; \r
1824   consoleW = CW_USEDEFAULT;\r
1825   consoleH = CW_USEDEFAULT;\r
1826   analysisX = CW_USEDEFAULT; \r
1827   analysisY = CW_USEDEFAULT; \r
1828   analysisW = CW_USEDEFAULT;\r
1829   analysisH = CW_USEDEFAULT;\r
1830   commentX = CW_USEDEFAULT; \r
1831   commentY = CW_USEDEFAULT; \r
1832   commentW = CW_USEDEFAULT;\r
1833   commentH = CW_USEDEFAULT;\r
1834   editTagsX = CW_USEDEFAULT; \r
1835   editTagsY = CW_USEDEFAULT; \r
1836   editTagsW = CW_USEDEFAULT;\r
1837   editTagsH = CW_USEDEFAULT;\r
1838   gameListX = CW_USEDEFAULT; \r
1839   gameListY = CW_USEDEFAULT; \r
1840   gameListW = CW_USEDEFAULT;\r
1841   gameListH = CW_USEDEFAULT;\r
1842   icsTextMenuString = ICS_TEXT_MENU_DEFAULT;\r
1843   icsNames = ICS_NAMES;\r
1844   firstChessProgramNames = FCP_NAMES;\r
1845   secondChessProgramNames = SCP_NAMES;\r
1846   appData.initialMode = "";\r
1847   appData.variant = "normal";\r
1848   appData.firstProtocolVersion = PROTOVER;\r
1849   appData.secondProtocolVersion = PROTOVER;\r
1850   appData.showButtonBar = TRUE;\r
1851 \r
1852    /* [AS] New properties (see comments in header file) */\r
1853   appData.firstScoreIsAbsolute = FALSE;\r
1854   appData.secondScoreIsAbsolute = FALSE;\r
1855   appData.saveExtendedInfoInPGN = FALSE;\r
1856   appData.hideThinkingFromHuman = FALSE;\r
1857   appData.liteBackTextureFile = "";\r
1858   appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
1859   appData.darkBackTextureFile = "";\r
1860   appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
1861   appData.renderPiecesWithFont = "";\r
1862   appData.fontToPieceTable = "";\r
1863   appData.fontBackColorWhite = 0;\r
1864   appData.fontForeColorWhite = 0;\r
1865   appData.fontBackColorBlack = 0;\r
1866   appData.fontForeColorBlack = 0;\r
1867   appData.fontPieceSize = 80;\r
1868   appData.overrideLineGap = 1;\r
1869   appData.adjudicateLossThreshold = 0;\r
1870   appData.delayBeforeQuit = 0;\r
1871   appData.delayAfterQuit = 0;\r
1872   appData.nameOfDebugFile = "winboard.debug";\r
1873   appData.pgnEventHeader = "Computer Chess Game";\r
1874   appData.defaultFrcPosition = -1;\r
1875   appData.gameListTags = GLT_DEFAULT_TAGS;\r
1876   appData.saveOutOfBookInfo = TRUE;\r
1877   appData.showEvalInMoveHistory = TRUE;\r
1878   appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );\r
1879   appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );\r
1880   appData.highlightMoveWithArrow = FALSE;\r
1881   appData.highlightArrowColor = ParseColorName( "#FFFF80" );\r
1882   appData.useStickyWindows = TRUE;\r
1883   appData.adjudicateDrawMoves = 0;\r
1884   appData.autoDisplayComment = TRUE;\r
1885   appData.autoDisplayTags = TRUE;\r
1886   appData.firstIsUCI = FALSE;\r
1887   appData.secondIsUCI = FALSE;\r
1888   appData.firstHasOwnBookUCI = TRUE;\r
1889   appData.secondHasOwnBookUCI = TRUE;\r
1890   appData.polyglotDir = "";\r
1891   appData.usePolyglotBook = FALSE;\r
1892   appData.polyglotBook = "";\r
1893   appData.defaultHashSize = 64;\r
1894   appData.defaultCacheSizeEGTB = 4;\r
1895   appData.defaultPathEGTB = "c:\\egtb";\r
1896 \r
1897   InitWindowPlacement( &wpMoveHistory );\r
1898   InitWindowPlacement( &wpEvalGraph );\r
1899   InitWindowPlacement( &wpEngineOutput );\r
1900 \r
1901   /* [HGM] User-selectable board size, adjudication control, miscellaneous */\r
1902   appData.NrFiles      = -1;\r
1903   appData.NrRanks      = -1;\r
1904   appData.holdingsSize = -1;\r
1905   appData.testClaims   = FALSE;\r
1906   appData.checkMates   = FALSE;\r
1907   appData.materialDraws= FALSE;\r
1908   appData.trivialDraws = FALSE;\r
1909   appData.ruleMoves    = 51;\r
1910   appData.drawRepeats  = 6;\r
1911   appData.matchPause   = 10000;\r
1912   appData.alphaRank    = FALSE;\r
1913   appData.allWhite     = FALSE;\r
1914   appData.upsideDown   = FALSE;\r
1915   appData.serverPause  = 15;\r
1916   appData.serverMovesName   = NULL;\r
1917   appData.suppressLoadMoves = FALSE;\r
1918   appData.firstTimeOdds  = 1;\r
1919   appData.secondTimeOdds = 1;\r
1920   appData.firstAccumulateTC  = 1; // combine previous and current sessions\r
1921   appData.secondAccumulateTC = 1;\r
1922   appData.firstNPS  = -1; // [HGM] nps: use wall-clock time\r
1923   appData.secondNPS = -1;\r
1924   appData.engineComments = 1;\r
1925 \r
1926 \r
1927 #ifdef ZIPPY\r
1928   appData.zippyTalk = ZIPPY_TALK;\r
1929   appData.zippyPlay = ZIPPY_PLAY;\r
1930   appData.zippyLines = ZIPPY_LINES;\r
1931   appData.zippyPinhead = ZIPPY_PINHEAD;\r
1932   appData.zippyPassword = ZIPPY_PASSWORD;\r
1933   appData.zippyPassword2 = ZIPPY_PASSWORD2;\r
1934   appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;\r
1935   appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;\r
1936   appData.zippyUseI = ZIPPY_USE_I;\r
1937   appData.zippyBughouse = ZIPPY_BUGHOUSE;\r
1938   appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;\r
1939   appData.zippyGameEnd = ZIPPY_GAME_END;\r
1940   appData.zippyGameStart = ZIPPY_GAME_START;\r
1941   appData.zippyAdjourn = ZIPPY_ADJOURN;\r
1942   appData.zippyAbort = ZIPPY_ABORT;\r
1943   appData.zippyVariants = ZIPPY_VARIANTS;\r
1944   appData.zippyMaxGames = ZIPPY_MAX_GAMES;\r
1945   appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;\r
1946 #endif\r
1947 \r
1948   /* Point font array elements to structures and\r
1949      parse default font names */\r
1950   for (i=0; i<NUM_FONTS; i++) {\r
1951     for (j=0; j<NUM_SIZES; j++) {\r
1952       font[j][i] = &fontRec[j][i];\r
1953       ParseFontName(font[j][i]->def, &font[j][i]->mfp);\r
1954     }\r
1955   }\r
1956   \r
1957   /* Parse default settings file if any */\r
1958   if (ParseSettingsFile(settingsFileName, buf)) {\r
1959     settingsFileName = strdup(buf);\r
1960   }\r
1961 \r
1962   /* Parse command line */\r
1963   ParseArgs(StringGet, &lpCmdLine);\r
1964 \r
1965   /* [HGM] make sure board size is acceptable */\r
1966   if(appData.NrFiles > BOARD_SIZE ||\r
1967      appData.NrRanks > BOARD_SIZE   )\r
1968       DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);\r
1969 \r
1970   /* [HGM] After parsing the options from the .ini file, and overruling them\r
1971    * with options from the command line, we now make an even higher priority\r
1972    * overrule by WB options attached to the engine command line. This so that\r
1973    * tournament managers can use WB options (such as /timeOdds) that follow\r
1974    * the engines.\r
1975    */\r
1976   if(appData.firstChessProgram != NULL) {\r
1977       char *p = StrStr(appData.firstChessProgram, "WBopt");\r
1978       static char *f = "first";\r
1979       char buf[MSG_SIZ], *q = buf;\r
1980       if(p != NULL) { // engine command line contains WinBoard options\r
1981           sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"\r
1982           ParseArgs(StringGet, &q);\r
1983           p[-1] = 0; // cut them offengine command line\r
1984       }\r
1985   }\r
1986   // now do same for second chess program\r
1987   if(appData.secondChessProgram != NULL) {\r
1988       char *p = StrStr(appData.secondChessProgram, "WBopt");\r
1989       static char *s = "second";\r
1990       char buf[MSG_SIZ], *q = buf;\r
1991       if(p != NULL) { // engine command line contains WinBoard options\r
1992           sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"\r
1993           ParseArgs(StringGet, &q);\r
1994           p[-1] = 0; // cut them offengine command line\r
1995       }\r
1996   }\r
1997 \r
1998 \r
1999   /* Propagate options that affect others */\r
2000   if (appData.matchMode || appData.matchGames) chessProgram = TRUE;\r
2001   if (appData.icsActive || appData.noChessProgram) {\r
2002      chessProgram = FALSE;  /* not local chess program mode */\r
2003   }\r
2004 \r
2005   /* Open startup dialog if needed */\r
2006   if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||\r
2007       (appData.icsActive && *appData.icsHost == NULLCHAR) ||\r
2008       (chessProgram && (*appData.firstChessProgram == NULLCHAR ||\r
2009                         *appData.secondChessProgram == NULLCHAR))) {\r
2010     FARPROC lpProc;\r
2011     \r
2012     lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);\r
2013     DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);\r
2014     FreeProcInstance(lpProc);\r
2015   }\r
2016 \r
2017   /* Make sure save files land in the right (?) directory */\r
2018   if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {\r
2019     appData.saveGameFile = strdup(buf);\r
2020   }\r
2021   if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {\r
2022     appData.savePositionFile = strdup(buf);\r
2023   }\r
2024 \r
2025   /* Finish initialization for fonts and sounds */\r
2026   for (i=0; i<NUM_FONTS; i++) {\r
2027     for (j=0; j<NUM_SIZES; j++) {\r
2028       CreateFontInMF(font[j][i]);\r
2029     }\r
2030   }\r
2031   /* xboard, and older WinBoards, controlled the move sound with the\r
2032      appData.ringBellAfterMoves option.  In the current WinBoard, we\r
2033      always turn the option on (so that the backend will call us),\r
2034      then let the user turn the sound off by setting it to silence if\r
2035      desired.  To accommodate old winboard.ini files saved by old\r
2036      versions of WinBoard, we also turn off the sound if the option\r
2037      was initially set to false. */\r
2038   if (!appData.ringBellAfterMoves) {\r
2039     sounds[(int)SoundMove].name = strdup("");\r
2040     appData.ringBellAfterMoves = TRUE;\r
2041   }\r
2042   GetCurrentDirectory(MSG_SIZ, currDir);\r
2043   SetCurrentDirectory(installDir);\r
2044   LoadAllSounds();\r
2045   SetCurrentDirectory(currDir);\r
2046 \r
2047   p = icsTextMenuString;\r
2048   if (p[0] == '@') {\r
2049     FILE* f = fopen(p + 1, "r");\r
2050     if (f == NULL) {\r
2051       DisplayFatalError(p + 1, errno, 2);\r
2052       return;\r
2053     }\r
2054     i = fread(buf, 1, sizeof(buf)-1, f);\r
2055     fclose(f);\r
2056     buf[i] = NULLCHAR;\r
2057     p = buf;\r
2058   }\r
2059   ParseIcsTextMenu(strdup(p));\r
2060 }\r
2061 \r
2062 \r
2063 VOID\r
2064 InitMenuChecks()\r
2065 {\r
2066   HMENU hmenu = GetMenu(hwndMain);\r
2067 \r
2068   (void) EnableMenuItem(hmenu, IDM_CommPort,\r
2069                         MF_BYCOMMAND|((appData.icsActive &&\r
2070                                        *appData.icsCommPort != NULLCHAR) ?\r
2071                                       MF_ENABLED : MF_GRAYED));\r
2072   (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,\r
2073                        MF_BYCOMMAND|(saveSettingsOnExit ?\r
2074                                      MF_CHECKED : MF_UNCHECKED));\r
2075 }\r
2076 \r
2077 \r
2078 VOID\r
2079 SaveSettings(char* name)\r
2080 {\r
2081   FILE *f;\r
2082   ArgDescriptor *ad;\r
2083   WINDOWPLACEMENT wp;\r
2084   char dir[MSG_SIZ];\r
2085 \r
2086   if (!hwndMain) return;\r
2087 \r
2088   GetCurrentDirectory(MSG_SIZ, dir);\r
2089   SetCurrentDirectory(installDir);\r
2090   f = fopen(name, "w");\r
2091   SetCurrentDirectory(dir);\r
2092   if (f == NULL) {\r
2093     DisplayError(name, errno);\r
2094     return;\r
2095   }\r
2096   fprintf(f, ";\n");\r
2097   fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);\r
2098   fprintf(f, ";\n");\r
2099   fprintf(f, "; You can edit the values of options that are already set in this file,\n");\r
2100   fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");\r
2101   fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");\r
2102   fprintf(f, ";\n");\r
2103 \r
2104   wp.length = sizeof(WINDOWPLACEMENT);\r
2105   GetWindowPlacement(hwndMain, &wp);\r
2106   boardX = wp.rcNormalPosition.left;\r
2107   boardY = wp.rcNormalPosition.top;\r
2108 \r
2109   if (hwndConsole) {\r
2110     GetWindowPlacement(hwndConsole, &wp);\r
2111     consoleX = wp.rcNormalPosition.left;\r
2112     consoleY = wp.rcNormalPosition.top;\r
2113     consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2114     consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2115   }\r
2116 \r
2117   if (analysisDialog) {\r
2118     GetWindowPlacement(analysisDialog, &wp);\r
2119     analysisX = wp.rcNormalPosition.left;\r
2120     analysisY = wp.rcNormalPosition.top;\r
2121     analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2122     analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2123   }\r
2124 \r
2125   if (commentDialog) {\r
2126     GetWindowPlacement(commentDialog, &wp);\r
2127     commentX = wp.rcNormalPosition.left;\r
2128     commentY = wp.rcNormalPosition.top;\r
2129     commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2130     commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2131   }\r
2132 \r
2133   if (editTagsDialog) {\r
2134     GetWindowPlacement(editTagsDialog, &wp);\r
2135     editTagsX = wp.rcNormalPosition.left;\r
2136     editTagsY = wp.rcNormalPosition.top;\r
2137     editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2138     editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2139   }\r
2140 \r
2141   if (gameListDialog) {\r
2142     GetWindowPlacement(gameListDialog, &wp);\r
2143     gameListX = wp.rcNormalPosition.left;\r
2144     gameListY = wp.rcNormalPosition.top;\r
2145     gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2146     gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2147   }\r
2148 \r
2149   /* [AS] Move history */\r
2150   wpMoveHistory.visible = MoveHistoryIsUp();\r
2151   \r
2152   if( moveHistoryDialog ) {\r
2153     GetWindowPlacement(moveHistoryDialog, &wp);\r
2154     wpMoveHistory.x = wp.rcNormalPosition.left;\r
2155     wpMoveHistory.y = wp.rcNormalPosition.top;\r
2156     wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2157     wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2158   }\r
2159 \r
2160   /* [AS] Eval graph */\r
2161   wpEvalGraph.visible = EvalGraphIsUp();\r
2162 \r
2163   if( evalGraphDialog ) {\r
2164     GetWindowPlacement(evalGraphDialog, &wp);\r
2165     wpEvalGraph.x = wp.rcNormalPosition.left;\r
2166     wpEvalGraph.y = wp.rcNormalPosition.top;\r
2167     wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2168     wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2169   }\r
2170 \r
2171   /* [AS] Engine output */\r
2172   wpEngineOutput.visible = EngineOutputIsUp();\r
2173 \r
2174   if( engineOutputDialog ) {\r
2175     GetWindowPlacement(engineOutputDialog, &wp);\r
2176     wpEngineOutput.x = wp.rcNormalPosition.left;\r
2177     wpEngineOutput.y = wp.rcNormalPosition.top;\r
2178     wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2179     wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2180   }\r
2181 \r
2182   for (ad = argDescriptors; ad->argName != NULL; ad++) {\r
2183     if (!ad->save) continue;\r
2184     switch (ad->argType) {\r
2185     case ArgString:\r
2186       {\r
2187         char *p = *(char **)ad->argLoc;\r
2188         if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {\r
2189           /* Quote multiline values or \-containing values\r
2190              with { } if possible */\r
2191           fprintf(f, "/%s={%s}\n", ad->argName, p);\r
2192         } else {\r
2193           /* Else quote with " " */\r
2194           fprintf(f, "/%s=\"", ad->argName);\r
2195           while (*p) {\r
2196             if (*p == '\n') fprintf(f, "\n");\r
2197             else if (*p == '\r') fprintf(f, "\\r");\r
2198             else if (*p == '\t') fprintf(f, "\\t");\r
2199             else if (*p == '\b') fprintf(f, "\\b");\r
2200             else if (*p == '\f') fprintf(f, "\\f");\r
2201             else if (*p < ' ') fprintf(f, "\\%03o", *p);\r
2202             else if (*p == '\"') fprintf(f, "\\\"");\r
2203             else if (*p == '\\') fprintf(f, "\\\\");\r
2204             else putc(*p, f);\r
2205             p++;\r
2206           }\r
2207           fprintf(f, "\"\n");\r
2208         }\r
2209       }\r
2210       break;\r
2211     case ArgInt:\r
2212       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);\r
2213       break;\r
2214     case ArgFloat:\r
2215       fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);\r
2216       break;\r
2217     case ArgBoolean:\r
2218       fprintf(f, "/%s=%s\n", ad->argName, \r
2219         (*(Boolean *)ad->argLoc) ? "true" : "false");\r
2220       break;\r
2221     case ArgTrue:\r
2222       if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
2223       break;\r
2224     case ArgFalse:\r
2225       if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
2226       break;\r
2227     case ArgColor:\r
2228       {\r
2229         COLORREF color = *(COLORREF *)ad->argLoc;\r
2230         fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName, \r
2231           color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
2232       }\r
2233       break;\r
2234     case ArgAttribs:\r
2235       {\r
2236         MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];\r
2237         fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,\r
2238           (ta->effects & CFE_BOLD) ? "b" : "",\r
2239           (ta->effects & CFE_ITALIC) ? "i" : "",\r
2240           (ta->effects & CFE_UNDERLINE) ? "u" : "",\r
2241           (ta->effects & CFE_STRIKEOUT) ? "s" : "",\r
2242           (ta->effects) ? " " : "",\r
2243           ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);\r
2244       }\r
2245       break;\r
2246     case ArgFilename:\r
2247       if (strchr(*(char **)ad->argLoc, '\"')) {\r
2248         fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);\r
2249       } else {\r
2250         fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);\r
2251       }\r
2252       break;\r
2253     case ArgBoardSize:\r
2254       fprintf(f, "/%s=%s\n", ad->argName,\r
2255               sizeInfo[*(BoardSize *)ad->argLoc].name);\r
2256       break;\r
2257     case ArgFont:\r
2258       {\r
2259         int bs;\r
2260         for (bs=0; bs<NUM_SIZES; bs++) {\r
2261           MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;\r
2262           fprintf(f, "/size=%s ", sizeInfo[bs].name);\r
2263           fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",\r
2264             ad->argName, mfp->faceName, mfp->pointSize,\r
2265             mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",\r
2266             mfp->bold ? "b" : "",\r
2267             mfp->italic ? "i" : "",\r
2268             mfp->underline ? "u" : "",\r
2269             mfp->strikeout ? "s" : "");\r
2270         }\r
2271       }\r
2272       break;\r
2273     case ArgCommSettings:\r
2274       PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);\r
2275     }\r
2276   }\r
2277   fclose(f);\r
2278 }\r
2279 \r
2280 \r
2281 \r
2282 /*---------------------------------------------------------------------------*\\r
2283  *\r
2284  * GDI board drawing routines\r
2285  *\r
2286 \*---------------------------------------------------------------------------*/\r
2287 \r
2288 /* [AS] Draw square using background texture */\r
2289 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )\r
2290 {\r
2291     XFORM   x;\r
2292 \r
2293     if( mode == 0 ) {\r
2294         return; /* Should never happen! */\r
2295     }\r
2296 \r
2297     SetGraphicsMode( dst, GM_ADVANCED );\r
2298 \r
2299     switch( mode ) {\r
2300     case 1:\r
2301         /* Identity */\r
2302         break;\r
2303     case 2:\r
2304         /* X reflection */\r
2305         x.eM11 = -1.0;\r
2306         x.eM12 = 0;\r
2307         x.eM21 = 0;\r
2308         x.eM22 = 1.0;\r
2309         x.eDx = (FLOAT) dw + dx - 1;\r
2310         x.eDy = 0;\r
2311         dx = 0;\r
2312         SetWorldTransform( dst, &x );\r
2313         break;\r
2314     case 3:\r
2315         /* Y reflection */\r
2316         x.eM11 = 1.0;\r
2317         x.eM12 = 0;\r
2318         x.eM21 = 0;\r
2319         x.eM22 = -1.0;\r
2320         x.eDx = 0;\r
2321         x.eDy = (FLOAT) dh + dy - 1;\r
2322         dy = 0;\r
2323         SetWorldTransform( dst, &x );\r
2324         break;\r
2325     case 4:\r
2326         /* X/Y flip */\r
2327         x.eM11 = 0;\r
2328         x.eM12 = 1.0;\r
2329         x.eM21 = 1.0;\r
2330         x.eM22 = 0;\r
2331         x.eDx = (FLOAT) dx;\r
2332         x.eDy = (FLOAT) dy;\r
2333         dx = 0;\r
2334         dy = 0;\r
2335         SetWorldTransform( dst, &x );\r
2336         break;\r
2337     }\r
2338 \r
2339     BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );\r
2340 \r
2341     x.eM11 = 1.0;\r
2342     x.eM12 = 0;\r
2343     x.eM21 = 0;\r
2344     x.eM22 = 1.0;\r
2345     x.eDx = 0;\r
2346     x.eDy = 0;\r
2347     SetWorldTransform( dst, &x );\r
2348 \r
2349     ModifyWorldTransform( dst, 0, MWT_IDENTITY );\r
2350 }\r
2351 \r
2352 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */\r
2353 enum {\r
2354     PM_WP = (int) WhitePawn, \r
2355     PM_WN = (int) WhiteKnight, \r
2356     PM_WB = (int) WhiteBishop, \r
2357     PM_WR = (int) WhiteRook, \r
2358     PM_WQ = (int) WhiteQueen, \r
2359     PM_WF = (int) WhiteFerz, \r
2360     PM_WW = (int) WhiteWazir, \r
2361     PM_WE = (int) WhiteAlfil, \r
2362     PM_WM = (int) WhiteMan, \r
2363     PM_WO = (int) WhiteCannon, \r
2364     PM_WU = (int) WhiteUnicorn, \r
2365     PM_WH = (int) WhiteNightrider, \r
2366     PM_WA = (int) WhiteAngel, \r
2367     PM_WC = (int) WhiteMarshall, \r
2368     PM_WG = (int) WhiteGrasshopper, \r
2369     PM_WK = (int) WhiteKing,\r
2370     PM_BP = (int) BlackPawn, \r
2371     PM_BN = (int) BlackKnight, \r
2372     PM_BB = (int) BlackBishop, \r
2373     PM_BR = (int) BlackRook, \r
2374     PM_BQ = (int) BlackQueen, \r
2375     PM_BF = (int) BlackFerz, \r
2376     PM_BW = (int) BlackWazir, \r
2377     PM_BE = (int) BlackAlfil, \r
2378     PM_BM = (int) BlackMan,\r
2379     PM_BO = (int) BlackCannon, \r
2380     PM_BU = (int) BlackUnicorn, \r
2381     PM_BH = (int) BlackNightrider, \r
2382     PM_BA = (int) BlackAngel, \r
2383     PM_BC = (int) BlackMarshall, \r
2384     PM_BG = (int) BlackGrasshopper, \r
2385     PM_BK = (int) BlackKing\r
2386 };\r
2387 \r
2388 static HFONT hPieceFont = NULL;\r
2389 static HBITMAP hPieceMask[(int) EmptySquare];\r
2390 static HBITMAP hPieceFace[(int) EmptySquare];\r
2391 static int fontBitmapSquareSize = 0;\r
2392 static char pieceToFontChar[(int) EmptySquare] =\r
2393                               { 'p', 'n', 'b', 'r', 'q', \r
2394                       'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',\r
2395                       'k', 'o', 'm', 'v', 't', 'w', \r
2396                       'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',\r
2397                                                               'l' };\r
2398 \r
2399 extern BOOL SetCharTable( char *table, const char * map );\r
2400 /* [HGM] moved to backend.c */\r
2401 \r
2402 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )\r
2403 {\r
2404     HBRUSH hbrush;\r
2405     BYTE r1 = GetRValue( color );\r
2406     BYTE g1 = GetGValue( color );\r
2407     BYTE b1 = GetBValue( color );\r
2408     BYTE r2 = r1 / 2;\r
2409     BYTE g2 = g1 / 2;\r
2410     BYTE b2 = b1 / 2;\r
2411     RECT rc;\r
2412 \r
2413     /* Create a uniform background first */\r
2414     hbrush = CreateSolidBrush( color );\r
2415     SetRect( &rc, 0, 0, squareSize, squareSize );\r
2416     FillRect( hdc, &rc, hbrush );\r
2417     DeleteObject( hbrush );\r
2418     \r
2419     if( mode == 1 ) {\r
2420         /* Vertical gradient, good for pawn, knight and rook, less for queen and king */\r
2421         int steps = squareSize / 2;\r
2422         int i;\r
2423 \r
2424         for( i=0; i<steps; i++ ) {\r
2425             BYTE r = r1 - (r1-r2) * i / steps;\r
2426             BYTE g = g1 - (g1-g2) * i / steps;\r
2427             BYTE b = b1 - (b1-b2) * i / steps;\r
2428 \r
2429             hbrush = CreateSolidBrush( RGB(r,g,b) );\r
2430             SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );\r
2431             FillRect( hdc, &rc, hbrush );\r
2432             DeleteObject(hbrush);\r
2433         }\r
2434     }\r
2435     else if( mode == 2 ) {\r
2436         /* Diagonal gradient, good more or less for every piece */\r
2437         POINT triangle[3];\r
2438         HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );\r
2439         HBRUSH hbrush_old;\r
2440         int steps = squareSize;\r
2441         int i;\r
2442 \r
2443         triangle[0].x = squareSize - steps;\r
2444         triangle[0].y = squareSize;\r
2445         triangle[1].x = squareSize;\r
2446         triangle[1].y = squareSize;\r
2447         triangle[2].x = squareSize;\r
2448         triangle[2].y = squareSize - steps;\r
2449 \r
2450         for( i=0; i<steps; i++ ) {\r
2451             BYTE r = r1 - (r1-r2) * i / steps;\r
2452             BYTE g = g1 - (g1-g2) * i / steps;\r
2453             BYTE b = b1 - (b1-b2) * i / steps;\r
2454 \r
2455             hbrush = CreateSolidBrush( RGB(r,g,b) );\r
2456             hbrush_old = SelectObject( hdc, hbrush );\r
2457             Polygon( hdc, triangle, 3 );\r
2458             SelectObject( hdc, hbrush_old );\r
2459             DeleteObject(hbrush);\r
2460             triangle[0].x++;\r
2461             triangle[2].y++;\r
2462         }\r
2463 \r
2464         SelectObject( hdc, hpen );\r
2465     }\r
2466 }\r
2467 \r
2468 /*\r
2469     [AS] The method I use to create the bitmaps it a bit tricky, but it\r
2470     seems to work ok. The main problem here is to find the "inside" of a chess\r
2471     piece: follow the steps as explained below.\r
2472 */\r
2473 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )\r
2474 {\r
2475     HBITMAP hbm;\r
2476     HBITMAP hbm_old;\r
2477     COLORREF chroma = RGB(0xFF,0x00,0xFF);\r
2478     RECT rc;\r
2479     SIZE sz;\r
2480     POINT pt;\r
2481     int backColor = whitePieceColor; \r
2482     int foreColor = blackPieceColor;\r
2483     int shapeIndex = index < 6 ? index+6 : index;\r
2484     \r
2485     if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {\r
2486         backColor = appData.fontBackColorWhite;\r
2487         foreColor = appData.fontForeColorWhite;\r
2488     }\r
2489     else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {\r
2490         backColor = appData.fontBackColorBlack;\r
2491         foreColor = appData.fontForeColorBlack;\r
2492     }\r
2493 \r
2494     /* Mask */\r
2495     hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2496 \r
2497     hbm_old = SelectObject( hdc, hbm );\r
2498 \r
2499     rc.left = 0;\r
2500     rc.top = 0;\r
2501     rc.right = squareSize;\r
2502     rc.bottom = squareSize;\r
2503 \r
2504     /* Step 1: background is now black */\r
2505     FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );\r
2506 \r
2507     GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );\r
2508 \r
2509     pt.x = (squareSize - sz.cx) / 2;\r
2510     pt.y = (squareSize - sz.cy) / 2;\r
2511 \r
2512     SetBkMode( hdc, TRANSPARENT );\r
2513     SetTextColor( hdc, chroma );\r
2514     /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */\r
2515     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );\r
2516 \r
2517     SelectObject( hdc, GetStockObject(WHITE_BRUSH) );\r
2518     /* Step 3: the area outside the piece is filled with white */\r
2519     FloodFill( hdc, 0, 0, chroma );\r
2520     SelectObject( hdc, GetStockObject(BLACK_BRUSH) );\r
2521     /* \r
2522         Step 4: this is the tricky part, the area inside the piece is filled with black,\r
2523         but if the start point is not inside the piece we're lost!\r
2524         There should be a better way to do this... if we could create a region or path\r
2525         from the fill operation we would be fine for example.\r
2526     */\r
2527     FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );\r
2528 \r
2529     SetTextColor( hdc, 0 );\r
2530     /* \r
2531         Step 5: some fonts have "disconnected" areas that are skipped by the fill:\r
2532         draw the piece again in black for safety.\r
2533     */\r
2534     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );\r
2535 \r
2536     SelectObject( hdc, hbm_old );\r
2537 \r
2538     if( hPieceMask[index] != NULL ) {\r
2539         DeleteObject( hPieceMask[index] );\r
2540     }\r
2541 \r
2542     hPieceMask[index] = hbm;\r
2543 \r
2544     /* Face */\r
2545     hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2546 \r
2547     SelectObject( hdc, hbm );\r
2548 \r
2549     {\r
2550         HDC dc1 = CreateCompatibleDC( hdc_window );\r
2551         HDC dc2 = CreateCompatibleDC( hdc_window );\r
2552         HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2553 \r
2554         SelectObject( dc1, hPieceMask[index] );\r
2555         SelectObject( dc2, bm2 );\r
2556         FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );\r
2557         BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );\r
2558         \r
2559         /* \r
2560             Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves\r
2561             the piece background and deletes (makes transparent) the rest.\r
2562             Thanks to that mask, we are free to paint the background with the greates\r
2563             freedom, as we'll be able to mask off the unwanted parts when finished.\r
2564             We use this, to make gradients and give the pieces a "roundish" look.\r
2565         */\r
2566         SetPieceBackground( hdc, backColor, 2 );\r
2567         BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );\r
2568 \r
2569         DeleteDC( dc2 );\r
2570         DeleteDC( dc1 );\r
2571         DeleteObject( bm2 );\r
2572     }\r
2573 \r
2574     SetTextColor( hdc, foreColor );\r
2575     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );\r
2576 \r
2577     SelectObject( hdc, hbm_old );\r
2578 \r
2579     if( hPieceFace[index] != NULL ) {\r
2580         DeleteObject( hPieceFace[index] );\r
2581     }\r
2582 \r
2583     hPieceFace[index] = hbm;\r
2584 }\r
2585 \r
2586 static int TranslatePieceToFontPiece( int piece )\r
2587 {\r
2588     switch( piece ) {\r
2589     case BlackPawn:\r
2590         return PM_BP;\r
2591     case BlackKnight:\r
2592         return PM_BN;\r
2593     case BlackBishop:\r
2594         return PM_BB;\r
2595     case BlackRook:\r
2596         return PM_BR;\r
2597     case BlackQueen:\r
2598         return PM_BQ;\r
2599     case BlackKing:\r
2600         return PM_BK;\r
2601     case WhitePawn:\r
2602         return PM_WP;\r
2603     case WhiteKnight:\r
2604         return PM_WN;\r
2605     case WhiteBishop:\r
2606         return PM_WB;\r
2607     case WhiteRook:\r
2608         return PM_WR;\r
2609     case WhiteQueen:\r
2610         return PM_WQ;\r
2611     case WhiteKing:\r
2612         return PM_WK;\r
2613     case BlackAngel:\r
2614         return PM_BA;\r
2615     case BlackMarshall:\r
2616         return PM_BC;\r
2617     case BlackFerz:\r
2618         return PM_BF;\r
2619     case BlackNightrider:\r
2620         return PM_BH;\r
2621     case BlackAlfil:\r
2622         return PM_BE;\r
2623     case BlackWazir:\r
2624         return PM_BW;\r
2625     case BlackUnicorn:\r
2626         return PM_BU;\r
2627     case BlackCannon:\r
2628         return PM_BO;\r
2629     case BlackGrasshopper:\r
2630         return PM_BG;\r
2631     case BlackMan:\r
2632         return PM_BM;\r
2633     case WhiteAngel:\r
2634         return PM_WA;\r
2635     case WhiteMarshall:\r
2636         return PM_WC;\r
2637     case WhiteFerz:\r
2638         return PM_WF;\r
2639     case WhiteNightrider:\r
2640         return PM_WH;\r
2641     case WhiteAlfil:\r
2642         return PM_WE;\r
2643     case WhiteWazir:\r
2644         return PM_WW;\r
2645     case WhiteUnicorn:\r
2646         return PM_WU;\r
2647     case WhiteCannon:\r
2648         return PM_WO;\r
2649     case WhiteGrasshopper:\r
2650         return PM_WG;\r
2651     case WhiteMan:\r
2652         return PM_WM;\r
2653     }\r
2654 \r
2655     return 0;\r
2656 }\r
2657 \r
2658 void CreatePiecesFromFont()\r
2659 {\r
2660     LOGFONT lf;\r
2661     HDC hdc_window = NULL;\r
2662     HDC hdc = NULL;\r
2663     HFONT hfont_old;\r
2664     int fontHeight;\r
2665     int i;\r
2666 \r
2667     if( fontBitmapSquareSize < 0 ) {\r
2668         /* Something went seriously wrong in the past: do not try to recreate fonts! */\r
2669         return;\r
2670     }\r
2671 \r
2672     if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {\r
2673         fontBitmapSquareSize = -1;\r
2674         return;\r
2675     }\r
2676 \r
2677     if( fontBitmapSquareSize != squareSize ) {\r
2678         hdc_window = GetDC( hwndMain );\r
2679         hdc = CreateCompatibleDC( hdc_window );\r
2680 \r
2681         if( hPieceFont != NULL ) {\r
2682             DeleteObject( hPieceFont );\r
2683         }\r
2684         else {\r
2685             for( i=0; i<12; i++ ) {\r
2686                 hPieceMask[i] = NULL;\r
2687                 hPieceFace[i] = NULL;\r
2688             }\r
2689         }\r
2690 \r
2691         fontHeight = 75;\r
2692 \r
2693         if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {\r
2694             fontHeight = appData.fontPieceSize;\r
2695         }\r
2696 \r
2697         fontHeight = (fontHeight * squareSize) / 100;\r
2698 \r
2699         lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );\r
2700         lf.lfWidth = 0;\r
2701         lf.lfEscapement = 0;\r
2702         lf.lfOrientation = 0;\r
2703         lf.lfWeight = FW_NORMAL;\r
2704         lf.lfItalic = 0;\r
2705         lf.lfUnderline = 0;\r
2706         lf.lfStrikeOut = 0;\r
2707         lf.lfCharSet = DEFAULT_CHARSET;\r
2708         lf.lfOutPrecision = OUT_DEFAULT_PRECIS;\r
2709         lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
2710         lf.lfQuality = PROOF_QUALITY;\r
2711         lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;\r
2712         strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );\r
2713         lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';\r
2714 \r
2715         hPieceFont = CreateFontIndirect( &lf );\r
2716 \r
2717         if( hPieceFont == NULL ) {\r
2718             fontBitmapSquareSize = -2;\r
2719         }\r
2720         else {\r
2721             /* Setup font-to-piece character table */\r
2722             if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {\r
2723                 /* No (or wrong) global settings, try to detect the font */\r
2724                 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {\r
2725                     /* Alpha */\r
2726                     SetCharTable(pieceToFontChar, "phbrqkojntwl");\r
2727                 }\r
2728                 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {\r
2729                     /* DiagramTT* family */\r
2730                     SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");\r
2731                 }\r
2732                 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {\r
2733                     /* Fairy symbols */\r
2734                      SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");\r
2735                 }\r
2736                 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {\r
2737                     /* Good Companion (Some characters get warped as literal :-( */\r
2738                     char s[] = "1cmWG0ñueOS¯®oYI23wgQU";\r
2739                     s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;\r
2740                     SetCharTable(pieceToFontChar, s);\r
2741                 }\r
2742                 else {\r
2743                     /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */\r
2744                     SetCharTable(pieceToFontChar, "pnbrqkomvtwl");\r
2745                 }\r
2746             }\r
2747 \r
2748             /* Create bitmaps */\r
2749             hfont_old = SelectObject( hdc, hPieceFont );\r
2750 \r
2751             CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );\r
2752             CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );\r
2753             CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );\r
2754             CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );\r
2755             CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );\r
2756             CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );\r
2757             CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );\r
2758             CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );\r
2759             CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );\r
2760             CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );\r
2761             CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );\r
2762             CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );\r
2763 #ifdef FAIRY\r
2764             CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );\r
2765             CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );\r
2766             CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );\r
2767             CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );\r
2768             CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );\r
2769             CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );\r
2770             CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );\r
2771             CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );\r
2772             CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );\r
2773             CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );\r
2774             CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );\r
2775             CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );\r
2776             CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );\r
2777             CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );\r
2778             CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );\r
2779             CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );\r
2780             CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );\r
2781             CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );\r
2782             CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );\r
2783             CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );\r
2784 #endif\r
2785 \r
2786             SelectObject( hdc, hfont_old );\r
2787 \r
2788             fontBitmapSquareSize = squareSize;\r
2789         }\r
2790     }\r
2791 \r
2792     if( hdc != NULL ) {\r
2793         DeleteDC( hdc );\r
2794     }\r
2795 \r
2796     if( hdc_window != NULL ) {\r
2797         ReleaseDC( hwndMain, hdc_window );\r
2798     }\r
2799 }\r
2800 \r
2801 HBITMAP\r
2802 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)\r
2803 {\r
2804   char name[128];\r
2805 \r
2806   sprintf(name, "%s%d%s", piece, squareSize, suffix);\r
2807   if (gameInfo.event &&\r
2808       strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&\r
2809       strcmp(name, "k80s") == 0) {\r
2810     strcpy(name, "tim");\r
2811   }\r
2812   return LoadBitmap(hinst, name);\r
2813 }\r
2814 \r
2815 \r
2816 /* Insert a color into the program's logical palette\r
2817    structure.  This code assumes the given color is\r
2818    the result of the RGB or PALETTERGB macro, and it\r
2819    knows how those macros work (which is documented).\r
2820 */\r
2821 VOID\r
2822 InsertInPalette(COLORREF color)\r
2823 {\r
2824   LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);\r
2825 \r
2826   if (pLogPal->palNumEntries++ >= PALETTESIZE) {\r
2827     DisplayFatalError("Too many colors", 0, 1);\r
2828     pLogPal->palNumEntries--;\r
2829     return;\r
2830   }\r
2831 \r
2832   pe->peFlags = (char) 0;\r
2833   pe->peRed = (char) (0xFF & color);\r
2834   pe->peGreen = (char) (0xFF & (color >> 8));\r
2835   pe->peBlue = (char) (0xFF & (color >> 16));\r
2836   return;\r
2837 }\r
2838 \r
2839 \r
2840 VOID\r
2841 InitDrawingColors()\r
2842 {\r
2843   if (pLogPal == NULL) {\r
2844     /* Allocate enough memory for a logical palette with\r
2845      * PALETTESIZE entries and set the size and version fields\r
2846      * of the logical palette structure.\r
2847      */\r
2848     pLogPal = (NPLOGPALETTE)\r
2849       LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +\r
2850                               (sizeof(PALETTEENTRY) * (PALETTESIZE))));\r
2851     pLogPal->palVersion    = 0x300;\r
2852   }\r
2853   pLogPal->palNumEntries = 0;\r
2854 \r
2855   InsertInPalette(lightSquareColor);\r
2856   InsertInPalette(darkSquareColor);\r
2857   InsertInPalette(whitePieceColor);\r
2858   InsertInPalette(blackPieceColor);\r
2859   InsertInPalette(highlightSquareColor);\r
2860   InsertInPalette(premoveHighlightColor);\r
2861 \r
2862   /*  create a logical color palette according the information\r
2863    *  in the LOGPALETTE structure.\r
2864    */\r
2865   hPal = CreatePalette((LPLOGPALETTE) pLogPal);\r
2866 \r
2867   lightSquareBrush = CreateSolidBrush(lightSquareColor);\r
2868   blackSquareBrush = CreateSolidBrush(blackPieceColor);\r
2869   darkSquareBrush = CreateSolidBrush(darkSquareColor);\r
2870   whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
2871   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
2872   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
2873 \r
2874   /* [AS] Force rendering of the font-based pieces */\r
2875   if( fontBitmapSquareSize > 0 ) {\r
2876     fontBitmapSquareSize = 0;\r
2877   }\r
2878 }\r
2879 \r
2880 \r
2881 int\r
2882 BoardWidth(int boardSize, int n)\r
2883 { /* [HGM] argument n added to allow different width and height */\r
2884   int lineGap = sizeInfo[boardSize].lineGap;\r
2885 \r
2886   if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
2887       lineGap = appData.overrideLineGap;\r
2888   }\r
2889 \r
2890   return (n + 1) * lineGap +\r
2891           n * sizeInfo[boardSize].squareSize;\r
2892 }\r
2893 \r
2894 /* Respond to board resize by dragging edge */\r
2895 VOID\r
2896 ResizeBoard(int newSizeX, int newSizeY, int flags)\r
2897 {\r
2898   BoardSize newSize = NUM_SIZES - 1;\r
2899   static int recurse = 0;\r
2900   if (IsIconic(hwndMain)) return;\r
2901   if (recurse > 0) return;\r
2902   recurse++;\r
2903   while (newSize > 0 &&\r
2904          (newSizeX < sizeInfo[newSize].cliWidth ||\r
2905           newSizeY < sizeInfo[newSize].cliHeight)) {\r
2906     newSize--;\r
2907   } \r
2908   boardSize = newSize;\r
2909   InitDrawingSizes(boardSize, flags);\r
2910   recurse--;\r
2911 }\r
2912 \r
2913 \r
2914 \r
2915 VOID\r
2916 InitDrawingSizes(BoardSize boardSize, int flags)\r
2917 {\r
2918   int i, boardWidth, boardHeight; /* [HGM] height treated separately */\r
2919   ChessSquare piece;\r
2920   static int oldBoardSize = -1, oldTinyLayout = 0;\r
2921   HDC hdc;\r
2922   SIZE clockSize, messageSize;\r
2923   HFONT oldFont;\r
2924   char buf[MSG_SIZ];\r
2925   char *str;\r
2926   HMENU hmenu = GetMenu(hwndMain);\r
2927   RECT crect, wrect;\r
2928   int offby;\r
2929   LOGBRUSH logbrush;\r
2930 \r
2931   /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */\r
2932   if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;\r
2933 \r
2934   tinyLayout = sizeInfo[boardSize].tinyLayout;\r
2935   smallLayout = sizeInfo[boardSize].smallLayout;\r
2936   squareSize = sizeInfo[boardSize].squareSize;\r
2937   lineGap = sizeInfo[boardSize].lineGap;\r
2938   minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted  */\r
2939 \r
2940   if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
2941       lineGap = appData.overrideLineGap;\r
2942   }\r
2943 \r
2944   if (tinyLayout != oldTinyLayout) {\r
2945     long style = GetWindowLong(hwndMain, GWL_STYLE);\r
2946     if (tinyLayout) {\r
2947       style &= ~WS_SYSMENU;\r
2948       InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,\r
2949                  "&Minimize\tCtrl+F4");\r
2950     } else {\r
2951       style |= WS_SYSMENU;\r
2952       RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);\r
2953     }\r
2954     SetWindowLong(hwndMain, GWL_STYLE, style);\r
2955 \r
2956     for (i=0; menuBarText[tinyLayout][i]; i++) {\r
2957       ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP, \r
2958         (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);\r
2959     }\r
2960     DrawMenuBar(hwndMain);\r
2961   }\r
2962 \r
2963   boardWidth  = BoardWidth(boardSize, BOARD_WIDTH);\r
2964   boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);\r
2965 \r
2966   /* Get text area sizes */\r
2967   hdc = GetDC(hwndMain);\r
2968   if (appData.clockMode) {\r
2969     sprintf(buf, "White: %s", TimeString(23*60*60*1000L));\r
2970   } else {\r
2971     sprintf(buf, "White");\r
2972   }\r
2973   oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
2974   GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);\r
2975   SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
2976   str = "We only care about the height here";\r
2977   GetTextExtentPoint(hdc, str, strlen(str), &messageSize);\r
2978   SelectObject(hdc, oldFont);\r
2979   ReleaseDC(hwndMain, hdc);\r
2980 \r
2981   /* Compute where everything goes */\r
2982   whiteRect.left = OUTER_MARGIN;\r
2983   whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;\r
2984   whiteRect.top = OUTER_MARGIN;\r
2985   whiteRect.bottom = whiteRect.top + clockSize.cy;\r
2986 \r
2987   blackRect.left = whiteRect.right + INNER_MARGIN;\r
2988   blackRect.right = blackRect.left + boardWidth/2 - 1;\r
2989   blackRect.top = whiteRect.top;\r
2990   blackRect.bottom = whiteRect.bottom;\r
2991 \r
2992   messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;\r
2993   if (appData.showButtonBar) {\r
2994     messageRect.right = blackRect.right\r
2995       - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;\r
2996   } else {\r
2997     messageRect.right = blackRect.right;\r
2998   }\r
2999   messageRect.top = whiteRect.bottom + INNER_MARGIN;\r
3000   messageRect.bottom = messageRect.top + messageSize.cy;\r
3001 \r
3002   boardRect.left = whiteRect.left;\r
3003   boardRect.right = boardRect.left + boardWidth;\r
3004   boardRect.top = messageRect.bottom + INNER_MARGIN;\r
3005   boardRect.bottom = boardRect.top + boardHeight;\r
3006 \r
3007   sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;\r
3008   sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;\r
3009   winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;\r
3010   winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +\r
3011     GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;\r
3012   GetWindowRect(hwndMain, &wrect);\r
3013   SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,\r
3014                SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
3015   /* compensate if menu bar wrapped */\r
3016   GetClientRect(hwndMain, &crect);\r
3017   offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;\r
3018   winHeight += offby;\r
3019   switch (flags) {\r
3020   case WMSZ_TOPLEFT:\r
3021     SetWindowPos(hwndMain, NULL, \r
3022                  wrect.right - winWidth, wrect.bottom - winHeight, \r
3023                  winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
3024     break;\r
3025 \r
3026   case WMSZ_TOPRIGHT:\r
3027   case WMSZ_TOP:\r
3028     SetWindowPos(hwndMain, NULL, \r
3029                  wrect.left, wrect.bottom - winHeight, \r
3030                  winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
3031     break;\r
3032 \r
3033   case WMSZ_BOTTOMLEFT:\r
3034   case WMSZ_LEFT:\r
3035     SetWindowPos(hwndMain, NULL, \r
3036                  wrect.right - winWidth, wrect.top, \r
3037                  winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
3038     break;\r
3039 \r
3040   case WMSZ_BOTTOMRIGHT:\r
3041   case WMSZ_BOTTOM:\r
3042   case WMSZ_RIGHT:\r
3043   default:\r
3044     SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,\r
3045                SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
3046     break;\r
3047   }\r
3048 \r
3049   hwndPause = NULL;\r
3050   for (i = 0; i < N_BUTTONS; i++) {\r
3051     if (buttonDesc[i].hwnd != NULL) {\r
3052       DestroyWindow(buttonDesc[i].hwnd);\r
3053       buttonDesc[i].hwnd = NULL;\r
3054     }\r
3055     if (appData.showButtonBar) {\r
3056       buttonDesc[i].hwnd =\r
3057         CreateWindow("BUTTON", buttonDesc[i].label,\r
3058                      WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,\r
3059                      boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),\r
3060                      messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,\r
3061                      (HMENU) buttonDesc[i].id,\r
3062                      (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);\r
3063       if (tinyLayout) {\r
3064         SendMessage(buttonDesc[i].hwnd, WM_SETFONT, \r
3065                     (WPARAM)font[boardSize][MESSAGE_FONT]->hf,\r
3066                     MAKELPARAM(FALSE, 0));\r
3067       }\r
3068       if (buttonDesc[i].id == IDM_Pause)\r
3069         hwndPause = buttonDesc[i].hwnd;\r
3070       buttonDesc[i].wndproc = (WNDPROC)\r
3071         SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);\r
3072     }\r
3073   }\r
3074   if (gridPen != NULL) DeleteObject(gridPen);\r
3075   if (highlightPen != NULL) DeleteObject(highlightPen);\r
3076   if (premovePen != NULL) DeleteObject(premovePen);\r
3077   if (lineGap != 0) {\r
3078     logbrush.lbStyle = BS_SOLID;\r
3079     logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */\r
3080     gridPen =\r
3081       ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
3082                    lineGap, &logbrush, 0, NULL);\r
3083     logbrush.lbColor = highlightSquareColor;\r
3084     highlightPen =\r
3085       ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
3086                    lineGap, &logbrush, 0, NULL);\r
3087 \r
3088     logbrush.lbColor = premoveHighlightColor; \r
3089     premovePen =\r
3090       ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
3091                    lineGap, &logbrush, 0, NULL);\r
3092 \r
3093     /* [HGM] Loop had to be split in part for vert. and hor. lines */\r
3094     for (i = 0; i < BOARD_HEIGHT + 1; i++) {\r
3095       gridEndpoints[i*2].x = boardRect.left + lineGap / 2;\r
3096       gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =\r
3097         boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));\r
3098       gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +\r
3099         BOARD_WIDTH * (squareSize + lineGap);\r
3100         lineGap / 2 + (i * (squareSize + lineGap));\r
3101       gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
3102     }\r
3103     for (i = 0; i < BOARD_WIDTH + 1; i++) {\r
3104       gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;\r
3105       gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =\r
3106         gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +\r
3107         lineGap / 2 + (i * (squareSize + lineGap));\r
3108       gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =\r
3109         boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);\r
3110       gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
3111     }\r
3112   }\r
3113 \r
3114   /* [HGM] Licensing requirement */\r
3115 #ifdef GOTHIC\r
3116   if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else\r
3117 #endif\r
3118 #ifdef FALCON\r
3119   if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else\r
3120 #endif\r
3121   GothicPopUp( "", VariantNormal);\r
3122 \r
3123 \r
3124 /*  if (boardSize == oldBoardSize) return; [HGM] variant might have changed */\r
3125   oldBoardSize = boardSize;\r
3126   oldTinyLayout = tinyLayout;\r
3127 \r
3128   /* Load piece bitmaps for this board size */\r
3129   for (i=0; i<=2; i++) {\r
3130     for (piece = WhitePawn;\r
3131          (int) piece < (int) BlackPawn;\r
3132          piece = (ChessSquare) ((int) piece + 1)) {\r
3133       if (pieceBitmap[i][piece] != NULL)\r
3134         DeleteObject(pieceBitmap[i][piece]);\r
3135     }\r
3136   }\r
3137 \r
3138   // Orthodox Chess pieces\r
3139   pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");\r
3140   pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");\r
3141   pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");\r
3142   pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");\r
3143   pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");\r
3144   pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");\r
3145   pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");\r
3146   pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");\r
3147   pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");\r
3148   pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");\r
3149   pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");\r
3150   pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");\r
3151   pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");\r
3152   pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");\r
3153   pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");\r
3154   if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {\r
3155     // in Shogi, Hijack the unused Queen for Lance\r
3156     pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
3157     pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
3158     pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
3159   } else {\r
3160     pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");\r
3161     pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");\r
3162     pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");\r
3163   }\r
3164 \r
3165   if(squareSize <= 72 && squareSize >= 33) { \r
3166     /* A & C are available in most sizes now */\r
3167     if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like\r
3168       pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");\r
3169       pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");\r
3170       pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");\r
3171       pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
3172       pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
3173       pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
3174       pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
3175       pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
3176       pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
3177       pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
3178       pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
3179       pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
3180     } else { // Smirf-like\r
3181       pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");\r
3182       pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");\r
3183       pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");\r
3184     }\r
3185     if(gameInfo.variant == VariantGothic) { // Vortex-like\r
3186       pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
3187       pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
3188       pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
3189     } else { // WinBoard standard\r
3190       pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");\r
3191       pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");\r
3192       pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");\r
3193     }\r
3194   }\r
3195 \r
3196 \r
3197   if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */\r
3198     pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");\r
3199     pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");\r
3200     pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");\r
3201     pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");\r
3202     pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");\r
3203     pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3204     pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");\r
3205     pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");\r
3206     pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");\r
3207     pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");\r
3208     pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");\r
3209     pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");\r
3210     pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");\r
3211     pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");\r
3212     pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");\r
3213     pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");\r
3214     pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");\r
3215     pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");\r
3216     pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");\r
3217     pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");\r
3218     pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");\r
3219     pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");\r
3220     pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");\r
3221     pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");\r
3222     pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
3223     pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
3224     pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
3225     pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");\r
3226     pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");\r
3227     pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");\r
3228 \r
3229     if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */\r
3230       pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");\r
3231       pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");\r
3232       pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3233       pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");\r
3234       pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");\r
3235       pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3236       pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");\r
3237       pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");\r
3238       pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3239       pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");\r
3240       pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");\r
3241       pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3242     } else {\r
3243       pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");\r
3244       pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");\r
3245       pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");\r
3246       pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");\r
3247       pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");\r
3248       pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");\r
3249       pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
3250       pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
3251       pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
3252       pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");\r
3253       pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");\r
3254       pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");\r
3255     }\r
3256 \r
3257   } else { /* other size, no special bitmaps available. Use smaller symbols */\r
3258     if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;\r
3259     else  minorSize = sizeInfo[(int)boardSize - 2].squareSize;\r
3260     pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");\r
3261     pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");\r
3262     pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");\r
3263     pieceBitmap[0][WhiteCardinal]   = DoLoadBitmap(hInst, "b", minorSize, "s");\r
3264     pieceBitmap[1][WhiteCardinal]   = DoLoadBitmap(hInst, "b", minorSize, "o");\r
3265     pieceBitmap[2][WhiteCardinal]   = DoLoadBitmap(hInst, "b", minorSize, "w");\r
3266     pieceBitmap[0][WhiteDragon]   = DoLoadBitmap(hInst, "r", minorSize, "s");\r
3267     pieceBitmap[1][WhiteDragon]   = DoLoadBitmap(hInst, "r", minorSize, "o");\r
3268     pieceBitmap[2][WhiteDragon]   = DoLoadBitmap(hInst, "r", minorSize, "w");\r
3269     pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");\r
3270     pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");\r
3271     pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");\r
3272   }\r
3273 \r
3274 \r
3275   if(gameInfo.variant == VariantShogi && squareSize == 58)\r
3276   /* special Shogi support in this size */\r
3277   { for (i=0; i<=2; i++) { /* replace all bitmaps */\r
3278       for (piece = WhitePawn;\r
3279            (int) piece < (int) BlackPawn;\r
3280            piece = (ChessSquare) ((int) piece + 1)) {\r
3281         if (pieceBitmap[i][piece] != NULL)\r
3282           DeleteObject(pieceBitmap[i][piece]);\r
3283       }\r
3284     }\r
3285   pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");\r
3286   pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");\r
3287   pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");\r
3288   pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");\r
3289   pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");\r
3290   pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");\r
3291   pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");\r
3292   pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");\r
3293   pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");\r
3294   pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");\r
3295   pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");\r
3296   pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");\r
3297   pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");\r
3298   pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");\r
3299   pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");\r
3300   pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");\r
3301   pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");\r
3302   pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");\r
3303   pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");\r
3304   pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");\r
3305   pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");\r
3306   pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");\r
3307   pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");\r
3308   pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");\r
3309   pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");\r
3310   pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");\r
3311   pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");\r
3312   pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");\r
3313   pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");\r
3314   pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");\r
3315   pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
3316   pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
3317   pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");\r
3318   pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");\r
3319   pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
3320   pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
3321   pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");\r
3322   pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");\r
3323   pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
3324   pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
3325   pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");\r
3326   pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
3327   minorSize = 0;\r
3328   }\r
3329 }\r
3330 \r
3331 HBITMAP\r
3332 PieceBitmap(ChessSquare p, int kind)\r
3333 {\r
3334   if ((int) p >= (int) BlackPawn)\r
3335     p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);\r
3336 \r
3337   return pieceBitmap[kind][(int) p];\r
3338 }\r
3339 \r
3340 /***************************************************************/\r
3341 \r
3342 #define MIN(a,b) (((a) < (b)) ? (a) : (b))\r
3343 #define MAX(a,b) (((a) > (b)) ? (a) : (b))\r
3344 /*\r
3345 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))\r
3346 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))\r
3347 */\r
3348 \r
3349 VOID\r
3350 SquareToPos(int row, int column, int * x, int * y)\r
3351 {\r
3352   if (flipView) {\r
3353     *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);\r
3354     *y = boardRect.top + lineGap + row * (squareSize + lineGap);\r
3355   } else {\r
3356     *x = boardRect.left + lineGap + column * (squareSize + lineGap);\r
3357     *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);\r
3358   }\r
3359 }\r
3360 \r
3361 VOID\r
3362 DrawCoordsOnDC(HDC hdc)\r
3363 {\r
3364   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
3365   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
3366   char str[2] = { NULLCHAR, NULLCHAR };\r
3367   int oldMode, oldAlign, x, y, start, i;\r
3368   HFONT oldFont;\r
3369   HBRUSH oldBrush;\r
3370 \r
3371   if (!appData.showCoords)\r
3372     return;\r
3373 \r
3374   start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;\r
3375 \r
3376   oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));\r
3377   oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));\r
3378   oldAlign = GetTextAlign(hdc);\r
3379   oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);\r
3380 \r
3381   y = boardRect.top + lineGap;\r
3382   x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);\r
3383 \r
3384   SetTextAlign(hdc, TA_LEFT|TA_TOP);\r
3385   for (i = 0; i < BOARD_HEIGHT; i++) {\r
3386     str[0] = files[start + i];\r
3387     ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);\r
3388     y += squareSize + lineGap;\r
3389   }\r
3390 \r
3391   start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;\r
3392 \r
3393   SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);\r
3394   for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {\r
3395     str[0] = ranks[start + i];\r
3396     ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);\r
3397     x += squareSize + lineGap;\r
3398   }    \r
3399 \r
3400   SelectObject(hdc, oldBrush);\r
3401   SetBkMode(hdc, oldMode);\r
3402   SetTextAlign(hdc, oldAlign);\r
3403   SelectObject(hdc, oldFont);\r
3404 }\r
3405 \r
3406 VOID\r
3407 DrawGridOnDC(HDC hdc)\r
3408 {\r
3409   HPEN oldPen;\r
3410  \r
3411   if (lineGap != 0) {\r
3412     oldPen = SelectObject(hdc, gridPen);\r
3413     PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);\r
3414     SelectObject(hdc, oldPen);\r
3415   }\r
3416 }\r
3417 \r
3418 #define HIGHLIGHT_PEN 0\r
3419 #define PREMOVE_PEN   1\r
3420 \r
3421 VOID\r
3422 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)\r
3423 {\r
3424   int x1, y1;\r
3425   HPEN oldPen, hPen;\r
3426   if (lineGap == 0) return;\r
3427   if (flipView) {\r
3428     x1 = boardRect.left +\r
3429       lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);\r
3430     y1 = boardRect.top +\r
3431       lineGap/2 + y * (squareSize + lineGap);\r
3432   } else {\r
3433     x1 = boardRect.left +\r
3434       lineGap/2 + x * (squareSize + lineGap);\r
3435     y1 = boardRect.top +\r
3436       lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);\r
3437   }\r
3438   hPen = pen ? premovePen : highlightPen;\r
3439   oldPen = SelectObject(hdc, on ? hPen : gridPen);\r
3440   MoveToEx(hdc, x1, y1, NULL);\r
3441   LineTo(hdc, x1 + squareSize + lineGap, y1);\r
3442   LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);\r
3443   LineTo(hdc, x1, y1 + squareSize + lineGap);\r
3444   LineTo(hdc, x1, y1);\r
3445   SelectObject(hdc, oldPen);\r
3446 }\r
3447 \r
3448 VOID\r
3449 DrawHighlightsOnDC(HDC hdc)\r
3450 {\r
3451   int i;\r
3452   for (i=0; i<2; i++) {\r
3453     if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) \r
3454       DrawHighlightOnDC(hdc, TRUE,\r
3455                         highlightInfo.sq[i].x, highlightInfo.sq[i].y,\r
3456                         HIGHLIGHT_PEN);\r
3457   }\r
3458   for (i=0; i<2; i++) {\r
3459     if (premoveHighlightInfo.sq[i].x >= 0 && \r
3460         premoveHighlightInfo.sq[i].y >= 0) {\r
3461         DrawHighlightOnDC(hdc, TRUE,\r
3462                           premoveHighlightInfo.sq[i].x, \r
3463                           premoveHighlightInfo.sq[i].y,\r
3464                           PREMOVE_PEN);\r
3465     }\r
3466   }\r
3467 }\r
3468 \r
3469 /* Note: sqcolor is used only in monoMode */\r
3470 /* Note that this code is largely duplicated in woptions.c,\r
3471    function DrawSampleSquare, so that needs to be updated too */\r
3472 VOID\r
3473 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)\r
3474 {\r
3475   HBITMAP oldBitmap;\r
3476   HBRUSH oldBrush;\r
3477   int tmpSize;\r
3478 \r
3479   if (appData.blindfold) return;\r
3480 \r
3481   /* [AS] Use font-based pieces if needed */\r
3482   if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {\r
3483     /* Create piece bitmaps, or do nothing if piece set is up to date */\r
3484     CreatePiecesFromFont();\r
3485 \r
3486     if( fontBitmapSquareSize == squareSize ) {\r
3487         int index = TranslatePieceToFontPiece( piece );\r
3488 \r
3489         SelectObject( tmphdc, hPieceMask[ index ] );\r
3490 \r
3491         BitBlt( hdc,\r
3492             x, y,\r
3493             squareSize, squareSize,\r
3494             tmphdc,\r
3495             0, 0,\r
3496             SRCAND );\r
3497 \r
3498         SelectObject( tmphdc, hPieceFace[ index ] );\r
3499 \r
3500         BitBlt( hdc,\r
3501             x, y,\r
3502             squareSize, squareSize,\r
3503             tmphdc,\r
3504             0, 0,\r
3505             SRCPAINT );\r
3506 \r
3507         return;\r
3508     }\r
3509   }\r
3510 \r
3511   if (appData.monoMode) {\r
3512     SelectObject(tmphdc, PieceBitmap(piece, \r
3513       color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));\r
3514     BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,\r
3515            sqcolor ? SRCCOPY : NOTSRCCOPY);\r
3516   } else {\r
3517     tmpSize = squareSize;\r
3518     if(minorSize &&\r
3519         (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||\r
3520          piece >= (int)BlackNightrider && piece <= BlackGrasshopper)  ) {\r
3521       /* [HGM] no bitmap available for promoted pieces in Crazyhouse        */\r
3522       /* Bitmaps of smaller size are substituted, but we have to align them */\r
3523       x += (squareSize - minorSize)>>1;\r
3524       y += squareSize - minorSize - 2;\r
3525       tmpSize = minorSize;\r
3526     }\r
3527     if (color || appData.allWhite ) {\r
3528       oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));\r
3529       if( color )\r
3530               oldBrush = SelectObject(hdc, whitePieceBrush);\r
3531       else    oldBrush = SelectObject(hdc, blackPieceBrush);\r
3532       if(appData.upsideDown && color==flipView)\r
3533         StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);\r
3534       else\r
3535         BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
3536 #if 0\r
3537       /* Use black piece color for outline of white pieces */\r
3538       /* Not sure this looks really good (though xboard does it).\r
3539          Maybe better to have another selectable color, default black */\r
3540       SelectObject(hdc, blackPieceBrush); /* could have own brush */\r
3541       SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));\r
3542       BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
3543 #else\r
3544       /* Use black for outline of white pieces */\r
3545       SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));\r
3546       if(appData.upsideDown && color==flipView)\r
3547         StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);\r
3548       else\r
3549         BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);\r
3550 #endif\r
3551     } else {\r
3552 #if 0\r
3553       /* Use white piece color for details of black pieces */\r
3554       /* Requires filled-in solid bitmaps (BLACK_PIECE class); the\r
3555          WHITE_PIECE ones aren't always the right shape. */\r
3556       /* Not sure this looks really good (though xboard does it).\r
3557          Maybe better to have another selectable color, default medium gray? */\r
3558       oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));\r
3559       oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */\r
3560       BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
3561       SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));\r
3562       SelectObject(hdc, blackPieceBrush);\r
3563       BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
3564 #else\r
3565       /* Use square color for details of black pieces */\r
3566       oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));\r
3567       oldBrush = SelectObject(hdc, blackPieceBrush);\r
3568       if(appData.upsideDown && !flipView)\r
3569         StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);\r
3570       else\r
3571         BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
3572 #endif\r
3573     }\r
3574     SelectObject(hdc, oldBrush);\r
3575     SelectObject(tmphdc, oldBitmap);\r
3576   }\r
3577 }\r
3578 \r
3579 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */\r
3580 int GetBackTextureMode( int algo )\r
3581 {\r
3582     int result = BACK_TEXTURE_MODE_DISABLED;\r
3583 \r
3584     switch( algo ) \r
3585     {\r
3586         case BACK_TEXTURE_MODE_PLAIN:\r
3587             result = 1; /* Always use identity map */\r
3588             break;\r
3589         case BACK_TEXTURE_MODE_FULL_RANDOM:\r
3590             result = 1 + (myrandom() % 3); /* Pick a transformation at random */\r
3591             break;\r
3592     }\r
3593 \r
3594     return result;\r
3595 }\r
3596 \r
3597 /* \r
3598     [AS] Compute and save texture drawing info, otherwise we may not be able\r
3599     to handle redraws cleanly (as random numbers would always be different).\r
3600 */\r
3601 VOID RebuildTextureSquareInfo()\r
3602 {\r
3603     BITMAP bi;\r
3604     int lite_w = 0;\r
3605     int lite_h = 0;\r
3606     int dark_w = 0;\r
3607     int dark_h = 0;\r
3608     int row;\r
3609     int col;\r
3610 \r
3611     ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );\r
3612 \r
3613     if( liteBackTexture != NULL ) {\r
3614         if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {\r
3615             lite_w = bi.bmWidth;\r
3616             lite_h = bi.bmHeight;\r
3617         }\r
3618     }\r
3619 \r
3620     if( darkBackTexture != NULL ) {\r
3621         if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {\r
3622             dark_w = bi.bmWidth;\r
3623             dark_h = bi.bmHeight;\r
3624         }\r
3625     }\r
3626 \r
3627     for( row=0; row<BOARD_HEIGHT; row++ ) {\r
3628         for( col=0; col<BOARD_WIDTH; col++ ) {\r
3629             if( (col + row) & 1 ) {\r
3630                 /* Lite square */\r
3631                 if( lite_w >= squareSize && lite_h >= squareSize ) {\r
3632                     backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_WIDTH;\r
3633                     backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_HEIGHT;\r
3634                     backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);\r
3635                 }\r
3636             }\r
3637             else {\r
3638                 /* Dark square */\r
3639                 if( dark_w >= squareSize && dark_h >= squareSize ) {\r
3640                     backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_WIDTH;\r
3641                     backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_HEIGHT;\r
3642                     backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);\r
3643                 }\r
3644             }\r
3645         }\r
3646     }\r
3647 }\r
3648 \r
3649 /* [AS] Arrow highlighting support */\r
3650 \r
3651 static int A_WIDTH = 5; /* Width of arrow body */\r
3652 \r
3653 #define A_HEIGHT_FACTOR 6   /* Length of arrow "point", relative to body width */\r
3654 #define A_WIDTH_FACTOR  3   /* Width of arrow "point", relative to body width */\r
3655 \r
3656 static double Sqr( double x )\r
3657 {\r
3658     return x*x;\r
3659 }\r
3660 \r
3661 static int Round( double x )\r
3662 {\r
3663     return (int) (x + 0.5);\r
3664 }\r
3665 \r
3666 /* Draw an arrow between two points using current settings */\r