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