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