fb317b741af53d4ca46b0fc45bf85fb077c93c40
[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 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 x, y, radius;\r
136 } ExplodeInfo;\r
137 \r
138 static ExplodeInfo explodeInfo = {0, 0, 0};\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   /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */\r
1290   { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },\r
1291 #endif\r
1292   /* [HGM] options for broadcasting and time odds */\r
1293   { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },\r
1294   { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },\r
1295   { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },\r
1296   { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },\r
1297   { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },\r
1298   { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },\r
1299   { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },\r
1300   { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },\r
1301   { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },\r
1302   { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },\r
1303   { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },\r
1304   { NULL, ArgNone, NULL, FALSE }\r
1305 };\r
1306 \r
1307 \r
1308 /* Kludge for indirection files on command line */\r
1309 char* lastIndirectionFilename;\r
1310 ArgDescriptor argDescriptorIndirection =\r
1311 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };\r
1312 \r
1313 \r
1314 VOID\r
1315 ExitArgError(char *msg, char *badArg)\r
1316 {\r
1317   char buf[MSG_SIZ];\r
1318 \r
1319   sprintf(buf, "%s %s", msg, badArg);\r
1320   DisplayFatalError(buf, 0, 2);\r
1321   exit(2);\r
1322 }\r
1323 \r
1324 /* Command line font name parser.  NULL name means do nothing.\r
1325    Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"\r
1326    For backward compatibility, syntax without the colon is also\r
1327    accepted, but font names with digits in them won't work in that case.\r
1328 */\r
1329 VOID\r
1330 ParseFontName(char *name, MyFontParams *mfp)\r
1331 {\r
1332   char *p, *q;\r
1333   if (name == NULL) return;\r
1334   p = name;\r
1335   q = strchr(p, ':');\r
1336   if (q) {\r
1337     if (q - p >= sizeof(mfp->faceName))\r
1338       ExitArgError("Font name too long:", name);\r
1339     memcpy(mfp->faceName, p, q - p);\r
1340     mfp->faceName[q - p] = NULLCHAR;\r
1341     p = q + 1;\r
1342   } else {\r
1343     q = mfp->faceName;\r
1344     while (*p && !isdigit(*p)) {\r
1345       *q++ = *p++;\r
1346       if (q - mfp->faceName >= sizeof(mfp->faceName))\r
1347         ExitArgError("Font name too long:", name);\r
1348     }\r
1349     while (q > mfp->faceName && q[-1] == ' ') q--;\r
1350     *q = NULLCHAR;\r
1351   }\r
1352   if (!*p) ExitArgError("Font point size missing:", name);\r
1353   mfp->pointSize = (float) atof(p);\r
1354   mfp->bold = (strchr(p, 'b') != NULL);\r
1355   mfp->italic = (strchr(p, 'i') != NULL);\r
1356   mfp->underline = (strchr(p, 'u') != NULL);\r
1357   mfp->strikeout = (strchr(p, 's') != NULL);\r
1358 }\r
1359 \r
1360 /* Color name parser.\r
1361    X version accepts X color names, but this one\r
1362    handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */\r
1363 COLORREF\r
1364 ParseColorName(char *name)\r
1365 {\r
1366   int red, green, blue, count;\r
1367   char buf[MSG_SIZ];\r
1368 \r
1369   count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);\r
1370   if (count != 3) {\r
1371     count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d", \r
1372       &red, &green, &blue);\r
1373   }\r
1374   if (count != 3) {\r
1375     sprintf(buf, "Can't parse color name %s", name);\r
1376     DisplayError(buf, 0);\r
1377     return RGB(0, 0, 0);\r
1378   }\r
1379   return PALETTERGB(red, green, blue);\r
1380 }\r
1381 \r
1382 \r
1383 void ParseAttribs(COLORREF *color, int *effects, char* argValue)\r
1384 {\r
1385   char *e = argValue;\r
1386   int eff = 0;\r
1387 \r
1388   while (*e) {\r
1389     if (*e == 'b')      eff |= CFE_BOLD;\r
1390     else if (*e == 'i') eff |= CFE_ITALIC;\r
1391     else if (*e == 'u') eff |= CFE_UNDERLINE;\r
1392     else if (*e == 's') eff |= CFE_STRIKEOUT;\r
1393     else if (*e == '#' || isdigit(*e)) break;\r
1394     e++;\r
1395   }\r
1396   *effects = eff;\r
1397   *color   = ParseColorName(e);\r
1398 }\r
1399 \r
1400 \r
1401 BoardSize\r
1402 ParseBoardSize(char *name)\r
1403 {\r
1404   BoardSize bs = SizeTiny;\r
1405   while (sizeInfo[bs].name != NULL) {\r
1406     if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;\r
1407     bs++;\r
1408   }\r
1409   ExitArgError("Unrecognized board size value", name);\r
1410   return bs; /* not reached */\r
1411 }\r
1412 \r
1413 \r
1414 char\r
1415 StringGet(void *getClosure)\r
1416 {\r
1417   char **p = (char **) getClosure;\r
1418   return *((*p)++);\r
1419 }\r
1420 \r
1421 char\r
1422 FileGet(void *getClosure)\r
1423 {\r
1424   int c;\r
1425   FILE* f = (FILE*) getClosure;\r
1426 \r
1427   c = getc(f);\r
1428   if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely\r
1429   if (c == EOF)\r
1430     return NULLCHAR;\r
1431   else\r
1432     return (char) c;\r
1433 }\r
1434 \r
1435 /* Parse settings file named "name". If file found, return the\r
1436    full name in fullname and return TRUE; else return FALSE */\r
1437 BOOLEAN\r
1438 ParseSettingsFile(char *name, char fullname[MSG_SIZ])\r
1439 {\r
1440   char *dummy;\r
1441   FILE *f;\r
1442   int ok; char buf[MSG_SIZ];\r
1443 \r
1444   ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);\r
1445   if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed\r
1446     sprintf(buf, "%s.ini", name);\r
1447     ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);\r
1448   }\r
1449   if (ok) {\r
1450     f = fopen(fullname, "r");\r
1451     if (f != NULL) {\r
1452       ParseArgs(FileGet, f);\r
1453       fclose(f);\r
1454       return TRUE;\r
1455     }\r
1456   }\r
1457   return FALSE;\r
1458 }\r
1459 \r
1460 VOID\r
1461 ParseArgs(GetFunc get, void *cl)\r
1462 {\r
1463   char argName[ARG_MAX];\r
1464   char argValue[ARG_MAX];\r
1465   ArgDescriptor *ad;\r
1466   char start;\r
1467   char *q;\r
1468   int i, octval;\r
1469   char ch;\r
1470   int posarg = 0;\r
1471 \r
1472   ch = get(cl);\r
1473   for (;;) {\r
1474     while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);\r
1475     if (ch == NULLCHAR) break;\r
1476     if (ch == ';') {\r
1477       /* Comment to end of line */\r
1478       ch = get(cl);\r
1479       while (ch != '\n' && ch != NULLCHAR) ch = get(cl);\r
1480       continue;\r
1481     } else if (ch == '/' || ch == '-') {\r
1482       /* Switch */\r
1483       q = argName;\r
1484       while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&\r
1485              ch != '\n' && ch != '\t') {\r
1486         *q++ = ch;\r
1487         ch = get(cl);\r
1488       }\r
1489       *q = NULLCHAR;\r
1490 \r
1491       for (ad = argDescriptors; ad->argName != NULL; ad++)\r
1492         if (strcmp(ad->argName, argName + 1) == 0) break;\r
1493 \r
1494       if (ad->argName == NULL)\r
1495         ExitArgError("Unrecognized argument", argName);\r
1496 \r
1497     } else if (ch == '@') {\r
1498       /* Indirection file */\r
1499       ad = &argDescriptorIndirection;\r
1500       ch = get(cl);\r
1501     } else {\r
1502       /* Positional argument */\r
1503       ad = &argDescriptors[posarg++];\r
1504       strcpy(argName, ad->argName);\r
1505     }\r
1506 \r
1507     if (ad->argType == ArgTrue) {\r
1508       *(Boolean *) ad->argLoc = TRUE;\r
1509       continue;\r
1510     }\r
1511     if (ad->argType == ArgFalse) {\r
1512       *(Boolean *) ad->argLoc = FALSE;\r
1513       continue;\r
1514     }\r
1515 \r
1516     while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);\r
1517     if (ch == NULLCHAR || ch == '\n') {\r
1518       ExitArgError("No value provided for argument", argName);\r
1519     }\r
1520     q = argValue;\r
1521     if (ch == '{') {\r
1522       // Quoting with { }.  No characters have to (or can) be escaped.\r
1523       // Thus the string cannot contain a '}' character.\r
1524       start = ch;\r
1525       ch = get(cl);\r
1526       while (start) {\r
1527         switch (ch) {\r
1528         case NULLCHAR:\r
1529           start = NULLCHAR;\r
1530           break;\r
1531           \r
1532         case '}':\r
1533           ch = get(cl);\r
1534           start = NULLCHAR;\r
1535           break;\r
1536 \r
1537         default:\r
1538           *q++ = ch;\r
1539           ch = get(cl);\r
1540           break;\r
1541         }\r
1542       }   \r
1543     } else if (ch == '\'' || ch == '"') {\r
1544       // Quoting with ' ' or " ", with \ as escape character.\r
1545       // Inconvenient for long strings that may contain Windows filenames.\r
1546       start = ch;\r
1547       ch = get(cl);\r
1548       while (start) {\r
1549         switch (ch) {\r
1550         case NULLCHAR:\r
1551           start = NULLCHAR;\r
1552           break;\r
1553 \r
1554         default:\r
1555         not_special:\r
1556           *q++ = ch;\r
1557           ch = get(cl);\r
1558           break;\r
1559 \r
1560         case '\'':\r
1561         case '\"':\r
1562           if (ch == start) {\r
1563             ch = get(cl);\r
1564             start = NULLCHAR;\r
1565             break;\r
1566           } else {\r
1567             goto not_special;\r
1568           }\r
1569 \r
1570         case '\\':\r
1571           if (ad->argType == ArgFilename\r
1572               || ad->argType == ArgSettingsFilename) {\r
1573               goto not_special;\r
1574           }\r
1575           ch = get(cl);\r
1576           switch (ch) {\r
1577           case NULLCHAR:\r
1578             ExitArgError("Incomplete \\ escape in value for", argName);\r
1579             break;\r
1580           case 'n':\r
1581             *q++ = '\n';\r
1582             ch = get(cl);\r
1583             break;\r
1584           case 'r':\r
1585             *q++ = '\r';\r
1586             ch = get(cl);\r
1587             break;\r
1588           case 't':\r
1589             *q++ = '\t';\r
1590             ch = get(cl);\r
1591             break;\r
1592           case 'b':\r
1593             *q++ = '\b';\r
1594             ch = get(cl);\r
1595             break;\r
1596           case 'f':\r
1597             *q++ = '\f';\r
1598             ch = get(cl);\r
1599             break;\r
1600           default:\r
1601             octval = 0;\r
1602             for (i = 0; i < 3; i++) {\r
1603               if (ch >= '0' && ch <= '7') {\r
1604                 octval = octval*8 + (ch - '0');\r
1605                 ch = get(cl);\r
1606               } else {\r
1607                 break;\r
1608               }\r
1609             }\r
1610             if (i > 0) {\r
1611               *q++ = (char) octval;\r
1612             } else {\r
1613               *q++ = ch;\r
1614               ch = get(cl);\r
1615             }\r
1616             break;\r
1617           }\r
1618           break;\r
1619         }\r
1620       }\r
1621     } else {\r
1622       while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {\r
1623         *q++ = ch;\r
1624         ch = get(cl);\r
1625       }\r
1626     }\r
1627     *q = NULLCHAR;\r
1628 \r
1629     switch (ad->argType) {\r
1630     case ArgInt:\r
1631       *(int *) ad->argLoc = atoi(argValue);\r
1632       break;\r
1633 \r
1634     case ArgFloat:\r
1635       *(float *) ad->argLoc = (float) atof(argValue);\r
1636       break;\r
1637 \r
1638     case ArgString:\r
1639     case ArgFilename:\r
1640       *(char **) ad->argLoc = strdup(argValue);\r
1641       break;\r
1642 \r
1643     case ArgSettingsFilename:\r
1644       {\r
1645         char fullname[MSG_SIZ];\r
1646         if (ParseSettingsFile(argValue, fullname)) {\r
1647           if (ad->argLoc != NULL) {\r
1648             *(char **) ad->argLoc = strdup(fullname);\r
1649           }\r
1650         } else {\r
1651           if (ad->argLoc != NULL) {\r
1652           } else {\r
1653             ExitArgError("Failed to open indirection file", argValue);\r
1654           }\r
1655         }\r
1656       }\r
1657       break;\r
1658 \r
1659     case ArgBoolean:\r
1660       switch (argValue[0]) {\r
1661       case 't':\r
1662       case 'T':\r
1663         *(Boolean *) ad->argLoc = TRUE;\r
1664         break;\r
1665       case 'f':\r
1666       case 'F':\r
1667         *(Boolean *) ad->argLoc = FALSE;\r
1668         break;\r
1669       default:\r
1670         ExitArgError("Unrecognized boolean argument value", argValue);\r
1671         break;\r
1672       }\r
1673       break;\r
1674 \r
1675     case ArgColor:\r
1676       *(COLORREF *)ad->argLoc = ParseColorName(argValue);\r
1677       break;\r
1678 \r
1679     case ArgAttribs: {\r
1680       ColorClass cc = (ColorClass)ad->argLoc;\r
1681       ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);\r
1682       }\r
1683       break;\r
1684       \r
1685     case ArgBoardSize:\r
1686       *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);\r
1687       break;\r
1688 \r
1689     case ArgFont:\r
1690       ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);\r
1691       break;\r
1692 \r
1693     case ArgCommSettings:\r
1694       ParseCommSettings(argValue, &dcb);\r
1695       break;\r
1696 \r
1697     case ArgNone:\r
1698       ExitArgError("Unrecognized argument", argValue);\r
1699       break;\r
1700     case ArgTrue:\r
1701     case ArgFalse: ;\r
1702     }\r
1703   }\r
1704 }\r
1705 \r
1706 VOID\r
1707 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)\r
1708 {\r
1709   HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);\r
1710   lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);\r
1711   DeleteDC(hdc);\r
1712   lf->lfWidth = 0;\r
1713   lf->lfEscapement = 0;\r
1714   lf->lfOrientation = 0;\r
1715   lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;\r
1716   lf->lfItalic = mfp->italic;\r
1717   lf->lfUnderline = mfp->underline;\r
1718   lf->lfStrikeOut = mfp->strikeout;\r
1719   lf->lfCharSet = DEFAULT_CHARSET;\r
1720   lf->lfOutPrecision = OUT_DEFAULT_PRECIS;\r
1721   lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
1722   lf->lfQuality = DEFAULT_QUALITY;\r
1723   lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;\r
1724   strcpy(lf->lfFaceName, mfp->faceName);\r
1725 }\r
1726 \r
1727 VOID\r
1728 CreateFontInMF(MyFont *mf)\r
1729 {\r
1730   LFfromMFP(&mf->lf, &mf->mfp);\r
1731   if (mf->hf) DeleteObject(mf->hf);\r
1732   mf->hf = CreateFontIndirect(&mf->lf);\r
1733 }\r
1734 \r
1735 VOID\r
1736 SetDefaultTextAttribs()\r
1737 {\r
1738   ColorClass cc;\r
1739   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1740     ParseAttribs(&textAttribs[cc].color, \r
1741                  &textAttribs[cc].effects, \r
1742                  defaultTextAttribs[cc]);\r
1743   }\r
1744 }\r
1745 \r
1746 VOID\r
1747 SetDefaultSounds()\r
1748 {\r
1749   ColorClass cc;\r
1750   SoundClass sc;\r
1751   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1752     textAttribs[cc].sound.name = strdup("");\r
1753     textAttribs[cc].sound.data = NULL;\r
1754   }\r
1755   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
1756     sounds[sc].name = strdup("");\r
1757     sounds[sc].data = NULL;\r
1758   }\r
1759   sounds[(int)SoundBell].name = strdup(SOUND_BELL);\r
1760 }\r
1761 \r
1762 VOID\r
1763 LoadAllSounds()\r
1764 {\r
1765   ColorClass cc;\r
1766   SoundClass sc;\r
1767   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1768     MyLoadSound(&textAttribs[cc].sound);\r
1769   }\r
1770   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
1771     MyLoadSound(&sounds[sc]);\r
1772   }\r
1773 }\r
1774 \r
1775 VOID\r
1776 InitAppData(LPSTR lpCmdLine)\r
1777 {\r
1778   int i, j;\r
1779   char buf[ARG_MAX], currDir[MSG_SIZ];\r
1780   char *dummy, *p;\r
1781 \r
1782   programName = szAppName;\r
1783 \r
1784   /* Initialize to defaults */\r
1785   lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);\r
1786   darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);\r
1787   whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);\r
1788   blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);\r
1789   highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);\r
1790   premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);\r
1791   consoleBackgroundColor = ParseColorName(COLOR_BKGD);\r
1792   SetDefaultTextAttribs();\r
1793   SetDefaultSounds();\r
1794   appData.movesPerSession = MOVES_PER_SESSION;\r
1795   appData.initString = INIT_STRING;\r
1796   appData.secondInitString = INIT_STRING;\r
1797   appData.firstComputerString = COMPUTER_STRING;\r
1798   appData.secondComputerString = COMPUTER_STRING;\r
1799   appData.firstChessProgram = FIRST_CHESS_PROGRAM;\r
1800   appData.secondChessProgram = SECOND_CHESS_PROGRAM;\r
1801   appData.firstPlaysBlack = FALSE;\r
1802   appData.noChessProgram = FALSE;\r
1803   chessProgram = FALSE;\r
1804   appData.firstHost = FIRST_HOST;\r
1805   appData.secondHost = SECOND_HOST;\r
1806   appData.firstDirectory = FIRST_DIRECTORY;\r
1807   appData.secondDirectory = SECOND_DIRECTORY;\r
1808   appData.bitmapDirectory = "";\r
1809   appData.remoteShell = REMOTE_SHELL;\r
1810   appData.remoteUser = "";\r
1811   appData.timeDelay = TIME_DELAY;\r
1812   appData.timeControl = TIME_CONTROL;\r
1813   appData.timeIncrement = TIME_INCREMENT;\r
1814   appData.icsActive = FALSE;\r
1815   appData.icsHost = "";\r
1816   appData.icsPort = ICS_PORT;\r
1817   appData.icsCommPort = ICS_COMM_PORT;\r
1818   appData.icsLogon = ICS_LOGON;\r
1819   appData.icsHelper = "";\r
1820   appData.useTelnet = FALSE;\r
1821   appData.telnetProgram = TELNET_PROGRAM;\r
1822   appData.gateway = "";\r
1823   appData.loadGameFile = "";\r
1824   appData.loadGameIndex = 0;\r
1825   appData.saveGameFile = "";\r
1826   appData.autoSaveGames = FALSE;\r
1827   appData.loadPositionFile = "";\r
1828   appData.loadPositionIndex = 1;\r
1829   appData.savePositionFile = "";\r
1830   appData.matchMode = FALSE;\r
1831   appData.matchGames = 0;\r
1832   appData.monoMode = FALSE;\r
1833   appData.debugMode = FALSE;\r
1834   appData.clockMode = TRUE;\r
1835   boardSize = (BoardSize) -1; /* determine by screen size */\r
1836   appData.Iconic = FALSE; /*unused*/\r
1837   appData.searchTime = "";\r
1838   appData.searchDepth = 0;\r
1839   appData.showCoords = FALSE;\r
1840   appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/\r
1841   appData.autoCallFlag = FALSE;\r
1842   appData.flipView = FALSE;\r
1843   appData.autoFlipView = TRUE;\r
1844   appData.cmailGameName = "";\r
1845   appData.alwaysPromoteToQueen = FALSE;\r
1846   appData.oldSaveStyle = FALSE;\r
1847   appData.quietPlay = FALSE;\r
1848   appData.showThinking = FALSE;\r
1849   appData.ponderNextMove = TRUE;\r
1850   appData.periodicUpdates = TRUE;\r
1851   appData.popupExitMessage = TRUE;\r
1852   appData.popupMoveErrors = FALSE;\r
1853   appData.autoObserve = FALSE;\r
1854   appData.autoComment = FALSE;\r
1855   appData.animate = TRUE;\r
1856   appData.animSpeed = 10;\r
1857   appData.animateDragging = TRUE;\r
1858   appData.highlightLastMove = TRUE;\r
1859   appData.getMoveList = TRUE;\r
1860   appData.testLegality = TRUE;\r
1861   appData.premove = TRUE;\r
1862   appData.premoveWhite = FALSE;\r
1863   appData.premoveWhiteText = "";\r
1864   appData.premoveBlack = FALSE;\r
1865   appData.premoveBlackText = "";\r
1866   appData.icsAlarm = TRUE;\r
1867   appData.icsAlarmTime = 5000;\r
1868   appData.autoRaiseBoard = TRUE;\r
1869   appData.localLineEditing = TRUE;\r
1870   appData.colorize = TRUE;\r
1871   appData.reuseFirst = TRUE;\r
1872   appData.reuseSecond = TRUE;\r
1873   appData.blindfold = FALSE;\r
1874   appData.icsEngineAnalyze = FALSE;\r
1875   memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +\r
1876   dcb.DCBlength = sizeof(DCB);\r
1877   dcb.BaudRate = 9600;\r
1878   dcb.fBinary = TRUE;\r
1879   dcb.fParity = FALSE;\r
1880   dcb.fOutxCtsFlow = FALSE;\r
1881   dcb.fOutxDsrFlow = FALSE;\r
1882   dcb.fDtrControl = DTR_CONTROL_ENABLE;\r
1883   dcb.fDsrSensitivity = FALSE;\r
1884   dcb.fTXContinueOnXoff = TRUE;\r
1885   dcb.fOutX = FALSE;\r
1886   dcb.fInX = FALSE;\r
1887   dcb.fNull = FALSE;\r
1888   dcb.fRtsControl = RTS_CONTROL_ENABLE;\r
1889   dcb.fAbortOnError = FALSE;\r
1890   dcb.ByteSize = 7;\r
1891   dcb.Parity = SPACEPARITY;\r
1892   dcb.StopBits = ONESTOPBIT;\r
1893   settingsFileName = SETTINGS_FILE;\r
1894   saveSettingsOnExit = TRUE;\r
1895   boardX = CW_USEDEFAULT;\r
1896   boardY = CW_USEDEFAULT;\r
1897   consoleX = CW_USEDEFAULT; \r
1898   consoleY = CW_USEDEFAULT; \r
1899   consoleW = CW_USEDEFAULT;\r
1900   consoleH = CW_USEDEFAULT;\r
1901   analysisX = CW_USEDEFAULT; \r
1902   analysisY = CW_USEDEFAULT; \r
1903   analysisW = CW_USEDEFAULT;\r
1904   analysisH = CW_USEDEFAULT;\r
1905   commentX = CW_USEDEFAULT; \r
1906   commentY = CW_USEDEFAULT; \r
1907   commentW = CW_USEDEFAULT;\r
1908   commentH = CW_USEDEFAULT;\r
1909   editTagsX = CW_USEDEFAULT; \r
1910   editTagsY = CW_USEDEFAULT; \r
1911   editTagsW = CW_USEDEFAULT;\r
1912   editTagsH = CW_USEDEFAULT;\r
1913   gameListX = CW_USEDEFAULT; \r
1914   gameListY = CW_USEDEFAULT; \r
1915   gameListW = CW_USEDEFAULT;\r
1916   gameListH = CW_USEDEFAULT;\r
1917   icsTextMenuString = ICS_TEXT_MENU_DEFAULT;\r
1918   icsNames = ICS_NAMES;\r
1919   firstChessProgramNames = FCP_NAMES;\r
1920   secondChessProgramNames = SCP_NAMES;\r
1921   appData.initialMode = "";\r
1922   appData.variant = "normal";\r
1923   appData.firstProtocolVersion = PROTOVER;\r
1924   appData.secondProtocolVersion = PROTOVER;\r
1925   appData.showButtonBar = TRUE;\r
1926 \r
1927    /* [AS] New properties (see comments in header file) */\r
1928   appData.firstScoreIsAbsolute = FALSE;\r
1929   appData.secondScoreIsAbsolute = FALSE;\r
1930   appData.saveExtendedInfoInPGN = FALSE;\r
1931   appData.hideThinkingFromHuman = FALSE;\r
1932   appData.liteBackTextureFile = "";\r
1933   appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
1934   appData.darkBackTextureFile = "";\r
1935   appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
1936   appData.renderPiecesWithFont = "";\r
1937   appData.fontToPieceTable = "";\r
1938   appData.fontBackColorWhite = 0;\r
1939   appData.fontForeColorWhite = 0;\r
1940   appData.fontBackColorBlack = 0;\r
1941   appData.fontForeColorBlack = 0;\r
1942   appData.fontPieceSize = 80;\r
1943   appData.overrideLineGap = 1;\r
1944   appData.adjudicateLossThreshold = 0;\r
1945   appData.delayBeforeQuit = 0;\r
1946   appData.delayAfterQuit = 0;\r
1947   appData.nameOfDebugFile = "winboard.debug";\r
1948   appData.pgnEventHeader = "Computer Chess Game";\r
1949   appData.defaultFrcPosition = -1;\r
1950   appData.gameListTags = GLT_DEFAULT_TAGS;\r
1951   appData.saveOutOfBookInfo = TRUE;\r
1952   appData.showEvalInMoveHistory = TRUE;\r
1953   appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );\r
1954   appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );\r
1955   appData.highlightMoveWithArrow = FALSE;\r
1956   appData.highlightArrowColor = ParseColorName( "#FFFF80" );\r
1957   appData.useStickyWindows = TRUE;\r
1958   appData.adjudicateDrawMoves = 0;\r
1959   appData.autoDisplayComment = TRUE;\r
1960   appData.autoDisplayTags = TRUE;\r
1961   appData.firstIsUCI = FALSE;\r
1962   appData.secondIsUCI = FALSE;\r
1963   appData.firstHasOwnBookUCI = TRUE;\r
1964   appData.secondHasOwnBookUCI = TRUE;\r
1965   appData.polyglotDir = "";\r
1966   appData.usePolyglotBook = FALSE;\r
1967   appData.polyglotBook = "";\r
1968   appData.defaultHashSize = 64;\r
1969   appData.defaultCacheSizeEGTB = 4;\r
1970   appData.defaultPathEGTB = "c:\\egtb";\r
1971   appData.firstOptions = "";\r
1972   appData.secondOptions = "";\r
1973 \r
1974   InitWindowPlacement( &wpMoveHistory );\r
1975   InitWindowPlacement( &wpEvalGraph );\r
1976   InitWindowPlacement( &wpEngineOutput );\r
1977 \r
1978   /* [HGM] User-selectable board size, adjudication control, miscellaneous */\r
1979   appData.NrFiles      = -1;\r
1980   appData.NrRanks      = -1;\r
1981   appData.holdingsSize = -1;\r
1982   appData.testClaims   = FALSE;\r
1983   appData.checkMates   = FALSE;\r
1984   appData.materialDraws= FALSE;\r
1985   appData.trivialDraws = FALSE;\r
1986   appData.ruleMoves    = 51;\r
1987   appData.drawRepeats  = 6;\r
1988   appData.matchPause   = 10000;\r
1989   appData.alphaRank    = FALSE;\r
1990   appData.allWhite     = FALSE;\r
1991   appData.upsideDown   = FALSE;\r
1992   appData.serverPause  = 15;\r
1993   appData.serverMovesName   = NULL;\r
1994   appData.suppressLoadMoves = FALSE;\r
1995   appData.firstTimeOdds  = 1;\r
1996   appData.secondTimeOdds = 1;\r
1997   appData.firstAccumulateTC  = 1; // combine previous and current sessions\r
1998   appData.secondAccumulateTC = 1;\r
1999   appData.firstNPS  = -1; // [HGM] nps: use wall-clock time\r
2000   appData.secondNPS = -1;\r
2001   appData.engineComments = 1;\r
2002   appData.smpCores = 1; // [HGM] SMP: max nr of cores\r
2003   appData.egtFormats = "";\r
2004 \r
2005 #ifdef ZIPPY\r
2006   appData.zippyTalk = ZIPPY_TALK;\r
2007   appData.zippyPlay = ZIPPY_PLAY;\r
2008   appData.zippyLines = ZIPPY_LINES;\r
2009   appData.zippyPinhead = ZIPPY_PINHEAD;\r
2010   appData.zippyPassword = ZIPPY_PASSWORD;\r
2011   appData.zippyPassword2 = ZIPPY_PASSWORD2;\r
2012   appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;\r
2013   appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;\r
2014   appData.zippyUseI = ZIPPY_USE_I;\r
2015   appData.zippyBughouse = ZIPPY_BUGHOUSE;\r
2016   appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;\r
2017   appData.zippyGameEnd = ZIPPY_GAME_END;\r
2018   appData.zippyGameStart = ZIPPY_GAME_START;\r
2019   appData.zippyAdjourn = ZIPPY_ADJOURN;\r
2020   appData.zippyAbort = ZIPPY_ABORT;\r
2021   appData.zippyVariants = ZIPPY_VARIANTS;\r
2022   appData.zippyMaxGames = ZIPPY_MAX_GAMES;\r
2023   appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;\r
2024 #endif\r
2025 \r
2026   /* Point font array elements to structures and\r
2027      parse default font names */\r
2028   for (i=0; i<NUM_FONTS; i++) {\r
2029     for (j=0; j<NUM_SIZES; j++) {\r
2030       font[j][i] = &fontRec[j][i];\r
2031       ParseFontName(font[j][i]->def, &font[j][i]->mfp);\r
2032     }\r
2033   }\r
2034   \r
2035   /* Parse default settings file if any */\r
2036   if (ParseSettingsFile(settingsFileName, buf)) {\r
2037     settingsFileName = strdup(buf);\r
2038   }\r
2039 \r
2040   /* Parse command line */\r
2041   ParseArgs(StringGet, &lpCmdLine);\r
2042 \r
2043   /* [HGM] make sure board size is acceptable */\r
2044   if(appData.NrFiles > BOARD_SIZE ||\r
2045      appData.NrRanks > BOARD_SIZE   )\r
2046       DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);\r
2047 \r
2048   /* [HGM] After parsing the options from the .ini file, and overruling them\r
2049    * with options from the command line, we now make an even higher priority\r
2050    * overrule by WB options attached to the engine command line. This so that\r
2051    * tournament managers can use WB options (such as /timeOdds) that follow\r
2052    * the engines.\r
2053    */\r
2054   if(appData.firstChessProgram != NULL) {\r
2055       char *p = StrStr(appData.firstChessProgram, "WBopt");\r
2056       static char *f = "first";\r
2057       char buf[MSG_SIZ], *q = buf;\r
2058       if(p != NULL) { // engine command line contains WinBoard options\r
2059           sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"\r
2060           ParseArgs(StringGet, &q);\r
2061           p[-1] = 0; // cut them offengine command line\r
2062       }\r
2063   }\r
2064   // now do same for second chess program\r
2065   if(appData.secondChessProgram != NULL) {\r
2066       char *p = StrStr(appData.secondChessProgram, "WBopt");\r
2067       static char *s = "second";\r
2068       char buf[MSG_SIZ], *q = buf;\r
2069       if(p != NULL) { // engine command line contains WinBoard options\r
2070           sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"\r
2071           ParseArgs(StringGet, &q);\r
2072           p[-1] = 0; // cut them offengine command line\r
2073       }\r
2074   }\r
2075 \r
2076 \r
2077   /* Propagate options that affect others */\r
2078   if (appData.matchMode || appData.matchGames) chessProgram = TRUE;\r
2079   if (appData.icsActive || appData.noChessProgram) {\r
2080      chessProgram = FALSE;  /* not local chess program mode */\r
2081   }\r
2082 \r
2083   /* Open startup dialog if needed */\r
2084   if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||\r
2085       (appData.icsActive && *appData.icsHost == NULLCHAR) ||\r
2086       (chessProgram && (*appData.firstChessProgram == NULLCHAR ||\r
2087                         *appData.secondChessProgram == NULLCHAR))) {\r
2088     FARPROC lpProc;\r
2089     \r
2090     lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);\r
2091     DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);\r
2092     FreeProcInstance(lpProc);\r
2093   }\r
2094 \r
2095   /* Make sure save files land in the right (?) directory */\r
2096   if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {\r
2097     appData.saveGameFile = strdup(buf);\r
2098   }\r
2099   if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {\r
2100     appData.savePositionFile = strdup(buf);\r
2101   }\r
2102 \r
2103   /* Finish initialization for fonts and sounds */\r
2104   for (i=0; i<NUM_FONTS; i++) {\r
2105     for (j=0; j<NUM_SIZES; j++) {\r
2106       CreateFontInMF(font[j][i]);\r
2107     }\r
2108   }\r
2109   /* xboard, and older WinBoards, controlled the move sound with the\r
2110      appData.ringBellAfterMoves option.  In the current WinBoard, we\r
2111      always turn the option on (so that the backend will call us),\r
2112      then let the user turn the sound off by setting it to silence if\r
2113      desired.  To accommodate old winboard.ini files saved by old\r
2114      versions of WinBoard, we also turn off the sound if the option\r
2115      was initially set to false. */\r
2116   if (!appData.ringBellAfterMoves) {\r
2117     sounds[(int)SoundMove].name = strdup("");\r
2118     appData.ringBellAfterMoves = TRUE;\r
2119   }\r
2120   GetCurrentDirectory(MSG_SIZ, currDir);\r
2121   SetCurrentDirectory(installDir);\r
2122   LoadAllSounds();\r
2123   SetCurrentDirectory(currDir);\r
2124 \r
2125   p = icsTextMenuString;\r
2126   if (p[0] == '@') {\r
2127     FILE* f = fopen(p + 1, "r");\r
2128     if (f == NULL) {\r
2129       DisplayFatalError(p + 1, errno, 2);\r
2130       return;\r
2131     }\r
2132     i = fread(buf, 1, sizeof(buf)-1, f);\r
2133     fclose(f);\r
2134     buf[i] = NULLCHAR;\r
2135     p = buf;\r
2136   }\r
2137   ParseIcsTextMenu(strdup(p));\r
2138 }\r
2139 \r
2140 \r
2141 VOID\r
2142 InitMenuChecks()\r
2143 {\r
2144   HMENU hmenu = GetMenu(hwndMain);\r
2145 \r
2146   (void) EnableMenuItem(hmenu, IDM_CommPort,\r
2147                         MF_BYCOMMAND|((appData.icsActive &&\r
2148                                        *appData.icsCommPort != NULLCHAR) ?\r
2149                                       MF_ENABLED : MF_GRAYED));\r
2150   (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,\r
2151                        MF_BYCOMMAND|(saveSettingsOnExit ?\r
2152                                      MF_CHECKED : MF_UNCHECKED));\r
2153 }\r
2154 \r
2155 \r
2156 VOID\r
2157 SaveSettings(char* name)\r
2158 {\r
2159   FILE *f;\r
2160   ArgDescriptor *ad;\r
2161   WINDOWPLACEMENT wp;\r
2162   char dir[MSG_SIZ];\r
2163 \r
2164   if (!hwndMain) return;\r
2165 \r
2166   GetCurrentDirectory(MSG_SIZ, dir);\r
2167   SetCurrentDirectory(installDir);\r
2168   f = fopen(name, "w");\r
2169   SetCurrentDirectory(dir);\r
2170   if (f == NULL) {\r
2171     DisplayError(name, errno);\r
2172     return;\r
2173   }\r
2174   fprintf(f, ";\n");\r
2175   fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);\r
2176   fprintf(f, ";\n");\r
2177   fprintf(f, "; You can edit the values of options that are already set in this file,\n");\r
2178   fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");\r
2179   fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");\r
2180   fprintf(f, ";\n");\r
2181 \r
2182   wp.length = sizeof(WINDOWPLACEMENT);\r
2183   GetWindowPlacement(hwndMain, &wp);\r
2184   boardX = wp.rcNormalPosition.left;\r
2185   boardY = wp.rcNormalPosition.top;\r
2186 \r
2187   if (hwndConsole) {\r
2188     GetWindowPlacement(hwndConsole, &wp);\r
2189     consoleX = wp.rcNormalPosition.left;\r
2190     consoleY = wp.rcNormalPosition.top;\r
2191     consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2192     consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2193   }\r
2194 \r
2195   if (analysisDialog) {\r
2196     GetWindowPlacement(analysisDialog, &wp);\r
2197     analysisX = wp.rcNormalPosition.left;\r
2198     analysisY = wp.rcNormalPosition.top;\r
2199     analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2200     analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2201   }\r
2202 \r
2203   if (commentDialog) {\r
2204     GetWindowPlacement(commentDialog, &wp);\r
2205     commentX = wp.rcNormalPosition.left;\r
2206     commentY = wp.rcNormalPosition.top;\r
2207     commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2208     commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2209   }\r
2210 \r
2211   if (editTagsDialog) {\r
2212     GetWindowPlacement(editTagsDialog, &wp);\r
2213     editTagsX = wp.rcNormalPosition.left;\r
2214     editTagsY = wp.rcNormalPosition.top;\r
2215     editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2216     editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2217   }\r
2218 \r
2219   if (gameListDialog) {\r
2220     GetWindowPlacement(gameListDialog, &wp);\r
2221     gameListX = wp.rcNormalPosition.left;\r
2222     gameListY = wp.rcNormalPosition.top;\r
2223     gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2224     gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2225   }\r
2226 \r
2227   /* [AS] Move history */\r
2228   wpMoveHistory.visible = MoveHistoryIsUp();\r
2229   \r
2230   if( moveHistoryDialog ) {\r
2231     GetWindowPlacement(moveHistoryDialog, &wp);\r
2232     wpMoveHistory.x = wp.rcNormalPosition.left;\r
2233     wpMoveHistory.y = wp.rcNormalPosition.top;\r
2234     wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2235     wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2236   }\r
2237 \r
2238   /* [AS] Eval graph */\r
2239   wpEvalGraph.visible = EvalGraphIsUp();\r
2240 \r
2241   if( evalGraphDialog ) {\r
2242     GetWindowPlacement(evalGraphDialog, &wp);\r
2243     wpEvalGraph.x = wp.rcNormalPosition.left;\r
2244     wpEvalGraph.y = wp.rcNormalPosition.top;\r
2245     wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2246     wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2247   }\r
2248 \r
2249   /* [AS] Engine output */\r
2250   wpEngineOutput.visible = EngineOutputIsUp();\r
2251 \r
2252   if( engineOutputDialog ) {\r
2253     GetWindowPlacement(engineOutputDialog, &wp);\r
2254     wpEngineOutput.x = wp.rcNormalPosition.left;\r
2255     wpEngineOutput.y = wp.rcNormalPosition.top;\r
2256     wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2257     wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2258   }\r
2259 \r
2260   for (ad = argDescriptors; ad->argName != NULL; ad++) {\r
2261     if (!ad->save) continue;\r
2262     switch (ad->argType) {\r
2263     case ArgString:\r
2264       {\r
2265         char *p = *(char **)ad->argLoc;\r
2266         if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {\r
2267           /* Quote multiline values or \-containing values\r
2268              with { } if possible */\r
2269           fprintf(f, "/%s={%s}\n", ad->argName, p);\r
2270         } else {\r
2271           /* Else quote with " " */\r
2272           fprintf(f, "/%s=\"", ad->argName);\r
2273           while (*p) {\r
2274             if (*p == '\n') fprintf(f, "\n");\r
2275             else if (*p == '\r') fprintf(f, "\\r");\r
2276             else if (*p == '\t') fprintf(f, "\\t");\r
2277             else if (*p == '\b') fprintf(f, "\\b");\r
2278             else if (*p == '\f') fprintf(f, "\\f");\r
2279             else if (*p < ' ') fprintf(f, "\\%03o", *p);\r
2280             else if (*p == '\"') fprintf(f, "\\\"");\r
2281             else if (*p == '\\') fprintf(f, "\\\\");\r
2282             else putc(*p, f);\r
2283             p++;\r
2284           }\r
2285           fprintf(f, "\"\n");\r
2286         }\r
2287       }\r
2288       break;\r
2289     case ArgInt:\r
2290       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);\r
2291       break;\r
2292     case ArgFloat:\r
2293       fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);\r
2294       break;\r
2295     case ArgBoolean:\r
2296       fprintf(f, "/%s=%s\n", ad->argName, \r
2297         (*(Boolean *)ad->argLoc) ? "true" : "false");\r
2298       break;\r
2299     case ArgTrue:\r
2300       if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
2301       break;\r
2302     case ArgFalse:\r
2303       if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
2304       break;\r
2305     case ArgColor:\r
2306       {\r
2307         COLORREF color = *(COLORREF *)ad->argLoc;\r
2308         fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName, \r
2309           color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
2310       }\r
2311       break;\r
2312     case ArgAttribs:\r
2313       {\r
2314         MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];\r
2315         fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,\r
2316           (ta->effects & CFE_BOLD) ? "b" : "",\r
2317           (ta->effects & CFE_ITALIC) ? "i" : "",\r
2318           (ta->effects & CFE_UNDERLINE) ? "u" : "",\r
2319           (ta->effects & CFE_STRIKEOUT) ? "s" : "",\r
2320           (ta->effects) ? " " : "",\r
2321           ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);\r
2322       }\r
2323       break;\r
2324     case ArgFilename:\r
2325       if (strchr(*(char **)ad->argLoc, '\"')) {\r
2326         fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);\r
2327       } else {\r
2328         fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);\r
2329       }\r
2330       break;\r
2331     case ArgBoardSize:\r
2332       fprintf(f, "/%s=%s\n", ad->argName,\r
2333               sizeInfo[*(BoardSize *)ad->argLoc].name);\r
2334       break;\r
2335     case ArgFont:\r
2336       {\r
2337         int bs;\r
2338         for (bs=0; bs<NUM_SIZES; bs++) {\r
2339           MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;\r
2340           fprintf(f, "/size=%s ", sizeInfo[bs].name);\r
2341           fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",\r
2342             ad->argName, mfp->faceName, mfp->pointSize,\r
2343             mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",\r
2344             mfp->bold ? "b" : "",\r
2345             mfp->italic ? "i" : "",\r
2346             mfp->underline ? "u" : "",\r
2347             mfp->strikeout ? "s" : "");\r
2348         }\r
2349       }\r
2350       break;\r
2351     case ArgCommSettings:\r
2352       PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);\r
2353     case ArgNone:\r
2354     case ArgSettingsFilename: ;\r
2355     }\r
2356   }\r
2357   fclose(f);\r
2358 }\r
2359 \r
2360 \r
2361 \r
2362 /*---------------------------------------------------------------------------*\\r
2363  *\r
2364  * GDI board drawing routines\r
2365  *\r
2366 \*---------------------------------------------------------------------------*/\r
2367 \r
2368 /* [AS] Draw square using background texture */\r
2369 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )\r
2370 {\r
2371     XFORM   x;\r
2372 \r
2373     if( mode == 0 ) {\r
2374         return; /* Should never happen! */\r
2375     }\r
2376 \r
2377     SetGraphicsMode( dst, GM_ADVANCED );\r
2378 \r
2379     switch( mode ) {\r
2380     case 1:\r
2381         /* Identity */\r
2382         break;\r
2383     case 2:\r
2384         /* X reflection */\r
2385         x.eM11 = -1.0;\r
2386         x.eM12 = 0;\r
2387         x.eM21 = 0;\r
2388         x.eM22 = 1.0;\r
2389         x.eDx = (FLOAT) dw + dx - 1;\r
2390         x.eDy = 0;\r
2391         dx = 0;\r
2392         SetWorldTransform( dst, &x );\r
2393         break;\r
2394     case 3:\r
2395         /* Y reflection */\r
2396         x.eM11 = 1.0;\r
2397         x.eM12 = 0;\r
2398         x.eM21 = 0;\r
2399         x.eM22 = -1.0;\r
2400         x.eDx = 0;\r
2401         x.eDy = (FLOAT) dh + dy - 1;\r
2402         dy = 0;\r
2403         SetWorldTransform( dst, &x );\r
2404         break;\r
2405     case 4:\r
2406         /* X/Y flip */\r
2407         x.eM11 = 0;\r
2408         x.eM12 = 1.0;\r
2409         x.eM21 = 1.0;\r
2410         x.eM22 = 0;\r
2411         x.eDx = (FLOAT) dx;\r
2412         x.eDy = (FLOAT) dy;\r
2413         dx = 0;\r
2414         dy = 0;\r
2415         SetWorldTransform( dst, &x );\r
2416         break;\r
2417     }\r
2418 \r
2419     BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );\r
2420 \r
2421     x.eM11 = 1.0;\r
2422     x.eM12 = 0;\r
2423     x.eM21 = 0;\r
2424     x.eM22 = 1.0;\r
2425     x.eDx = 0;\r
2426     x.eDy = 0;\r
2427     SetWorldTransform( dst, &x );\r
2428 \r
2429     ModifyWorldTransform( dst, 0, MWT_IDENTITY );\r
2430 }\r
2431 \r
2432 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */\r
2433 enum {\r
2434     PM_WP = (int) WhitePawn, \r
2435     PM_WN = (int) WhiteKnight, \r
2436     PM_WB = (int) WhiteBishop, \r
2437     PM_WR = (int) WhiteRook, \r
2438     PM_WQ = (int) WhiteQueen, \r
2439     PM_WF = (int) WhiteFerz, \r
2440     PM_WW = (int) WhiteWazir, \r
2441     PM_WE = (int) WhiteAlfil, \r
2442     PM_WM = (int) WhiteMan, \r
2443     PM_WO = (int) WhiteCannon, \r
2444     PM_WU = (int) WhiteUnicorn, \r
2445     PM_WH = (int) WhiteNightrider, \r
2446     PM_WA = (int) WhiteAngel, \r
2447     PM_WC = (int) WhiteMarshall, \r
2448     PM_WAB = (int) WhiteCardinal, \r
2449     PM_WD = (int) WhiteDragon, \r
2450     PM_WL = (int) WhiteLance, \r
2451     PM_WS = (int) WhiteCobra, \r
2452     PM_WV = (int) WhiteFalcon, \r
2453     PM_WSG = (int) WhiteSilver, \r
2454     PM_WG = (int) WhiteGrasshopper, \r
2455     PM_WK = (int) WhiteKing,\r
2456     PM_BP = (int) BlackPawn, \r
2457     PM_BN = (int) BlackKnight, \r
2458     PM_BB = (int) BlackBishop, \r
2459     PM_BR = (int) BlackRook, \r
2460     PM_BQ = (int) BlackQueen, \r
2461     PM_BF = (int) BlackFerz, \r
2462     PM_BW = (int) BlackWazir, \r
2463     PM_BE = (int) BlackAlfil, \r
2464     PM_BM = (int) BlackMan,\r
2465     PM_BO = (int) BlackCannon, \r
2466     PM_BU = (int) BlackUnicorn, \r
2467     PM_BH = (int) BlackNightrider, \r
2468     PM_BA = (int) BlackAngel, \r
2469     PM_BC = (int) BlackMarshall, \r
2470     PM_BG = (int) BlackGrasshopper, \r
2471     PM_BAB = (int) BlackCardinal,\r
2472     PM_BD = (int) BlackDragon,\r
2473     PM_BL = (int) BlackLance,\r
2474     PM_BS = (int) BlackCobra,\r
2475     PM_BV = (int) BlackFalcon,\r
2476     PM_BSG = (int) BlackSilver,\r
2477     PM_BK = (int) BlackKing\r
2478 };\r
2479 \r
2480 static HFONT hPieceFont = NULL;\r
2481 static HBITMAP hPieceMask[(int) EmptySquare];\r
2482 static HBITMAP hPieceFace[(int) EmptySquare];\r
2483 static int fontBitmapSquareSize = 0;\r
2484 static char pieceToFontChar[(int) EmptySquare] =\r
2485                               { 'p', 'n', 'b', 'r', 'q', \r
2486                       'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',\r
2487                       'k', 'o', 'm', 'v', 't', 'w', \r
2488                       'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',\r
2489                                                               'l' };\r
2490 \r
2491 extern BOOL SetCharTable( char *table, const char * map );\r
2492 /* [HGM] moved to backend.c */\r
2493 \r
2494 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )\r
2495 {\r
2496     HBRUSH hbrush;\r
2497     BYTE r1 = GetRValue( color );\r
2498     BYTE g1 = GetGValue( color );\r
2499     BYTE b1 = GetBValue( color );\r
2500     BYTE r2 = r1 / 2;\r
2501     BYTE g2 = g1 / 2;\r
2502     BYTE b2 = b1 / 2;\r
2503     RECT rc;\r
2504 \r
2505     /* Create a uniform background first */\r
2506     hbrush = CreateSolidBrush( color );\r
2507     SetRect( &rc, 0, 0, squareSize, squareSize );\r
2508     FillRect( hdc, &rc, hbrush );\r
2509     DeleteObject( hbrush );\r
2510     \r
2511     if( mode == 1 ) {\r
2512         /* Vertical gradient, good for pawn, knight and rook, less for queen and king */\r
2513         int steps = squareSize / 2;\r
2514         int i;\r
2515 \r
2516         for( i=0; i<steps; i++ ) {\r
2517             BYTE r = r1 - (r1-r2) * i / steps;\r
2518             BYTE g = g1 - (g1-g2) * i / steps;\r
2519             BYTE b = b1 - (b1-b2) * i / steps;\r
2520 \r
2521             hbrush = CreateSolidBrush( RGB(r,g,b) );\r
2522             SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );\r
2523             FillRect( hdc, &rc, hbrush );\r
2524             DeleteObject(hbrush);\r
2525         }\r
2526     }\r
2527     else if( mode == 2 ) {\r
2528         /* Diagonal gradient, good more or less for every piece */\r
2529         POINT triangle[3];\r
2530         HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );\r
2531         HBRUSH hbrush_old;\r
2532         int steps = squareSize;\r
2533         int i;\r
2534 \r
2535         triangle[0].x = squareSize - steps;\r
2536         triangle[0].y = squareSize;\r
2537         triangle[1].x = squareSize;\r
2538         triangle[1].y = squareSize;\r
2539         triangle[2].x = squareSize;\r
2540         triangle[2].y = squareSize - steps;\r
2541 \r
2542         for( i=0; i<steps; i++ ) {\r
2543             BYTE r = r1 - (r1-r2) * i / steps;\r
2544             BYTE g = g1 - (g1-g2) * i / steps;\r
2545             BYTE b = b1 - (b1-b2) * i / steps;\r
2546 \r
2547             hbrush = CreateSolidBrush( RGB(r,g,b) );\r
2548             hbrush_old = SelectObject( hdc, hbrush );\r
2549             Polygon( hdc, triangle, 3 );\r
2550             SelectObject( hdc, hbrush_old );\r
2551             DeleteObject(hbrush);\r
2552             triangle[0].x++;\r
2553             triangle[2].y++;\r
2554         }\r
2555 \r
2556         SelectObject( hdc, hpen );\r
2557     }\r
2558 }\r
2559 \r
2560 /*\r
2561     [AS] The method I use to create the bitmaps it a bit tricky, but it\r
2562     seems to work ok. The main problem here is to find the "inside" of a chess\r
2563     piece: follow the steps as explained below.\r
2564 */\r
2565 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )\r
2566 {\r
2567     HBITMAP hbm;\r
2568     HBITMAP hbm_old;\r
2569     COLORREF chroma = RGB(0xFF,0x00,0xFF);\r
2570     RECT rc;\r
2571     SIZE sz;\r
2572     POINT pt;\r
2573     int backColor = whitePieceColor; \r
2574     int foreColor = blackPieceColor;\r
2575     \r
2576     if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {\r
2577         backColor = appData.fontBackColorWhite;\r
2578         foreColor = appData.fontForeColorWhite;\r
2579     }\r
2580     else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {\r
2581         backColor = appData.fontBackColorBlack;\r
2582         foreColor = appData.fontForeColorBlack;\r
2583     }\r
2584 \r
2585     /* Mask */\r
2586     hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2587 \r
2588     hbm_old = SelectObject( hdc, hbm );\r
2589 \r
2590     rc.left = 0;\r
2591     rc.top = 0;\r
2592     rc.right = squareSize;\r
2593     rc.bottom = squareSize;\r
2594 \r
2595     /* Step 1: background is now black */\r
2596     FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );\r
2597 \r
2598     GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );\r
2599 \r
2600     pt.x = (squareSize - sz.cx) / 2;\r
2601     pt.y = (squareSize - sz.cy) / 2;\r
2602 \r
2603     SetBkMode( hdc, TRANSPARENT );\r
2604     SetTextColor( hdc, chroma );\r
2605     /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */\r
2606     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2607 \r
2608     SelectObject( hdc, GetStockObject(WHITE_BRUSH) );\r
2609     /* Step 3: the area outside the piece is filled with white */\r
2610 //    FloodFill( hdc, 0, 0, chroma );\r
2611     ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );\r
2612     ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big\r
2613     ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );\r
2614     ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );\r
2615     SelectObject( hdc, GetStockObject(BLACK_BRUSH) );\r
2616     /* \r
2617         Step 4: this is the tricky part, the area inside the piece is filled with black,\r
2618         but if the start point is not inside the piece we're lost!\r
2619         There should be a better way to do this... if we could create a region or path\r
2620         from the fill operation we would be fine for example.\r
2621     */\r
2622 //    FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );\r
2623     ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );\r
2624 \r
2625     {   /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */\r
2626         HDC dc2 = CreateCompatibleDC( hdc_window );\r
2627         HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2628 \r
2629         SelectObject( dc2, bm2 );\r
2630         BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy\r
2631         BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2632         BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2633         BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2634         BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2635 \r
2636         DeleteDC( dc2 );\r
2637         DeleteObject( bm2 );\r
2638     }\r
2639 \r
2640     SetTextColor( hdc, 0 );\r
2641     /* \r
2642         Step 5: some fonts have "disconnected" areas that are skipped by the fill:\r
2643         draw the piece again in black for safety.\r
2644     */\r
2645     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2646 \r
2647     SelectObject( hdc, hbm_old );\r
2648 \r
2649     if( hPieceMask[index] != NULL ) {\r
2650         DeleteObject( hPieceMask[index] );\r
2651     }\r
2652 \r
2653     hPieceMask[index] = hbm;\r
2654 \r
2655     /* Face */\r
2656     hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2657 \r
2658     SelectObject( hdc, hbm );\r
2659 \r
2660     {\r
2661         HDC dc1 = CreateCompatibleDC( hdc_window );\r
2662         HDC dc2 = CreateCompatibleDC( hdc_window );\r
2663         HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2664 \r
2665         SelectObject( dc1, hPieceMask[index] );\r
2666         SelectObject( dc2, bm2 );\r
2667         FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );\r
2668         BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );\r
2669         \r
2670         /* \r
2671             Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves\r
2672             the piece background and deletes (makes transparent) the rest.\r
2673             Thanks to that mask, we are free to paint the background with the greates\r
2674             freedom, as we'll be able to mask off the unwanted parts when finished.\r
2675             We use this, to make gradients and give the pieces a "roundish" look.\r
2676         */\r
2677         SetPieceBackground( hdc, backColor, 2 );\r
2678         BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );\r
2679 \r
2680         DeleteDC( dc2 );\r
2681         DeleteDC( dc1 );\r
2682         DeleteObject( bm2 );\r
2683     }\r
2684 \r
2685     SetTextColor( hdc, foreColor );\r
2686     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2687 \r
2688     SelectObject( hdc, hbm_old );\r
2689 \r
2690     if( hPieceFace[index] != NULL ) {\r
2691         DeleteObject( hPieceFace[index] );\r
2692     }\r
2693 \r
2694     hPieceFace[index] = hbm;\r
2695 }\r
2696 \r
2697 static int TranslatePieceToFontPiece( int piece )\r
2698 {\r
2699     switch( piece ) {\r
2700     case BlackPawn:\r
2701         return PM_BP;\r
2702     case BlackKnight:\r
2703         return PM_BN;\r
2704     case BlackBishop:\r
2705         return PM_BB;\r
2706     case BlackRook:\r
2707         return PM_BR;\r
2708     case BlackQueen:\r
2709         return PM_BQ;\r
2710     case BlackKing:\r
2711         return PM_BK;\r
2712     case WhitePawn:\r
2713         return PM_WP;\r
2714     case WhiteKnight:\r
2715         return PM_WN;\r
2716     case WhiteBishop:\r
2717         return PM_WB;\r
2718     case WhiteRook:\r
2719         return PM_WR;\r
2720     case WhiteQueen:\r
2721         return PM_WQ;\r
2722     case WhiteKing:\r
2723         return PM_WK;\r
2724 \r
2725     case BlackAngel:\r
2726         return PM_BA;\r
2727     case BlackMarshall:\r
2728         return PM_BC;\r
2729     case BlackFerz:\r
2730         return PM_BF;\r
2731     case BlackNightrider:\r
2732         return PM_BH;\r
2733     case BlackAlfil:\r
2734         return PM_BE;\r
2735     case BlackWazir:\r
2736         return PM_BW;\r
2737     case BlackUnicorn:\r
2738         return PM_BU;\r
2739     case BlackCannon:\r
2740         return PM_BO;\r
2741     case BlackGrasshopper:\r
2742         return PM_BG;\r
2743     case BlackMan:\r
2744         return PM_BM;\r
2745     case BlackSilver:\r
2746         return PM_BSG;\r
2747     case BlackLance:\r
2748         return PM_BL;\r
2749     case BlackFalcon:\r
2750         return PM_BV;\r
2751     case BlackCobra:\r
2752         return PM_BS;\r
2753     case BlackCardinal:\r
2754         return PM_BAB;\r
2755     case BlackDragon:\r
2756         return PM_BD;\r
2757 \r
2758     case WhiteAngel:\r
2759         return PM_WA;\r
2760     case WhiteMarshall:\r
2761         return PM_WC;\r
2762     case WhiteFerz:\r
2763         return PM_WF;\r
2764     case WhiteNightrider:\r
2765         return PM_WH;\r
2766     case WhiteAlfil:\r
2767         return PM_WE;\r
2768     case WhiteWazir:\r
2769         return PM_WW;\r
2770     case WhiteUnicorn:\r
2771         return PM_WU;\r
2772     case WhiteCannon:\r
2773         return PM_WO;\r
2774     case WhiteGrasshopper:\r
2775         return PM_WG;\r
2776     case WhiteMan:\r
2777         return PM_WM;\r
2778     case WhiteSilver:\r
2779         return PM_WSG;\r
2780     case WhiteLance:\r
2781         return PM_WL;\r
2782     case WhiteFalcon:\r
2783         return PM_WV;\r
2784     case WhiteCobra:\r
2785         return PM_WS;\r
2786     case WhiteCardinal:\r
2787         return PM_WAB;\r
2788     case WhiteDragon:\r
2789         return PM_WD;\r
2790     }\r
2791 \r
2792     return 0;\r
2793 }\r
2794 \r
2795 void CreatePiecesFromFont()\r
2796 {\r
2797     LOGFONT lf;\r
2798     HDC hdc_window = NULL;\r
2799     HDC hdc = NULL;\r
2800     HFONT hfont_old;\r
2801     int fontHeight;\r
2802     int i;\r
2803 \r
2804     if( fontBitmapSquareSize < 0 ) {\r
2805         /* Something went seriously wrong in the past: do not try to recreate fonts! */\r
2806         return;\r
2807     }\r
2808 \r
2809     if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {\r
2810         fontBitmapSquareSize = -1;\r
2811         return;\r
2812     }\r
2813 \r
2814     if( fontBitmapSquareSize != squareSize ) {\r
2815         hdc_window = GetDC( hwndMain );\r
2816         hdc = CreateCompatibleDC( hdc_window );\r
2817 \r
2818         if( hPieceFont != NULL ) {\r
2819             DeleteObject( hPieceFont );\r
2820         }\r
2821         else {\r
2822             for( i=0; i<=(int)BlackKing; i++ ) {\r
2823                 hPieceMask[i] = NULL;\r
2824                 hPieceFace[i] = NULL;\r
2825             }\r
2826         }\r
2827 \r
2828         fontHeight = 75;\r
2829 \r
2830         if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {\r
2831             fontHeight = appData.fontPieceSize;\r
2832         }\r
2833 \r
2834         fontHeight = (fontHeight * squareSize) / 100;\r
2835 \r
2836         lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );\r
2837         lf.lfWidth = 0;\r
2838         lf.lfEscapement = 0;\r
2839         lf.lfOrientation = 0;\r
2840         lf.lfWeight = FW_NORMAL;\r
2841         lf.lfItalic = 0;\r
2842         lf.lfUnderline = 0;\r
2843         lf.lfStrikeOut = 0;\r
2844         lf.lfCharSet = DEFAULT_CHARSET;\r
2845         lf.lfOutPrecision = OUT_DEFAULT_PRECIS;\r
2846         lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
2847         lf.lfQuality = PROOF_QUALITY;\r
2848         lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;\r
2849         strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );\r
2850         lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';\r
2851 \r
2852         hPieceFont = CreateFontIndirect( &lf );\r
2853 \r
2854         if( hPieceFont == NULL ) {\r
2855             fontBitmapSquareSize = -2;\r
2856         }\r
2857         else {\r
2858             /* Setup font-to-piece character table */\r
2859             if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {\r
2860                 /* No (or wrong) global settings, try to detect the font */\r
2861                 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {\r
2862                     /* Alpha */\r
2863                     SetCharTable(pieceToFontChar, "phbrqkojntwl");\r
2864                 }\r
2865                 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {\r
2866                     /* DiagramTT* family */\r
2867                     SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");\r
2868                 }\r
2869                 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {\r
2870                     /* Fairy symbols */\r
2871                      SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");\r
2872                 }\r
2873                 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {\r
2874                     /* Good Companion (Some characters get warped as literal :-( */\r
2875                     char s[] = "1cmWG0ñueOS¯®oYI23wgQU";\r
2876                     s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;\r
2877                     SetCharTable(pieceToFontChar, s);\r
2878                 }\r
2879                 else {\r
2880                     /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */\r
2881                     SetCharTable(pieceToFontChar, "pnbrqkomvtwl");\r
2882                 }\r
2883             }\r
2884 \r
2885             /* Create bitmaps */\r
2886             hfont_old = SelectObject( hdc, hPieceFont );\r
2887 #if 0\r
2888             CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );\r
2889             CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );\r
2890             CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );\r
2891             CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );\r
2892             CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );\r
2893             CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );\r
2894             CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );\r
2895             CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );\r
2896             CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );\r
2897             CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );\r
2898             CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );\r
2899             CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );\r
2900 \r
2901             CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );\r
2902             CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );\r
2903             CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );\r
2904             CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );\r
2905             CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );\r
2906             CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );\r
2907             CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );\r
2908             CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );\r
2909             CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );\r
2910             CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );\r
2911             CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );\r
2912             CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );\r
2913             CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );\r
2914             CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );\r
2915             CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );\r
2916             CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );\r
2917             CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );\r
2918             CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );\r
2919             CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );\r
2920             CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );\r
2921             CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );\r
2922             CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );\r
2923             CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );\r
2924             CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );\r
2925             CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );\r
2926             CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );\r
2927             CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );\r
2928             CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );\r
2929             CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );\r
2930             CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );\r
2931             CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );\r
2932             CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );\r
2933 #else\r
2934             for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */\r
2935                 if(PieceToChar((ChessSquare)i) != '.')     /* skip unused pieces         */\r
2936                     CreatePieceMaskFromFont( hdc_window, hdc, i );\r
2937 #endif\r
2938             SelectObject( hdc, hfont_old );\r
2939 \r
2940             fontBitmapSquareSize = squareSize;\r
2941         }\r
2942     }\r
2943 \r
2944     if( hdc != NULL ) {\r
2945         DeleteDC( hdc );\r
2946     }\r
2947 \r
2948     if( hdc_window != NULL ) {\r
2949         ReleaseDC( hwndMain, hdc_window );\r
2950     }\r
2951 }\r
2952 \r
2953 HBITMAP\r
2954 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)\r
2955 {\r
2956   char name[128];\r
2957 \r
2958   sprintf(name, "%s%d%s", piece, squareSize, suffix);\r
2959   if (gameInfo.event &&\r
2960       strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&\r
2961       strcmp(name, "k80s") == 0) {\r
2962     strcpy(name, "tim");\r
2963   }\r
2964   return LoadBitmap(hinst, name);\r
2965 }\r
2966 \r
2967 \r
2968 /* Insert a color into the program's logical palette\r
2969    structure.  This code assumes the given color is\r
2970    the result of the RGB or PALETTERGB macro, and it\r
2971    knows how those macros work (which is documented).\r
2972 */\r
2973 VOID\r
2974 InsertInPalette(COLORREF color)\r
2975 {\r
2976   LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);\r
2977 \r
2978   if (pLogPal->palNumEntries++ >= PALETTESIZE) {\r
2979     DisplayFatalError("Too many colors", 0, 1);\r
2980     pLogPal->palNumEntries--;\r
2981     return;\r
2982   }\r
2983 \r
2984   pe->peFlags = (char) 0;\r
2985   pe->peRed = (char) (0xFF & color);\r
2986   pe->peGreen = (char) (0xFF & (color >> 8));\r
2987   pe->peBlue = (char) (0xFF & (color >> 16));\r
2988   return;\r
2989 }\r
2990 \r
2991 \r
2992 VOID\r
2993 InitDrawingColors()\r
2994 {\r
2995   if (pLogPal == NULL) {\r
2996     /* Allocate enough memory for a logical palette with\r
2997      * PALETTESIZE entries and set the size and version fields\r
2998      * of the logical palette structure.\r
2999      */\r
3000     pLogPal = (NPLOGPALETTE)\r
3001       LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +\r
3002                               (sizeof(PALETTEENTRY) * (PALETTESIZE))));\r
3003     pLogPal->palVersion    = 0x300;\r
3004   }\r
3005   pLogPal->palNumEntries = 0;\r
3006 \r
3007   InsertInPalette(lightSquareColor);\r
3008   InsertInPalette(darkSquareColor);\r
3009   InsertInPalette(whitePieceColor);\r
3010   InsertInPalette(blackPieceColor);\r
3011   InsertInPalette(highlightSquareColor);\r
3012   InsertInPalette(premoveHighlightColor);\r
3013 \r
3014   /*  create a logical color palette according the information\r
3015    *  in the LOGPALETTE structure.\r
3016    */\r
3017   hPal = CreatePalette((LPLOGPALETTE) pLogPal);\r
3018 \r
3019   lightSquareBrush = CreateSolidBrush(lightSquareColor);\r
3020   blackSquareBrush = CreateSolidBrush(blackPieceColor);\r
3021   darkSquareBrush = CreateSolidBrush(darkSquareColor);\r
3022   whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
3023   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
3024   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
3025   explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic\r
3026   /* [AS] Force rendering of the font-based pieces */\r
3027   if( fontBitmapSquareSize > 0 ) {\r
3028     fontBitmapSquareSize = 0;\r
3029   }\r
3030 }\r
3031 \r
3032 \r
3033 int\r
3034 BoardWidth(int boardSize, int n)\r
3035 { /* [HGM] argument n added to allow different width and height */\r
3036   int lineGap = sizeInfo[boardSize].lineGap;\r
3037 \r
3038   if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
3039       lineGap = appData.overrideLineGap;\r
3040   }\r
3041 \r
3042   return (n + 1) * lineGap +\r
3043           n * sizeInfo[boardSize].squareSize;\r
3044 }\r
3045 \r
3046 /* Respond to board resize by dragging edge */\r
3047 VOID\r
3048 ResizeBoard(int newSizeX, int newSizeY, int flags)\r
3049 {\r
3050   BoardSize newSize = NUM_SIZES - 1;\r
3051   static int recurse = 0;\r
3052   if (IsIconic(hwndMain)) return;\r
3053   if (recurse > 0) return;\r
3054   recurse++;\r
3055   while (newSize > 0) {\r
3056         InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects\r
3057         if(newSizeX >= sizeInfo[newSize].cliWidth &&\r
3058            newSizeY >= sizeInfo[newSize].cliHeight) break;\r
3059     newSize--;\r
3060   } \r
3061   boardSize = newSize;\r
3062   InitDrawingSizes(boardSize, flags);\r
3063   recurse--;\r
3064 }\r
3065 \r
3066 \r
3067 \r
3068 VOID\r
3069 InitDrawingSizes(BoardSize boardSize, int flags)\r
3070 {\r
3071   int i, boardWidth, boardHeight; /* [HGM] height treated separately */\r
3072   ChessSquare piece;\r
3073   static int oldBoardSize = -1, oldTinyLayout = 0;\r
3074   HDC hdc;\r
3075   SIZE clockSize, messageSize;\r
3076   HFONT oldFont;\r
3077   char buf[MSG_SIZ];\r
3078   char *str;\r
3079   HMENU hmenu = GetMenu(hwndMain);\r
3080   RECT crect, wrect;\r
3081   int offby;\r
3082   LOGBRUSH logbrush;\r
3083 \r
3084   int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only\r
3085   if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }\r
3086 \r
3087   /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */\r
3088   if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;\r
3089 \r
3090   tinyLayout = sizeInfo[boardSize].tinyLayout;\r
3091   smallLayout = sizeInfo[boardSize].smallLayout;\r
3092   squareSize = sizeInfo[boardSize].squareSize;\r
3093   lineGap = sizeInfo[boardSize].lineGap;\r
3094   minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted  */\r
3095 \r
3096   if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
3097       lineGap = appData.overrideLineGap;\r
3098   }\r
3099 \r
3100   if (tinyLayout != oldTinyLayout) {\r
3101     long style = GetWindowLong(hwndMain, GWL_STYLE);\r
3102     if (tinyLayout) {\r
3103       style &= ~WS_SYSMENU;\r
3104       InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,\r
3105                  "&Minimize\tCtrl+F4");\r
3106     } else {\r
3107       style |= WS_SYSMENU;\r
3108       RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);\r
3109     }\r
3110     SetWindowLong(hwndMain, GWL_STYLE, style);\r
3111 \r
3112     for (i=0; menuBarText[tinyLayout][i]; i++) {\r
3113       ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP, \r
3114         (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);\r
3115     }\r
3116     DrawMenuBar(hwndMain);\r
3117   }\r
3118 \r
3119   boardWidth  = BoardWidth(boardSize, BOARD_WIDTH);\r
3120   boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);\r
3121 \r
3122   /* Get text area sizes */\r
3123   hdc = GetDC(hwndMain);\r
3124   if (appData.clockMode) {\r
3125     sprintf(buf, "White: %s", TimeString(23*60*60*1000L));\r
3126   } else {\r
3127     sprintf(buf, "White");\r
3128   }\r
3129   oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
3130   GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);\r
3131   SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
3132   str = "We only care about the height here";\r
3133   GetTextExtentPoint(hdc, str, strlen(str), &messageSize);\r
3134   SelectObject(hdc, oldFont);\r
3135   ReleaseDC(hwndMain, hdc);\r
3136 \r
3137   /* Compute where everything goes */\r
3138   if(first.programLogo || second.programLogo) {\r
3139         /* [HGM] logo: if either logo is on, reserve space for it */\r
3140         logoHeight =  2*clockSize.cy;\r
3141         leftLogoRect.left   = OUTER_MARGIN;\r
3142         leftLogoRect.right  = leftLogoRect.left + 4*clockSize.cy;\r
3143         leftLogoRect.top    = OUTER_MARGIN;\r
3144         leftLogoRect.bottom = OUTER_MARGIN + logoHeight;\r
3145 \r
3146         rightLogoRect.right  = OUTER_MARGIN + boardWidth;\r
3147         rightLogoRect.left   = rightLogoRect.right - 4*clockSize.cy;\r
3148         rightLogoRect.top    = OUTER_MARGIN;\r
3149         rightLogoRect.bottom = OUTER_MARGIN + logoHeight;\r
3150 \r
3151 \r
3152     blackRect.left = leftLogoRect.right;\r
3153     blackRect.right = rightLogoRect.left;\r
3154     blackRect.top = OUTER_MARGIN;\r
3155     blackRect.bottom = blackRect.top + clockSize.cy;\r
3156 \r
3157     whiteRect.left = blackRect.left ;\r
3158     whiteRect.right = blackRect.right;\r
3159     whiteRect.top = blackRect.bottom;\r
3160     whiteRect.bottom = leftLogoRect.bottom;\r
3161   } else {\r
3162     whiteRect.left = OUTER_MARGIN;\r
3163     whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;\r
3164     whiteRect.top = OUTER_MARGIN + logoHeight;\r
3165     whiteRect.bottom = whiteRect.top + clockSize.cy;\r
3166 \r
3167     blackRect.left = whiteRect.right + INNER_MARGIN;\r
3168     blackRect.right = blackRect.left + boardWidth/2 - 1;\r
3169     blackRect.top = whiteRect.top;\r
3170     blackRect.bottom = whiteRect.bottom;\r
3171   }\r
3172 \r
3173   messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;\r
3174   if (appData.showButtonBar) {\r
3175     messageRect.right = OUTER_MARGIN + boardWidth         // [HGM] logo: expressed independent of clock placement\r
3176       - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;\r
3177   } else {\r
3178     messageRect.right = OUTER_MARGIN + boardWidth;\r
3179   }\r
3180   messageRect.top = whiteRect.bottom + INNER_MARGIN;\r
3181   messageRect.bottom = messageRect.top + messageSize.cy;\r
3182 \r
3183   boardRect.left = OUTER_MARGIN;\r
3184   boardRect.right = boardRect.left + boardWidth;\r
3185   boardRect.top = messageRect.bottom + INNER_MARGIN;\r
3186   boardRect.bottom = boardRect.top + boardHeight;\r
3187 \r
3188   sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;\r
3189   sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;\r
3190   if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only\r
3191   winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;\r
3192   winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +\r
3193     GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;\r
3194   GetWindowRect(hwndMain, &wrect);\r
3195   SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,\r
3196                SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
3197   /* compensate if menu bar wrapped */\r
3198   GetClientRect(hwndMain, &crect);\r
3199   offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;\r
3200   winHeight += offby;\r
3201   switch (flags) {\r
3202   case WMSZ_TOPLEFT:\r
3203     SetWindowPos(hwndMain, NULL, \r
3204                  wrect.right - winWidth, wrect.bottom - winHeight, \r
3205                  winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
3206     break;\r
3207 \r
3208   case WMSZ_TOPRIGHT:\r
3209   case WMSZ_TOP:\r
3210     SetWindowPos(hwndMain, NULL, \r
3211                  wrect.left, wrect.bottom - winHeight, \r
3212                  winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
3213     break;\r
3214 \r
3215   case WMSZ_BOTTOMLEFT:\r
3216   case WMSZ_LEFT:\r
3217     SetWindowPos(hwndMain, NULL, \r
3218                  wrect.right - winWidth, wrect.top, \r
3219                  winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
3220     break;\r
3221 \r
3222   case WMSZ_BOTTOMRIGHT:\r
3223   case WMSZ_BOTTOM:\r
3224   case WMSZ_RIGHT:\r
3225   default:\r
3226     SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,\r
3227                SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
3228     break;\r
3229   }\r
3230 \r
3231   hwndPause = NULL;\r
3232   for (i = 0; i < N_BUTTONS; i++) {\r
3233     if (buttonDesc[i].hwnd != NULL) {\r
3234       DestroyWindow(buttonDesc[i].hwnd);\r
3235       buttonDesc[i].hwnd = NULL;\r
3236     }\r
3237     if (appData.showButtonBar) {\r
3238       buttonDesc[i].hwnd =\r
3239         CreateWindow("BUTTON", buttonDesc[i].label,\r
3240                      WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,\r
3241                      boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),\r
3242                      messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,\r
3243                      (HMENU) buttonDesc[i].id,\r
3244                      (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);\r
3245       if (tinyLayout) {\r
3246         SendMessage(buttonDesc[i].hwnd, WM_SETFONT, \r
3247                     (WPARAM)font[boardSize][MESSAGE_FONT]->hf,\r
3248                     MAKELPARAM(FALSE, 0));\r
3249       }\r
3250       if (buttonDesc[i].id == IDM_Pause)\r
3251         hwndPause = buttonDesc[i].hwnd;\r
3252       buttonDesc[i].wndproc = (WNDPROC)\r
3253         SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);\r
3254     }\r
3255   }\r
3256   if (gridPen != NULL) DeleteObject(gridPen);\r
3257   if (highlightPen != NULL) DeleteObject(highlightPen);\r
3258   if (premovePen != NULL) DeleteObject(premovePen);\r
3259   if (lineGap != 0) {\r
3260     logbrush.lbStyle = BS_SOLID;\r
3261     logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */\r
3262     gridPen =\r
3263       ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
3264                    lineGap, &logbrush, 0, NULL);\r
3265     logbrush.lbColor = highlightSquareColor;\r
3266     highlightPen =\r
3267       ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
3268                    lineGap, &logbrush, 0, NULL);\r
3269 \r
3270     logbrush.lbColor = premoveHighlightColor; \r
3271     premovePen =\r
3272       ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
3273                    lineGap, &logbrush, 0, NULL);\r
3274 \r
3275     /* [HGM] Loop had to be split in part for vert. and hor. lines */\r
3276     for (i = 0; i < BOARD_HEIGHT + 1; i++) {\r
3277       gridEndpoints[i*2].x = boardRect.left + lineGap / 2;\r
3278       gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =\r
3279         boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));\r
3280       gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +\r
3281         BOARD_WIDTH * (squareSize + lineGap);\r
3282       gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
3283     }\r
3284     for (i = 0; i < BOARD_WIDTH + 1; i++) {\r
3285       gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;\r
3286       gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =\r
3287         gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +\r
3288         lineGap / 2 + (i * (squareSize + lineGap));\r
3289       gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =\r
3290         boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);\r
3291       gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
3292     }\r
3293   }\r
3294 \r
3295   /* [HGM] Licensing requirement */\r
3296 #ifdef GOTHIC\r
3297   if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else\r
3298 #endif\r
3299 #ifdef FALCON\r
3300   if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else\r
3301 #endif\r
3302   GothicPopUp( "", VariantNormal);\r
3303 \r
3304 \r
3305 /*  if (boardSize == oldBoardSize) return; [HGM] variant might have changed */\r
3306   oldBoardSize = boardSize;\r
3307   oldTinyLayout = tinyLayout;\r
3308 \r
3309   /* Load piece bitmaps for this board size */\r
3310   for (i=0; i<=2; i++) {\r
3311     for (piece = WhitePawn;\r
3312          (int) piece < (int) BlackPawn;\r
3313          piece = (ChessSquare) ((int) piece + 1)) {\r
3314       if (pieceBitmap[i][piece] != NULL)\r
3315         DeleteObject(pieceBitmap[i][piece]);\r
3316     }\r
3317   }\r
3318 \r
3319   fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */\r
3320   // Orthodox Chess pieces\r
3321   pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");\r
3322   pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");\r
3323   pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");\r
3324   pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");\r
3325   pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");\r
3326   pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");\r
3327   pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");\r
3328   pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");\r
3329   pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");\r
3330   pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");\r
3331   pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");\r
3332   pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");\r
3333   pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");\r
3334   pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");\r
3335   pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");\r
3336   if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {\r
3337     // in Shogi, Hijack the unused Queen for Lance\r
3338     pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
3339     pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
3340     pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
3341   } else {\r
3342     pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");\r
3343     pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");\r
3344     pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");\r
3345   }\r
3346 \r
3347   if(squareSize <= 72 && squareSize >= 33) { \r
3348     /* A & C are available in most sizes now */\r
3349     if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like\r
3350       pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");\r
3351       pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");\r
3352       pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");\r
3353       pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
3354       pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
3355       pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
3356       pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
3357       pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
3358       pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
3359       pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
3360       pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
3361       pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
3362     } else { // Smirf-like\r
3363       pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");\r
3364       pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");\r
3365       pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");\r
3366     }\r
3367     if(gameInfo.variant == VariantGothic) { // Vortex-like\r
3368       pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
3369       pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
3370       pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
3371     } else { // WinBoard standard\r
3372       pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");\r
3373       pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");\r
3374       pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");\r
3375     }\r
3376   }\r
3377 \r
3378 \r
3379   if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */\r
3380     pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");\r
3381     pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");\r
3382     pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");\r
3383     pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");\r
3384     pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");\r
3385     pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3386     pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");\r
3387     pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");\r
3388     pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");\r
3389     pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");\r
3390     pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");\r
3391     pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");\r
3392     pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");\r
3393     pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");\r
3394     pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");\r
3395     pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");\r
3396     pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");\r
3397     pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");\r
3398     pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");\r
3399     pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");\r
3400     pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");\r
3401     pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");\r
3402     pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");\r
3403     pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");\r
3404     pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
3405     pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
3406     pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
3407     pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");\r
3408     pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");\r
3409     pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");\r
3410 \r
3411     if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */\r
3412       pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");\r
3413       pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");\r
3414       pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3415       pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");\r
3416       pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");\r
3417       pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3418       pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");\r
3419       pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");\r
3420       pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3421       pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");\r
3422       pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");\r
3423       pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
3424     } else {\r
3425       pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");\r
3426       pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");\r
3427       pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");\r
3428       pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");\r
3429       pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");\r
3430       pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");\r
3431       pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
3432       pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
3433       pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
3434       pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");\r
3435       pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");\r
3436       pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");\r
3437     }\r
3438 \r
3439   } else { /* other size, no special bitmaps available. Use smaller symbols */\r
3440     if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;\r
3441     else  minorSize = sizeInfo[(int)boardSize - 2].squareSize;\r
3442     pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");\r
3443     pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");\r
3444     pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");\r
3445     pieceBitmap[0][WhiteCardinal]   = DoLoadBitmap(hInst, "b", minorSize, "s");\r
3446     pieceBitmap[1][WhiteCardinal]   = DoLoadBitmap(hInst, "b", minorSize, "o");\r
3447     pieceBitmap[2][WhiteCardinal]   = DoLoadBitmap(hInst, "b", minorSize, "w");\r
3448     pieceBitmap[0][WhiteDragon]   = DoLoadBitmap(hInst, "r", minorSize, "s");\r
3449     pieceBitmap[1][WhiteDragon]   = DoLoadBitmap(hInst, "r", minorSize, "o");\r
3450     pieceBitmap[2][WhiteDragon]   = DoLoadBitmap(hInst, "r", minorSize, "w");\r
3451     pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");\r
3452     pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");\r
3453     pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");\r
3454   }\r
3455 \r
3456 \r
3457   if(gameInfo.variant == VariantShogi && squareSize == 58)\r
3458   /* special Shogi support in this size */\r
3459   { for (i=0; i<=2; i++) { /* replace all bitmaps */\r
3460       for (piece = WhitePawn;\r
3461            (int) piece < (int) BlackPawn;\r
3462            piece = (ChessSquare) ((int) piece + 1)) {\r
3463         if (pieceBitmap[i][piece] != NULL)\r
3464           DeleteObject(pieceBitmap[i][piece]);\r
3465       }\r
3466     }\r
3467   pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");\r
3468   pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");\r
3469   pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");\r
3470   pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");\r
3471   pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");\r
3472   pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");\r
3473   pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");\r
3474   pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");\r
3475   pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");\r
3476   pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");\r
3477   pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");\r
3478   pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");\r
3479   pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");\r
3480   pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");\r
3481   pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");\r
3482   pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");\r
3483   pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");\r
3484   pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");\r
3485   pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");\r
3486   pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");\r
3487   pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");\r
3488   pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");\r
3489   pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");\r
3490   pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");\r
3491   pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");\r
3492   pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");\r
3493   pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");\r
3494   pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");\r
3495   pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");\r
3496   pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");\r
3497   pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
3498   pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
3499   pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");\r
3500   pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");\r
3501   pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
3502   pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
3503   pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");\r
3504   pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");\r
3505   pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
3506   pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
3507   pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");\r
3508   pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
3509   minorSize = 0;\r
3510   }\r
3511 }\r
3512 \r
3513 HBITMAP\r
3514 PieceBitmap(ChessSquare p, int kind)\r
3515 {\r
3516   if ((int) p >= (int) BlackPawn)\r
3517     p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);\r
3518 \r
3519   return pieceBitmap[kind][(int) p];\r
3520 }\r
3521 \r
3522 /***************************************************************/\r
3523 \r
3524 #define MIN(a,b) (((a) < (b)) ? (a) : (b))\r
3525 #define MAX(a,b) (((a) > (b)) ? (a) : (b))\r
3526 /*\r
3527 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))\r
3528 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))\r
3529 */\r
3530 \r
3531 VOID\r
3532 SquareToPos(int row, int column, int * x, int * y)\r
3533 {\r
3534   if (flipView) {\r
3535     *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);\r
3536     *y = boardRect.top + lineGap + row * (squareSize + lineGap);\r
3537   } else {\r
3538     *x = boardRect.left + lineGap + column * (squareSize + lineGap);\r
3539     *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);\r
3540   }\r
3541 }\r
3542 \r
3543 VOID\r
3544 DrawCoordsOnDC(HDC hdc)\r
3545 {\r
3546   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
3547   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
3548   char str[2] = { NULLCHAR, NULLCHAR };\r
3549   int oldMode, oldAlign, x, y, start, i;\r
3550   HFONT oldFont;\r
3551   HBRUSH oldBrush;\r
3552 \r
3553   if (!appData.showCoords)\r
3554     return;\r
3555 \r
3556   start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;\r
3557 \r
3558   oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));\r
3559   oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));\r
3560   oldAlign = GetTextAlign(hdc);\r
3561   oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);\r
3562 \r
3563   y = boardRect.top + lineGap;\r
3564   x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);\r
3565 \r
3566   SetTextAlign(hdc, TA_LEFT|TA_TOP);\r
3567   for (i = 0; i < BOARD_HEIGHT; i++) {\r
3568     str[0] = files[start + i];\r
3569     ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);\r
3570     y += squareSize + lineGap;\r
3571   }\r
3572 \r
3573   start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;\r
3574 \r
3575   SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);\r
3576   for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {\r
3577     str[0] = ranks[start + i];\r
3578     ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);\r
3579     x += squareSize + lineGap;\r
3580   }    \r
3581 \r
3582   SelectObject(hdc, oldBrush);\r
3583   SetBkMode(hdc, oldMode);\r
3584   SetTextAlign(hdc, oldAlign);\r
3585   SelectObject(hdc, oldFont);\r
3586 }\r
3587 \r
3588 VOID\r
3589 DrawGridOnDC(HDC hdc)\r
3590 {\r
3591   HPEN oldPen;\r
3592  \r
3593   if (lineGap != 0) {\r
3594     oldPen = SelectObject(hdc, gridPen);\r
3595     PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);\r
3596     SelectObject(hdc, oldPen);\r
3597   }\r
3598 }\r
3599 \r
3600 #define HIGHLIGHT_PEN 0\r
3601 #define PREMOVE_PEN   1\r
3602 \r
3603 VOID\r
3604 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)\r
3605 {\r
3606   int x1, y1;\r
3607   HPEN oldPen, hPen;\r
3608   if (lineGap == 0) return;\r
3609   if (flipView) {\r
3610     x1 = boardRect.left +\r
3611       lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);\r
3612     y1 = boardRect.top +\r
3613       lineGap/2 + y * (squareSize + lineGap);\r
3614   } else {\r
3615     x1 = boardRect.left +\r
3616       lineGap/2 + x * (squareSize + lineGap);\r
3617     y1 = boardRect.top +\r
3618       lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);\r
3619   }\r
3620   hPen = pen ? premovePen : highlightPen;\r
3621   oldPen = SelectObject(hdc, on ? hPen : gridPen);\r
3622   MoveToEx(hdc, x1, y1, NULL);\r
3623   LineTo(hdc, x1 + squareSize + lineGap, y1);\r
3624   LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);\r
3625   LineTo(hdc, x1, y1 + squareSize + lineGap);\r
3626   LineTo(hdc, x1, y1);\r
3627   SelectObject(hdc, oldPen);\r
3628 }\r
3629 \r
3630 VOID\r
3631 DrawHighlightsOnDC(HDC hdc)\r
3632 {\r
3633   int i;\r
3634   for (i=0; i<2; i++) {\r
3635     if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) \r
3636       DrawHighlightOnDC(hdc, TRUE,\r
3637                         highlightInfo.sq[i].x, highlightInfo.sq[i].y,\r
3638                         HIGHLIGHT_PEN);\r
3639   }\r
3640   for (i=0; i<2; i++) {\r
3641     if (premoveHighlightInfo.sq[i].x >= 0 && \r
3642         premoveHighlightInfo.sq[i].y >= 0) {\r
3643         DrawHighlightOnDC(hdc, TRUE,\r
3644                           premoveHighlightInfo.sq[i].x, \r
3645                           premoveHighlightInfo.sq[i].y,\r
3646                           PREMOVE_PEN);\r
3647     }\r
3648   }\r
3649 }\r
3650 \r
3651 /* Note: sqcolor is used only in monoMode */\r
3652 /* Note that this code is largely duplicated in woptions.c,\r
3653    function DrawSampleSquare, so that needs to be updated too */\r
3654 VOID\r
3655 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)\r
3656 {\r
3657   HBITMAP oldBitmap;\r
3658   HBRUSH oldBrush;\r
3659   int tmpSize;\r
3660 \r
3661   if (appData.blindfold) return;\r
3662 \r
3663   /* [AS] Use font-based pieces if needed */\r
3664   if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {\r
3665     /* Create piece bitmaps, or do nothing if piece set is up to date */\r
3666     CreatePiecesFromFont();\r
3667 \r
3668     if( fontBitmapSquareSize == squareSize ) {\r
3669         int index = TranslatePieceToFontPiece(piece);\r
3670 \r
3671         SelectObject( tmphdc, hPieceMask[ index ] );\r
3672 \r
3673         BitBlt( hdc,\r
3674             x, y,\r