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