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