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