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