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