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