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