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