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 $
5 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
\r
6 * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
\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
11 * The following terms apply to Digital Equipment Corporation's copyright
\r
12 * interest in XBoard:
\r
13 * ------------------------------------------------------------------------
\r
14 * All Rights Reserved
\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
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
31 * ------------------------------------------------------------------------
\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
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
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
54 #include <windows.h>
\r
55 #include <winuser.h>
\r
56 #include <winsock.h>
\r
62 #include <sys/stat.h>
\r
65 #include <commdlg.h>
\r
67 #include <richedit.h>
\r
68 #include <mmsystem.h>
\r
76 #include "winboard.h"
\r
77 #include "frontend.h"
\r
78 #include "backend.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
89 void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
92 void mysrandom(unsigned int seed);
96 POINT pos; /* window coordinates of current pos */
\r
97 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
98 POINT from; /* board coordinates of the piece's orig pos */
\r
99 POINT to; /* board coordinates of the piece's new pos */
\r
102 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
105 POINT start; /* window coordinates of start pos */
\r
106 POINT pos; /* window coordinates of current pos */
\r
107 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
108 POINT from; /* board coordinates of the piece's orig pos */
\r
111 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
114 POINT sq[2]; /* board coordinates of from, to squares */
\r
117 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
118 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
120 /* Window class names */
\r
121 char szAppName[] = "WinBoard";
\r
122 char szConsoleName[] = "WBConsole";
\r
124 /* Title bar text */
\r
125 char szTitle[] = "WinBoard";
\r
126 char szConsoleTitle[] = "ICS Interaction";
\r
129 char *settingsFileName;
\r
130 BOOLEAN saveSettingsOnExit;
\r
131 char installDir[MSG_SIZ];
\r
133 BoardSize boardSize;
\r
134 BOOLEAN chessProgram;
\r
135 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
136 static int squareSize, lineGap;
\r
137 static int winWidth, winHeight;
\r
138 static RECT messageRect, whiteRect, blackRect;
\r
139 static char messageText[MESSAGE_TEXT_MAX];
\r
140 static int clockTimerEvent = 0;
\r
141 static int loadGameTimerEvent = 0;
\r
142 static int analysisTimerEvent = 0;
\r
143 static DelayedEventCallback delayedTimerCallback;
\r
144 static int delayedTimerEvent = 0;
\r
145 static int buttonCount = 2;
\r
146 char *icsTextMenuString;
\r
148 char *firstChessProgramNames;
\r
149 char *secondChessProgramNames;
\r
151 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
153 #define PALETTESIZE 256
\r
155 HINSTANCE hInst; /* current instance */
\r
156 HWND hwndMain = NULL; /* root window*/
\r
157 HWND hwndConsole = NULL;
\r
158 BOOLEAN alwaysOnTop = FALSE;
\r
160 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
161 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
163 ColorClass currentColorClass;
\r
165 HWND hCommPort = NULL; /* currently open comm port */
\r
166 static HWND hwndPause; /* pause button */
\r
167 static HBITMAP pieceBitmap[3][(int) WhiteKing + 1];
\r
168 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
169 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
170 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
171 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
172 static HPEN gridPen = NULL;
\r
173 static HPEN highlightPen = NULL;
\r
174 static HPEN premovePen = NULL;
\r
175 static NPLOGPALETTE pLogPal;
\r
176 static BOOL paletteChanged = FALSE;
\r
177 static HICON iconWhite, iconBlack, iconCurrent;
\r
178 static int doingSizing = FALSE;
\r
179 static int lastSizing = 0;
\r
180 static int prevStderrPort;
\r
182 /* [AS] Support for background textures */
183 #define BACK_TEXTURE_MODE_DISABLED 0
184 #define BACK_TEXTURE_MODE_PLAIN 1
185 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
187 static HBITMAP liteBackTexture = NULL;
188 static HBITMAP darkBackTexture = NULL;
189 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
190 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
191 static int backTextureSquareSize = 0;
192 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
194 #if __GNUC__ && !defined(_winmajor)
\r
195 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
197 #define oldDialog (_winmajor < 4)
\r
200 char *defaultTextAttribs[] =
\r
202 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
203 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
213 int cliWidth, cliHeight;
\r
216 SizeInfo sizeInfo[] =
\r
218 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
219 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
220 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
221 { "petite", 33, 1, 1, 1, 0, 0 },
\r
222 { "slim", 37, 2, 1, 0, 0, 0 },
\r
223 { "small", 40, 2, 1, 0, 0, 0 },
\r
224 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
225 { "middling", 49, 2, 0, 0, 0, 0 },
\r
226 { "average", 54, 2, 0, 0, 0, 0 },
\r
227 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
228 { "medium", 64, 3, 0, 0, 0, 0 },
\r
229 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
230 { "large", 80, 3, 0, 0, 0, 0 },
\r
231 { "big", 87, 3, 0, 0, 0, 0 },
\r
232 { "huge", 95, 3, 0, 0, 0, 0 },
\r
233 { "giant", 108, 3, 0, 0, 0, 0 },
\r
234 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
235 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
236 { NULL, 0, 0, 0, 0, 0, 0 }
\r
239 #define MF(x) {x, {0, }, {0, }, 0}
\r
240 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
242 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY),
\r
243 MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY),
\r
244 MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY) },
\r
245 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY),
\r
246 MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY),
\r
247 MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY) },
\r
248 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY),
\r
249 MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY),
\r
250 MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY) },
\r
251 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE),
\r
252 MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE),
\r
253 MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE) },
\r
254 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM),
\r
255 MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM),
\r
256 MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM) },
\r
257 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL),
\r
258 MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL),
\r
259 MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL) },
\r
260 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE),
\r
261 MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE),
\r
262 MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE) },
\r
263 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING),
\r
264 MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING),
\r
265 MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING) },
\r
266 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE),
\r
267 MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE),
\r
268 MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE) },
\r
269 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE),
\r
270 MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE),
\r
271 MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE) },
\r
272 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM),
\r
273 MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM),
\r
274 MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM) },
\r
275 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY),
\r
276 MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY),
\r
277 MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY) },
\r
278 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE),
\r
279 MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE),
\r
280 MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE) },
\r
281 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG),
\r
282 MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG),
\r
283 MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG) },
\r
284 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE),
\r
285 MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE),
\r
286 MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE) },
\r
287 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT),
\r
288 MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT),
\r
289 MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT) },
\r
290 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL),
\r
291 MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL),
\r
292 MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL) },
\r
293 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC),
\r
294 MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC),
\r
295 MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC) },
\r
298 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
307 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
308 #define N_BUTTONS 5
\r
310 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
312 {"<<", IDM_ToStart, NULL, NULL},
\r
313 {"<", IDM_Backward, NULL, NULL},
\r
314 {"P", IDM_Pause, NULL, NULL},
\r
315 {">", IDM_Forward, NULL, NULL},
\r
316 {">>", IDM_ToEnd, NULL, NULL},
\r
319 int tinyLayout = 0, smallLayout = 0;
\r
320 #define MENU_BAR_ITEMS 6
\r
321 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
322 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
323 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
327 MySound sounds[(int)NSoundClasses];
\r
328 MyTextAttribs textAttribs[(int)NColorClasses];
\r
330 MyColorizeAttribs colorizeAttribs[] = {
\r
331 { (COLORREF)0, 0, "Shout Text" },
\r
332 { (COLORREF)0, 0, "SShout/CShout" },
\r
333 { (COLORREF)0, 0, "Channel 1 Text" },
\r
334 { (COLORREF)0, 0, "Channel Text" },
\r
335 { (COLORREF)0, 0, "Kibitz Text" },
\r
336 { (COLORREF)0, 0, "Tell Text" },
\r
337 { (COLORREF)0, 0, "Challenge Text" },
\r
338 { (COLORREF)0, 0, "Request Text" },
\r
339 { (COLORREF)0, 0, "Seek Text" },
\r
340 { (COLORREF)0, 0, "Normal Text" },
\r
341 { (COLORREF)0, 0, "None" }
\r
346 static char *commentTitle;
\r
347 static char *commentText;
\r
348 static int commentIndex;
\r
349 static Boolean editComment = FALSE;
\r
350 HWND commentDialog = NULL;
\r
351 BOOLEAN commentDialogUp = FALSE;
\r
352 static int commentX, commentY, commentH, commentW;
\r
354 static char *analysisTitle;
\r
355 static char *analysisText;
\r
356 HWND analysisDialog = NULL;
\r
357 BOOLEAN analysisDialogUp = FALSE;
\r
358 static int analysisX, analysisY, analysisH, analysisW;
\r
360 char errorTitle[MSG_SIZ];
\r
361 char errorMessage[2*MSG_SIZ];
\r
362 HWND errorDialog = NULL;
\r
363 BOOLEAN moveErrorMessageUp = FALSE;
\r
364 BOOLEAN consoleEcho = TRUE;
\r
365 CHARFORMAT consoleCF;
\r
366 COLORREF consoleBackgroundColor;
\r
368 char *programVersion;
\r
374 typedef int CPKind;
\r
383 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
386 #define INPUT_SOURCE_BUF_SIZE 4096
\r
388 typedef struct _InputSource {
\r
395 char buf[INPUT_SOURCE_BUF_SIZE];
\r
399 InputCallback func;
\r
400 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
404 InputSource *consoleInputSource;
\r
409 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
410 VOID ConsoleCreate();
\r
412 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
413 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
414 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
415 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
417 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
418 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
419 void ParseIcsTextMenu(char *icsTextMenuString);
\r
420 VOID PopUpMoveDialog(char firstchar);
\r
421 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
425 int GameListOptions();
427 HWND moveHistoryDialog = NULL;
428 BOOLEAN moveHistoryDialogUp = FALSE;
430 WindowPlacement wpMoveHistory;
432 HWND evalGraphDialog = NULL;
433 BOOLEAN evalGraphDialogUp = FALSE;
435 WindowPlacement wpEvalGraph;
437 HWND engineOutputDialog = NULL;
438 BOOLEAN engineOutputDialogUp = FALSE;
440 WindowPlacement wpEngineOutput;
442 VOID MoveHistoryPopUp();
443 VOID MoveHistoryPopDown();
444 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
445 BOOL MoveHistoryIsUp();
447 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
448 VOID EvalGraphPopUp();
449 VOID EvalGraphPopDown();
450 BOOL EvalGraphIsUp();
452 VOID EngineOutputPopUp();
453 VOID EngineOutputPopDown();
454 BOOL EngineOutputIsUp();
455 VOID EngineOutputUpdate( int which, int depth, unsigned long nodes, int score, int time, char * pv, char * hint );
458 * Setting "frozen" should disable all user input other than deleting
\r
459 * the window. We do this while engines are initializing themselves.
\r
461 static int frozen = 0;
\r
462 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
468 if (frozen) return;
\r
470 hmenu = GetMenu(hwndMain);
\r
471 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
472 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
474 DrawMenuBar(hwndMain);
\r
477 /* Undo a FreezeUI */
\r
483 if (!frozen) return;
\r
485 hmenu = GetMenu(hwndMain);
\r
486 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
487 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
489 DrawMenuBar(hwndMain);
\r
492 /*---------------------------------------------------------------------------*\
\r
496 \*---------------------------------------------------------------------------*/
\r
499 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
500 LPSTR lpCmdLine, int nCmdShow)
\r
503 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
507 LoadLibrary("RICHED32.DLL");
\r
508 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
510 if (!InitApplication(hInstance)) {
\r
513 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
517 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
518 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
519 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
521 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
523 while (GetMessage(&msg, /* message structure */
\r
524 NULL, /* handle of window receiving the message */
\r
525 0, /* lowest message to examine */
\r
526 0)) /* highest message to examine */
\r
528 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
529 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
530 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
531 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
532 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
533 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
534 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
535 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
536 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
537 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
538 TranslateMessage(&msg); /* Translates virtual key codes */
\r
539 DispatchMessage(&msg); /* Dispatches message to window */
\r
544 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
547 /*---------------------------------------------------------------------------*\
\r
549 * Initialization functions
\r
551 \*---------------------------------------------------------------------------*/
\r
554 InitApplication(HINSTANCE hInstance)
\r
558 /* Fill in window class structure with parameters that describe the */
\r
561 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
562 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
563 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
564 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
565 wc.hInstance = hInstance; /* Owner of this class */
\r
566 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
567 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
568 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
569 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
570 wc.lpszClassName = szAppName; /* Name to register as */
\r
572 /* Register the window class and return success/failure code. */
\r
573 if (!RegisterClass(&wc)) return FALSE;
\r
575 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
576 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
578 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
579 wc.hInstance = hInstance;
\r
580 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
581 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
582 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
583 wc.lpszMenuName = NULL;
\r
584 wc.lpszClassName = szConsoleName;
\r
586 if (!RegisterClass(&wc)) return FALSE;
\r
591 /* Set by InitInstance, used by EnsureOnScreen */
\r
592 int screenHeight, screenWidth;
\r
595 EnsureOnScreen(int *x, int *y)
\r
597 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
598 if (*x > screenWidth - 32) *x = 0;
\r
599 if (*y > screenHeight - 32) *y = 0;
\r
603 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
605 HWND hwnd; /* Main window handle. */
\r
607 WINDOWPLACEMENT wp;
\r
610 hInst = hInstance; /* Store instance handle in our global variable */
\r
612 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
613 *filepart = NULLCHAR;
\r
615 GetCurrentDirectory(MSG_SIZ, installDir);
\r
617 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
618 if (appData.debugMode) {
\r
619 debugFP = fopen(appData.nameOfDebugFile, "w");
620 setbuf(debugFP, NULL);
\r
625 InitEngineUCI( installDir, &first );
626 InitEngineUCI( installDir, &second );
628 /* Create a main window for this application instance. */
\r
629 hwnd = CreateWindow(szAppName, szTitle,
\r
630 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
631 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
632 NULL, NULL, hInstance, NULL);
\r
635 /* If window could not be created, return "failure" */
\r
640 iconWhite = LoadIcon(hInstance, "icon_white");
\r
641 iconBlack = LoadIcon(hInstance, "icon_black");
\r
642 iconCurrent = iconWhite;
\r
643 InitDrawingColors();
\r
644 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
645 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
646 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
647 /* Compute window size for each board size, and use the largest
\r
648 size that fits on this screen as the default. */
\r
649 InitDrawingSizes((BoardSize)ibs, 0);
\r
650 if (boardSize == (BoardSize)-1 &&
\r
651 winHeight <= screenHeight && winWidth <= screenWidth) {
\r
652 boardSize = (BoardSize)ibs;
\r
655 InitDrawingSizes(boardSize, 0);
\r
657 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
659 /* [AS] Load textures if specified */
660 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
662 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
663 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
664 liteBackTextureMode = appData.liteBackTextureMode;
666 if (liteBackTexture == NULL && appData.debugMode) {
667 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
671 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
672 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
673 darkBackTextureMode = appData.darkBackTextureMode;
675 if (darkBackTexture == NULL && appData.debugMode) {
676 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
680 mysrandom( (unsigned) time(NULL) );
682 /* Make a console window if needed */
\r
683 if (appData.icsActive) {
\r
687 /* [AS] Restore layout */
688 if( wpMoveHistory.visible ) {
692 if( wpEvalGraph.visible ) {
696 if( wpEngineOutput.visible ) {
702 /* Make the window visible; update its client area; and return "success" */
\r
703 EnsureOnScreen(&boardX, &boardY);
\r
704 wp.length = sizeof(WINDOWPLACEMENT);
\r
706 wp.showCmd = nCmdShow;
\r
707 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
708 wp.rcNormalPosition.left = boardX;
\r
709 wp.rcNormalPosition.right = boardX + winWidth;
\r
710 wp.rcNormalPosition.top = boardY;
\r
711 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
712 SetWindowPlacement(hwndMain, &wp);
\r
714 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
715 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
717 /* [AS] Disable the FRC stuff if not playing the proper variant */
718 if( gameInfo.variant != VariantFischeRandom ) {
719 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
724 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
725 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
727 ShowWindow(hwndConsole, nCmdShow);
\r
729 UpdateWindow(hwnd);
\r
737 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
738 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
739 ArgSettingsFilename
\r
747 String *pString; // ArgString
\r
748 int *pInt; // ArgInt
\r
749 float *pFloat; // ArgFloat
\r
750 Boolean *pBoolean; // ArgBoolean
\r
751 COLORREF *pColor; // ArgColor
\r
752 ColorClass cc; // ArgAttribs
\r
753 String *pFilename; // ArgFilename
\r
754 BoardSize *pBoardSize; // ArgBoardSize
\r
755 int whichFont; // ArgFont
\r
756 DCB *pDCB; // ArgCommSettings
\r
757 String *pFilename; // ArgSettingsFilename
\r
765 ArgDescriptor argDescriptors[] = {
\r
766 /* positional arguments */
\r
767 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
768 { "", ArgNone, NULL },
\r
769 /* keyword arguments */
\r
770 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
771 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
772 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
773 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
774 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
775 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
776 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
777 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
778 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
779 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
780 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
781 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
782 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
783 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
784 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
785 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
786 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
787 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
789 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
791 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
793 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
794 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
796 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
797 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
798 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
799 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
800 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
801 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
802 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
803 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
804 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
805 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
806 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
807 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
808 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
809 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
810 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
811 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
812 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
813 /*!!bitmapDirectory?*/
\r
814 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
815 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
816 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
817 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
818 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
819 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
820 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
821 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
822 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
823 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
824 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
825 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
826 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
827 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
828 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
829 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
830 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
831 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
832 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
833 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
834 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
835 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
836 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
837 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
838 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
839 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
840 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
841 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
842 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
843 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
844 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
845 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
846 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
847 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
848 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
849 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
850 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
851 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
852 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
853 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
854 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
855 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
856 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
857 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
858 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
859 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
860 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
861 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
862 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
863 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
864 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
865 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
866 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
867 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
868 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
869 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
870 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
871 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
872 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
873 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
874 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
875 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
876 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
877 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
878 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
879 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
880 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
881 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
882 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
883 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
884 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
885 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
886 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
887 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
888 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
889 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
890 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
891 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
892 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
893 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
894 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
895 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
896 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
897 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
898 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
899 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
900 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
901 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
902 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
903 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
904 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
905 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
906 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
907 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
908 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
909 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
910 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
911 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
912 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
913 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
914 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
915 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
916 TRUE }, /* must come after all fonts */
\r
917 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
918 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
919 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
920 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
921 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
922 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
923 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
924 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
925 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
926 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
927 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
928 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
929 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
930 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
931 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
932 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
933 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
934 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
935 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
936 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
937 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
938 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
939 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
940 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
941 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
942 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
943 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
944 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
945 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
946 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
947 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
949 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
950 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
952 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
953 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
954 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
955 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
956 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
957 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
958 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
959 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
960 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
961 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
962 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
963 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
964 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
965 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
966 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
967 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
968 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
969 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
970 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
971 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
972 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
973 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
974 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
975 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
976 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
977 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
978 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
979 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
980 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
981 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
982 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
983 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
984 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
985 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
986 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
987 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
988 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
989 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
990 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
991 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
992 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
993 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
994 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
995 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
996 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
997 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
998 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
999 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1000 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1001 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1002 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1003 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1004 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1005 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1006 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1007 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1008 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1009 { "highlightLastMove", ArgBoolean,
\r
1010 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1011 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1012 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1013 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1014 { "highlightDragging", ArgBoolean,
\r
1015 (LPVOID) &appData.highlightDragging, TRUE },
\r
1016 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1017 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1018 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1019 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1020 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1021 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1022 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1023 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1024 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1025 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1026 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1027 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1028 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1029 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1030 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1031 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1032 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1033 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1034 { "soundShout", ArgFilename,
\r
1035 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1036 { "soundSShout", ArgFilename,
\r
1037 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1038 { "soundChannel1", ArgFilename,
\r
1039 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1040 { "soundChannel", ArgFilename,
\r
1041 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1042 { "soundKibitz", ArgFilename,
\r
1043 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1044 { "soundTell", ArgFilename,
\r
1045 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1046 { "soundChallenge", ArgFilename,
\r
1047 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1048 { "soundRequest", ArgFilename,
\r
1049 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1050 { "soundSeek", ArgFilename,
\r
1051 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1052 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1053 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1054 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1055 { "soundIcsLoss", ArgFilename,
\r
1056 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1057 { "soundIcsDraw", ArgFilename,
\r
1058 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1059 { "soundIcsUnfinished", ArgFilename,
\r
1060 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1061 { "soundIcsAlarm", ArgFilename,
\r
1062 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1063 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1064 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1065 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1066 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1067 { "reuseChessPrograms", ArgBoolean,
\r
1068 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1069 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1070 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1071 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1072 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1073 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1074 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1075 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1076 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1077 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1078 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1079 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1080 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1081 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1082 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1083 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1084 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1085 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1086 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1087 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1088 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1089 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1090 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1091 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1092 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1093 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1094 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1095 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1096 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1097 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1098 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1099 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1100 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1101 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1102 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1103 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1104 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1105 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1107 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1109 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1110 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1111 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1112 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
1113 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
1114 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1115 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1116 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1117 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1118 /* [AS] New features */
1119 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
1120 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
1121 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
1122 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
1123 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
1124 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
1125 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
1126 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
1127 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
1128 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
1129 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
1130 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
1131 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
1132 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
1133 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
1134 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
1135 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
1136 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
1137 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
1138 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
1139 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
1140 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
1141 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
1142 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
1143 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
1144 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
1145 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
1146 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
1147 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
1148 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
1149 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
1150 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
1151 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
1152 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
1153 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
1154 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
1155 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
1156 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
1157 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
1158 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
1159 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
1160 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
1161 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
1162 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
1163 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
1164 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
1165 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
1166 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
1168 /* [AS] Layout stuff */
1169 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
1170 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
1171 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
1172 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
1173 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
1175 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
1176 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
1177 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
1178 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
1179 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
1181 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
1182 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
1183 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
1184 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
1185 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
1188 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1189 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1190 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1191 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1192 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1193 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1194 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1195 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1196 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1197 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1198 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1199 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1200 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1202 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1203 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1204 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1205 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1206 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1207 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1208 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1210 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1211 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1212 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1213 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1214 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1215 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1216 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1217 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1218 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1219 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1220 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1221 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1222 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1223 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1224 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1225 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1226 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1227 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1229 { NULL, ArgNone, NULL, FALSE }
\r
1233 /* Kludge for indirection files on command line */
\r
1234 char* lastIndirectionFilename;
\r
1235 ArgDescriptor argDescriptorIndirection =
\r
1236 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1240 ExitArgError(char *msg, char *badArg)
\r
1242 char buf[MSG_SIZ];
\r
1244 sprintf(buf, "%s %s", msg, badArg);
\r
1245 DisplayFatalError(buf, 0, 2);
\r
1249 /* Command line font name parser. NULL name means do nothing.
\r
1250 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1251 For backward compatibility, syntax without the colon is also
\r
1252 accepted, but font names with digits in them won't work in that case.
\r
1255 ParseFontName(char *name, MyFontParams *mfp)
\r
1258 if (name == NULL) return;
\r
1260 q = strchr(p, ':');
\r
1262 if (q - p >= sizeof(mfp->faceName))
\r
1263 ExitArgError("Font name too long:", name);
\r
1264 memcpy(mfp->faceName, p, q - p);
\r
1265 mfp->faceName[q - p] = NULLCHAR;
\r
1268 q = mfp->faceName;
\r
1269 while (*p && !isdigit(*p)) {
\r
1271 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1272 ExitArgError("Font name too long:", name);
\r
1274 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1277 if (!*p) ExitArgError("Font point size missing:", name);
\r
1278 mfp->pointSize = (float) atof(p);
\r
1279 mfp->bold = (strchr(p, 'b') != NULL);
\r
1280 mfp->italic = (strchr(p, 'i') != NULL);
\r
1281 mfp->underline = (strchr(p, 'u') != NULL);
\r
1282 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1285 /* Color name parser.
\r
1286 X version accepts X color names, but this one
\r
1287 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1289 ParseColorName(char *name)
\r
1291 int red, green, blue, count;
\r
1292 char buf[MSG_SIZ];
\r
1294 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1296 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1297 &red, &green, &blue);
\r
1300 sprintf(buf, "Can't parse color name %s", name);
\r
1301 DisplayError(buf, 0);
\r
1302 return RGB(0, 0, 0);
\r
1304 return PALETTERGB(red, green, blue);
\r
1308 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1310 char *e = argValue;
\r
1314 if (*e == 'b') eff |= CFE_BOLD;
\r
1315 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1316 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1317 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1318 else if (*e == '#' || isdigit(*e)) break;
\r
1322 *color = ParseColorName(e);
\r
1327 ParseBoardSize(char *name)
\r
1329 BoardSize bs = SizeTiny;
\r
1330 while (sizeInfo[bs].name != NULL) {
\r
1331 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1334 ExitArgError("Unrecognized board size value", name);
\r
1335 return bs; /* not reached */
\r
1340 StringGet(void *getClosure)
\r
1342 char **p = (char **) getClosure;
\r
1347 FileGet(void *getClosure)
\r
1350 FILE* f = (FILE*) getClosure;
\r
1359 /* Parse settings file named "name". If file found, return the
\r
1360 full name in fullname and return TRUE; else return FALSE */
\r
1362 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1367 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1368 f = fopen(fullname, "r");
\r
1370 ParseArgs(FileGet, f);
\r
1379 ParseArgs(GetFunc get, void *cl)
\r
1381 char argName[ARG_MAX];
\r
1382 char argValue[ARG_MAX];
\r
1383 ArgDescriptor *ad;
\r
1392 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1393 if (ch == NULLCHAR) break;
\r
1395 /* Comment to end of line */
\r
1397 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1399 } else if (ch == '/' || ch == '-') {
\r
1402 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1403 ch != '\n' && ch != '\t') {
\r
1409 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1410 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1412 if (ad->argName == NULL)
\r
1413 ExitArgError("Unrecognized argument", argName);
\r
1415 } else if (ch == '@') {
\r
1416 /* Indirection file */
\r
1417 ad = &argDescriptorIndirection;
\r
1420 /* Positional argument */
\r
1421 ad = &argDescriptors[posarg++];
\r
1422 strcpy(argName, ad->argName);
\r
1425 if (ad->argType == ArgTrue) {
\r
1426 *(Boolean *) ad->argLoc = TRUE;
\r
1429 if (ad->argType == ArgFalse) {
\r
1430 *(Boolean *) ad->argLoc = FALSE;
\r
1434 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1435 if (ch == NULLCHAR || ch == '\n') {
\r
1436 ExitArgError("No value provided for argument", argName);
\r
1440 // Quoting with { }. No characters have to (or can) be escaped.
\r
1441 // Thus the string cannot contain a '}' character.
\r
1461 } else if (ch == '\'' || ch == '"') {
\r
1462 // Quoting with ' ' or " ", with \ as escape character.
\r
1463 // Inconvenient for long strings that may contain Windows filenames.
\r
1480 if (ch == start) {
\r
1489 if (ad->argType == ArgFilename
\r
1490 || ad->argType == ArgSettingsFilename) {
\r
1496 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1520 for (i = 0; i < 3; i++) {
\r
1521 if (ch >= '0' && ch <= '7') {
\r
1522 octval = octval*8 + (ch - '0');
\r
1529 *q++ = (char) octval;
\r
1540 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1547 switch (ad->argType) {
\r
1549 *(int *) ad->argLoc = atoi(argValue);
\r
1553 *(float *) ad->argLoc = (float) atof(argValue);
\r
1558 *(char **) ad->argLoc = strdup(argValue);
\r
1561 case ArgSettingsFilename:
\r
1563 char fullname[MSG_SIZ];
\r
1564 if (ParseSettingsFile(argValue, fullname)) {
\r
1565 if (ad->argLoc != NULL) {
\r
1566 *(char **) ad->argLoc = strdup(fullname);
\r
1569 if (ad->argLoc != NULL) {
\r
1571 ExitArgError("Failed to open indirection file", argValue);
\r
1578 switch (argValue[0]) {
\r
1581 *(Boolean *) ad->argLoc = TRUE;
\r
1585 *(Boolean *) ad->argLoc = FALSE;
\r
1588 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1594 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1597 case ArgAttribs: {
\r
1598 ColorClass cc = (ColorClass)ad->argLoc;
\r
1599 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1603 case ArgBoardSize:
\r
1604 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1608 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1611 case ArgCommSettings:
\r
1612 ParseCommSettings(argValue, &dcb);
\r
1616 ExitArgError("Unrecognized argument", argValue);
\r
1623 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1625 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1626 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1629 lf->lfEscapement = 0;
\r
1630 lf->lfOrientation = 0;
\r
1631 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1632 lf->lfItalic = mfp->italic;
\r
1633 lf->lfUnderline = mfp->underline;
\r
1634 lf->lfStrikeOut = mfp->strikeout;
\r
1635 lf->lfCharSet = DEFAULT_CHARSET;
\r
1636 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1637 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1638 lf->lfQuality = DEFAULT_QUALITY;
\r
1639 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1640 strcpy(lf->lfFaceName, mfp->faceName);
\r
1644 CreateFontInMF(MyFont *mf)
\r
1646 LFfromMFP(&mf->lf, &mf->mfp);
\r
1647 if (mf->hf) DeleteObject(mf->hf);
\r
1648 mf->hf = CreateFontIndirect(&mf->lf);
\r
1652 SetDefaultTextAttribs()
\r
1655 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1656 ParseAttribs(&textAttribs[cc].color,
\r
1657 &textAttribs[cc].effects,
\r
1658 defaultTextAttribs[cc]);
\r
1663 SetDefaultSounds()
\r
1667 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1668 textAttribs[cc].sound.name = strdup("");
\r
1669 textAttribs[cc].sound.data = NULL;
\r
1671 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1672 sounds[sc].name = strdup("");
\r
1673 sounds[sc].data = NULL;
\r
1675 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1683 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1684 MyLoadSound(&textAttribs[cc].sound);
\r
1686 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1687 MyLoadSound(&sounds[sc]);
\r
1692 InitAppData(LPSTR lpCmdLine)
\r
1695 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1698 programName = szAppName;
\r
1700 /* Initialize to defaults */
\r
1701 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1702 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1703 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1704 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1705 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1706 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1707 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1708 SetDefaultTextAttribs();
\r
1709 SetDefaultSounds();
\r
1710 appData.movesPerSession = MOVES_PER_SESSION;
\r
1711 appData.initString = INIT_STRING;
\r
1712 appData.secondInitString = INIT_STRING;
\r
1713 appData.firstComputerString = COMPUTER_STRING;
\r
1714 appData.secondComputerString = COMPUTER_STRING;
\r
1715 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1716 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1717 appData.firstPlaysBlack = FALSE;
\r
1718 appData.noChessProgram = FALSE;
\r
1719 chessProgram = FALSE;
\r
1720 appData.firstHost = FIRST_HOST;
\r
1721 appData.secondHost = SECOND_HOST;
\r
1722 appData.firstDirectory = FIRST_DIRECTORY;
\r
1723 appData.secondDirectory = SECOND_DIRECTORY;
\r
1724 appData.bitmapDirectory = "";
\r
1725 appData.remoteShell = REMOTE_SHELL;
\r
1726 appData.remoteUser = "";
\r
1727 appData.timeDelay = TIME_DELAY;
\r
1728 appData.timeControl = TIME_CONTROL;
\r
1729 appData.timeIncrement = TIME_INCREMENT;
\r
1730 appData.icsActive = FALSE;
\r
1731 appData.icsHost = "";
\r
1732 appData.icsPort = ICS_PORT;
\r
1733 appData.icsCommPort = ICS_COMM_PORT;
\r
1734 appData.icsLogon = ICS_LOGON;
\r
1735 appData.icsHelper = "";
\r
1736 appData.useTelnet = FALSE;
\r
1737 appData.telnetProgram = TELNET_PROGRAM;
\r
1738 appData.gateway = "";
\r
1739 appData.loadGameFile = "";
\r
1740 appData.loadGameIndex = 0;
\r
1741 appData.saveGameFile = "";
\r
1742 appData.autoSaveGames = FALSE;
\r
1743 appData.loadPositionFile = "";
\r
1744 appData.loadPositionIndex = 1;
\r
1745 appData.savePositionFile = "";
\r
1746 appData.matchMode = FALSE;
\r
1747 appData.matchGames = 0;
\r
1748 appData.monoMode = FALSE;
\r
1749 appData.debugMode = FALSE;
\r
1750 appData.clockMode = TRUE;
\r
1751 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1752 appData.Iconic = FALSE; /*unused*/
\r
1753 appData.searchTime = "";
\r
1754 appData.searchDepth = 0;
\r
1755 appData.showCoords = FALSE;
\r
1756 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1757 appData.autoCallFlag = FALSE;
\r
1758 appData.flipView = FALSE;
\r
1759 appData.autoFlipView = TRUE;
\r
1760 appData.cmailGameName = "";
\r
1761 appData.alwaysPromoteToQueen = FALSE;
\r
1762 appData.oldSaveStyle = FALSE;
\r
1763 appData.quietPlay = FALSE;
\r
1764 appData.showThinking = FALSE;
\r
1765 appData.ponderNextMove = TRUE;
\r
1766 appData.periodicUpdates = TRUE;
\r
1767 appData.popupExitMessage = TRUE;
\r
1768 appData.popupMoveErrors = FALSE;
\r
1769 appData.autoObserve = FALSE;
\r
1770 appData.autoComment = FALSE;
\r
1771 appData.animate = TRUE;
\r
1772 appData.animSpeed = 10;
\r
1773 appData.animateDragging = TRUE;
\r
1774 appData.highlightLastMove = TRUE;
\r
1775 appData.getMoveList = TRUE;
\r
1776 appData.testLegality = TRUE;
\r
1777 appData.premove = TRUE;
\r
1778 appData.premoveWhite = FALSE;
\r
1779 appData.premoveWhiteText = "";
\r
1780 appData.premoveBlack = FALSE;
\r
1781 appData.premoveBlackText = "";
\r
1782 appData.icsAlarm = TRUE;
\r
1783 appData.icsAlarmTime = 5000;
\r
1784 appData.autoRaiseBoard = TRUE;
\r
1785 appData.localLineEditing = TRUE;
\r
1786 appData.colorize = TRUE;
\r
1787 appData.reuseFirst = TRUE;
\r
1788 appData.reuseSecond = TRUE;
\r
1789 appData.blindfold = FALSE;
\r
1790 dcb.DCBlength = sizeof(DCB);
\r
1791 dcb.BaudRate = 9600;
\r
1792 dcb.fBinary = TRUE;
\r
1793 dcb.fParity = FALSE;
\r
1794 dcb.fOutxCtsFlow = FALSE;
\r
1795 dcb.fOutxDsrFlow = FALSE;
\r
1796 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1797 dcb.fDsrSensitivity = FALSE;
\r
1798 dcb.fTXContinueOnXoff = TRUE;
\r
1799 dcb.fOutX = FALSE;
\r
1801 dcb.fNull = FALSE;
\r
1802 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1803 dcb.fAbortOnError = FALSE;
\r
1804 dcb.wReserved = 0;
\r
1806 dcb.Parity = SPACEPARITY;
\r
1807 dcb.StopBits = ONESTOPBIT;
\r
1808 settingsFileName = SETTINGS_FILE;
\r
1809 saveSettingsOnExit = TRUE;
\r
1810 boardX = CW_USEDEFAULT;
\r
1811 boardY = CW_USEDEFAULT;
\r
1812 consoleX = CW_USEDEFAULT;
\r
1813 consoleY = CW_USEDEFAULT;
\r
1814 consoleW = CW_USEDEFAULT;
\r
1815 consoleH = CW_USEDEFAULT;
\r
1816 analysisX = CW_USEDEFAULT;
\r
1817 analysisY = CW_USEDEFAULT;
\r
1818 analysisW = CW_USEDEFAULT;
\r
1819 analysisH = CW_USEDEFAULT;
\r
1820 commentX = CW_USEDEFAULT;
\r
1821 commentY = CW_USEDEFAULT;
\r
1822 commentW = CW_USEDEFAULT;
\r
1823 commentH = CW_USEDEFAULT;
\r
1824 editTagsX = CW_USEDEFAULT;
\r
1825 editTagsY = CW_USEDEFAULT;
\r
1826 editTagsW = CW_USEDEFAULT;
\r
1827 editTagsH = CW_USEDEFAULT;
\r
1828 gameListX = CW_USEDEFAULT;
\r
1829 gameListY = CW_USEDEFAULT;
\r
1830 gameListW = CW_USEDEFAULT;
\r
1831 gameListH = CW_USEDEFAULT;
\r
1832 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1833 icsNames = ICS_NAMES;
\r
1834 firstChessProgramNames = FCP_NAMES;
\r
1835 secondChessProgramNames = SCP_NAMES;
\r
1836 appData.initialMode = "";
\r
1837 appData.variant = "normal";
\r
1838 appData.firstProtocolVersion = PROTOVER;
\r
1839 appData.secondProtocolVersion = PROTOVER;
\r
1840 appData.showButtonBar = TRUE;
\r
1842 /* [AS] New properties (see comments in header file) */
1843 appData.firstScoreIsAbsolute = FALSE;
1844 appData.secondScoreIsAbsolute = FALSE;
1845 appData.saveExtendedInfoInPGN = FALSE;
1846 appData.hideThinkingFromHuman = FALSE;
1847 appData.liteBackTextureFile = "";
1848 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
1849 appData.darkBackTextureFile = "";
1850 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
1851 appData.renderPiecesWithFont = "";
1852 appData.fontToPieceTable = "";
1853 appData.fontBackColorWhite = 0;
1854 appData.fontForeColorWhite = 0;
1855 appData.fontBackColorBlack = 0;
1856 appData.fontForeColorBlack = 0;
1857 appData.fontPieceSize = 80;
1858 appData.overrideLineGap = 1;
1859 appData.adjudicateLossThreshold = 0;
1860 appData.delayBeforeQuit = 0;
1861 appData.delayAfterQuit = 0;
1862 appData.nameOfDebugFile = "winboard.debug";
1863 appData.pgnEventHeader = "Computer Chess Game";
1864 appData.defaultFrcPosition = -1;
1865 appData.gameListTags = GLT_DEFAULT_TAGS;
1866 appData.saveOutOfBookInfo = TRUE;
1867 appData.showEvalInMoveHistory = TRUE;
1868 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
1869 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
1870 appData.highlightMoveWithArrow = FALSE;
1871 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
1872 appData.useStickyWindows = TRUE;
1873 appData.adjudicateDrawMoves = 0;
1874 appData.autoDisplayComment = TRUE;
1875 appData.autoDisplayTags = TRUE;
1876 appData.firstIsUCI = FALSE;
1877 appData.secondIsUCI = FALSE;
1878 appData.firstHasOwnBookUCI = TRUE;
1879 appData.secondHasOwnBookUCI = TRUE;
1880 appData.polyglotDir = "";
1881 appData.usePolyglotBook = FALSE;
1882 appData.polyglotBook = "";
1883 appData.defaultHashSize = 64;
1884 appData.defaultCacheSizeEGTB = 4;
1885 appData.defaultPathEGTB = "c:\\egtb";
1887 InitWindowPlacement( &wpMoveHistory );
1888 InitWindowPlacement( &wpEvalGraph );
1889 InitWindowPlacement( &wpEngineOutput );
1892 appData.zippyTalk = ZIPPY_TALK;
\r
1893 appData.zippyPlay = ZIPPY_PLAY;
\r
1894 appData.zippyLines = ZIPPY_LINES;
\r
1895 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1896 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1897 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1898 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1899 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1900 appData.zippyUseI = ZIPPY_USE_I;
\r
1901 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1902 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1903 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1904 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1905 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1906 appData.zippyAbort = ZIPPY_ABORT;
\r
1907 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1908 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1909 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1912 /* Point font array elements to structures and
\r
1913 parse default font names */
\r
1914 for (i=0; i<NUM_FONTS; i++) {
\r
1915 for (j=0; j<NUM_SIZES; j++) {
\r
1916 font[j][i] = &fontRec[j][i];
\r
1917 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1921 /* Parse default settings file if any */
\r
1922 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1923 settingsFileName = strdup(buf);
\r
1926 /* Parse command line */
\r
1927 ParseArgs(StringGet, &lpCmdLine);
\r
1929 /* Propagate options that affect others */
\r
1930 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1931 if (appData.icsActive || appData.noChessProgram) {
\r
1932 chessProgram = FALSE; /* not local chess program mode */
\r
1935 /* Open startup dialog if needed */
\r
1936 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1937 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1938 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1939 *appData.secondChessProgram == NULLCHAR))) {
\r
1942 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1943 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1944 FreeProcInstance(lpProc);
\r
1947 /* Make sure save files land in the right (?) directory */
\r
1948 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1949 appData.saveGameFile = strdup(buf);
\r
1951 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1952 appData.savePositionFile = strdup(buf);
\r
1955 /* Finish initialization for fonts and sounds */
\r
1956 for (i=0; i<NUM_FONTS; i++) {
\r
1957 for (j=0; j<NUM_SIZES; j++) {
\r
1958 CreateFontInMF(font[j][i]);
\r
1961 /* xboard, and older WinBoards, controlled the move sound with the
\r
1962 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1963 always turn the option on (so that the backend will call us),
\r
1964 then let the user turn the sound off by setting it to silence if
\r
1965 desired. To accommodate old winboard.ini files saved by old
\r
1966 versions of WinBoard, we also turn off the sound if the option
\r
1967 was initially set to false. */
\r
1968 if (!appData.ringBellAfterMoves) {
\r
1969 sounds[(int)SoundMove].name = strdup("");
\r
1970 appData.ringBellAfterMoves = TRUE;
\r
1972 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1973 SetCurrentDirectory(installDir);
\r
1975 SetCurrentDirectory(currDir);
\r
1977 p = icsTextMenuString;
\r
1978 if (p[0] == '@') {
\r
1979 FILE* f = fopen(p + 1, "r");
\r
1981 DisplayFatalError(p + 1, errno, 2);
\r
1984 i = fread(buf, 1, sizeof(buf)-1, f);
\r
1986 buf[i] = NULLCHAR;
\r
1989 ParseIcsTextMenu(strdup(p));
\r
1996 HMENU hmenu = GetMenu(hwndMain);
\r
1998 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1999 MF_BYCOMMAND|((appData.icsActive &&
\r
2000 *appData.icsCommPort != NULLCHAR) ?
\r
2001 MF_ENABLED : MF_GRAYED));
\r
2002 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2003 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2004 MF_CHECKED : MF_UNCHECKED));
\r
2009 SaveSettings(char* name)
\r
2012 ArgDescriptor *ad;
\r
2013 WINDOWPLACEMENT wp;
\r
2014 char dir[MSG_SIZ];
\r
2016 if (!hwndMain) return;
\r
2018 GetCurrentDirectory(MSG_SIZ, dir);
\r
2019 SetCurrentDirectory(installDir);
\r
2020 f = fopen(name, "w");
\r
2021 SetCurrentDirectory(dir);
\r
2023 DisplayError(name, errno);
\r
2026 fprintf(f, ";\n");
\r
2027 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2028 fprintf(f, ";\n");
\r
2029 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2030 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2031 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2032 fprintf(f, ";\n");
\r
2034 wp.length = sizeof(WINDOWPLACEMENT);
\r
2035 GetWindowPlacement(hwndMain, &wp);
\r
2036 boardX = wp.rcNormalPosition.left;
\r
2037 boardY = wp.rcNormalPosition.top;
\r
2039 if (hwndConsole) {
\r
2040 GetWindowPlacement(hwndConsole, &wp);
\r
2041 consoleX = wp.rcNormalPosition.left;
\r
2042 consoleY = wp.rcNormalPosition.top;
\r
2043 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2044 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2047 if (analysisDialog) {
\r
2048 GetWindowPlacement(analysisDialog, &wp);
\r
2049 analysisX = wp.rcNormalPosition.left;
\r
2050 analysisY = wp.rcNormalPosition.top;
\r
2051 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2052 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2055 if (commentDialog) {
\r
2056 GetWindowPlacement(commentDialog, &wp);
\r
2057 commentX = wp.rcNormalPosition.left;
\r
2058 commentY = wp.rcNormalPosition.top;
\r
2059 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2060 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2063 if (editTagsDialog) {
\r
2064 GetWindowPlacement(editTagsDialog, &wp);
\r
2065 editTagsX = wp.rcNormalPosition.left;
\r
2066 editTagsY = wp.rcNormalPosition.top;
\r
2067 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2068 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2071 if (gameListDialog) {
\r
2072 GetWindowPlacement(gameListDialog, &wp);
\r
2073 gameListX = wp.rcNormalPosition.left;
\r
2074 gameListY = wp.rcNormalPosition.top;
\r
2075 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2076 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2079 /* [AS] Move history */
2080 wpMoveHistory.visible = MoveHistoryIsUp();
2082 if( moveHistoryDialog ) {
2083 GetWindowPlacement(moveHistoryDialog, &wp);
2084 wpMoveHistory.x = wp.rcNormalPosition.left;
2085 wpMoveHistory.y = wp.rcNormalPosition.top;
2086 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
2087 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
2090 /* [AS] Eval graph */
2091 wpEvalGraph.visible = EvalGraphIsUp();
2093 if( evalGraphDialog ) {
2094 GetWindowPlacement(evalGraphDialog, &wp);
2095 wpEvalGraph.x = wp.rcNormalPosition.left;
2096 wpEvalGraph.y = wp.rcNormalPosition.top;
2097 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
2098 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
2101 /* [AS] Engine output */
2102 wpEngineOutput.visible = EngineOutputIsUp();
2104 if( engineOutputDialog ) {
2105 GetWindowPlacement(engineOutputDialog, &wp);
2106 wpEngineOutput.x = wp.rcNormalPosition.left;
2107 wpEngineOutput.y = wp.rcNormalPosition.top;
2108 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
2109 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
2112 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2113 if (!ad->save) continue;
\r
2114 switch (ad->argType) {
\r
2117 char *p = *(char **)ad->argLoc;
\r
2118 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2119 /* Quote multiline values or \-containing values
\r
2120 with { } if possible */
\r
2121 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2123 /* Else quote with " " */
\r
2124 fprintf(f, "/%s=\"", ad->argName);
\r
2126 if (*p == '\n') fprintf(f, "\n");
\r
2127 else if (*p == '\r') fprintf(f, "\\r");
\r
2128 else if (*p == '\t') fprintf(f, "\\t");
\r
2129 else if (*p == '\b') fprintf(f, "\\b");
\r
2130 else if (*p == '\f') fprintf(f, "\\f");
\r
2131 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2132 else if (*p == '\"') fprintf(f, "\\\"");
\r
2133 else if (*p == '\\') fprintf(f, "\\\\");
\r
2137 fprintf(f, "\"\n");
\r
2142 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2145 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2148 fprintf(f, "/%s=%s\n", ad->argName,
\r
2149 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2152 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2155 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2159 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2160 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2161 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2166 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2167 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2168 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2169 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2170 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2171 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2172 (ta->effects) ? " " : "",
\r
2173 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2177 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2178 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2180 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2183 case ArgBoardSize:
\r
2184 fprintf(f, "/%s=%s\n", ad->argName,
\r
2185 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2190 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2191 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2192 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2193 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2194 ad->argName, mfp->faceName, mfp->pointSize,
\r
2195 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2196 mfp->bold ? "b" : "",
\r
2197 mfp->italic ? "i" : "",
\r
2198 mfp->underline ? "u" : "",
\r
2199 mfp->strikeout ? "s" : "");
\r
2203 case ArgCommSettings:
\r
2204 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2212 /*---------------------------------------------------------------------------*\
\r
2214 * GDI board drawing routines
\r
2216 \*---------------------------------------------------------------------------*/
\r
2218 /* [AS] Draw square using background texture */
2219 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
2224 return; /* Should never happen! */
2227 SetGraphicsMode( dst, GM_ADVANCED );
2239 x.eDx = (FLOAT) dw + dx - 1;
2242 SetWorldTransform( dst, &x );
2251 x.eDy = (FLOAT) dh + dy - 1;
2253 SetWorldTransform( dst, &x );
2265 SetWorldTransform( dst, &x );
2269 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
2277 SetWorldTransform( dst, &x );
2279 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
2298 static HFONT hPieceFont = NULL;
2299 static HBITMAP hPieceMask[12];
2300 static HBITMAP hPieceFace[12];
2301 static int fontBitmapSquareSize = 0;
2302 static char pieceToFontChar[12] = { 'p', 'n', 'b', 'r', 'q', 'k', 'o', 'm', 'v', 't', 'w', 'l' };
2304 static BOOL SetPieceToFontCharTable( const char * map )
2306 BOOL result = FALSE;
2308 if( map != NULL && strlen(map) == 12 ) {
2311 for( i=0; i<12; i++ ) {
2312 pieceToFontChar[i] = map[i];
2321 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
2324 BYTE r1 = GetRValue( color );
2325 BYTE g1 = GetGValue( color );
2326 BYTE b1 = GetBValue( color );
2332 /* Create a uniform background first */
2333 hbrush = CreateSolidBrush( color );
2334 SetRect( &rc, 0, 0, squareSize, squareSize );
2335 FillRect( hdc, &rc, hbrush );
2336 DeleteObject( hbrush );
2339 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
2340 int steps = squareSize / 2;
2343 for( i=0; i<steps; i++ ) {
2344 BYTE r = r1 - (r1-r2) * i / steps;
2345 BYTE g = g1 - (g1-g2) * i / steps;
2346 BYTE b = b1 - (b1-b2) * i / steps;
2348 hbrush = CreateSolidBrush( RGB(r,g,b) );
2349 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
2350 FillRect( hdc, &rc, hbrush );
2351 DeleteObject(hbrush);
2354 else if( mode == 2 ) {
2355 /* Diagonal gradient, good more or less for every piece */
2357 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
2359 int steps = squareSize;
2362 triangle[0].x = squareSize - steps;
2363 triangle[0].y = squareSize;
2364 triangle[1].x = squareSize;
2365 triangle[1].y = squareSize;
2366 triangle[2].x = squareSize;
2367 triangle[2].y = squareSize - steps;
2369 for( i=0; i<steps; i++ ) {
2370 BYTE r = r1 - (r1-r2) * i / steps;
2371 BYTE g = g1 - (g1-g2) * i / steps;
2372 BYTE b = b1 - (b1-b2) * i / steps;
2374 hbrush = CreateSolidBrush( RGB(r,g,b) );
2375 hbrush_old = SelectObject( hdc, hbrush );
2376 Polygon( hdc, triangle, 3 );
2377 SelectObject( hdc, hbrush_old );
2378 DeleteObject(hbrush);
2383 SelectObject( hdc, hpen );
2388 [AS] The method I use to create the bitmaps it a bit tricky, but it
2389 seems to work ok. The main problem here is to find the "inside" of a chess
2390 piece: follow the steps as explained below.
2392 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
2396 COLORREF chroma = RGB(0xFF,0x00,0xFF);
2400 int backColor = whitePieceColor;
2401 int foreColor = blackPieceColor;
2402 int shapeIndex = index < 6 ? index+6 : index;
2404 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
2405 backColor = appData.fontBackColorWhite;
2406 foreColor = appData.fontForeColorWhite;
2408 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
2409 backColor = appData.fontBackColorBlack;
2410 foreColor = appData.fontForeColorBlack;
2414 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2416 hbm_old = SelectObject( hdc, hbm );
2420 rc.right = squareSize;
2421 rc.bottom = squareSize;
2423 /* Step 1: background is now black */
2424 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
2426 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
2428 pt.x = (squareSize - sz.cx) / 2;
2429 pt.y = (squareSize - sz.cy) / 2;
2431 SetBkMode( hdc, TRANSPARENT );
2432 SetTextColor( hdc, chroma );
2433 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
2434 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2436 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
2437 /* Step 3: the area outside the piece is filled with white */
2438 FloodFill( hdc, 0, 0, chroma );
2439 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
2441 Step 4: this is the tricky part, the area inside the piece is filled with black,
2442 but if the start point is not inside the piece we're lost!
2443 There should be a better way to do this... if we could create a region or path
2444 from the fill operation we would be fine for example.
2446 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
2448 SetTextColor( hdc, 0 );
2450 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
2451 draw the piece again in black for safety.
2453 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2455 SelectObject( hdc, hbm_old );
2457 if( hPieceMask[index] != NULL ) {
2458 DeleteObject( hPieceMask[index] );
2461 hPieceMask[index] = hbm;
2464 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2466 SelectObject( hdc, hbm );
2469 HDC dc1 = CreateCompatibleDC( hdc_window );
2470 HDC dc2 = CreateCompatibleDC( hdc_window );
2471 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2473 SelectObject( dc1, hPieceMask[index] );
2474 SelectObject( dc2, bm2 );
2475 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
2476 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
2479 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
2480 the piece background and deletes (makes transparent) the rest.
2481 Thanks to that mask, we are free to paint the background with the greates
2482 freedom, as we'll be able to mask off the unwanted parts when finished.
2483 We use this, to make gradients and give the pieces a "roundish" look.
2485 SetPieceBackground( hdc, backColor, 2 );
2486 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
2490 DeleteObject( bm2 );
2493 SetTextColor( hdc, foreColor );
2494 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2496 SelectObject( hdc, hbm_old );
2498 if( hPieceFace[index] != NULL ) {
2499 DeleteObject( hPieceFace[index] );
2502 hPieceFace[index] = hbm;
2505 static int TranslatePieceToFontPiece( int piece )
2537 void CreatePiecesFromFont()
2540 HDC hdc_window = NULL;
2546 if( fontBitmapSquareSize < 0 ) {
2547 /* Something went seriously wrong in the past: do not try to recreate fonts! */
2551 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
2552 fontBitmapSquareSize = -1;
2556 if( fontBitmapSquareSize != squareSize ) {
2557 hdc_window = GetDC( hwndMain );
2558 hdc = CreateCompatibleDC( hdc_window );
2560 if( hPieceFont != NULL ) {
2561 DeleteObject( hPieceFont );
2564 for( i=0; i<12; i++ ) {
2565 hPieceMask[i] = NULL;
2566 hPieceFace[i] = NULL;
2572 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
2573 fontHeight = appData.fontPieceSize;
2576 fontHeight = (fontHeight * squareSize) / 100;
2578 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
2580 lf.lfEscapement = 0;
2581 lf.lfOrientation = 0;
2582 lf.lfWeight = FW_NORMAL;
2586 lf.lfCharSet = DEFAULT_CHARSET;
2587 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
2588 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2589 lf.lfQuality = PROOF_QUALITY;
2590 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
2591 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
2592 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
2594 hPieceFont = CreateFontIndirect( &lf );
2596 if( hPieceFont == NULL ) {
2597 fontBitmapSquareSize = -2;
2600 /* Setup font-to-piece character table */
2601 if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) {
2602 /* No (or wrong) global settings, try to detect the font */
2603 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
2605 SetPieceToFontCharTable("phbrqkojntwl");
2607 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
2608 /* DiagramTT* family */
2609 SetPieceToFontCharTable("PNLRQKpnlrqk");
2612 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
2613 SetPieceToFontCharTable("pnbrqkomvtwl");
2617 /* Create bitmaps */
2618 hfont_old = SelectObject( hdc, hPieceFont );
2620 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
2621 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
2622 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
2623 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
2624 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
2625 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
2626 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
2627 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
2628 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
2629 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
2630 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
2631 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
2633 SelectObject( hdc, hfont_old );
2635 fontBitmapSquareSize = squareSize;
2643 if( hdc_window != NULL ) {
2644 ReleaseDC( hwndMain, hdc_window );
2649 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2653 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2654 if (gameInfo.event &&
\r
2655 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2656 strcmp(name, "k80s") == 0) {
\r
2657 strcpy(name, "tim");
\r
2659 return LoadBitmap(hinst, name);
\r
2663 /* Insert a color into the program's logical palette
\r
2664 structure. This code assumes the given color is
\r
2665 the result of the RGB or PALETTERGB macro, and it
\r
2666 knows how those macros work (which is documented).
\r
2669 InsertInPalette(COLORREF color)
\r
2671 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2673 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2674 DisplayFatalError("Too many colors", 0, 1);
\r
2675 pLogPal->palNumEntries--;
\r
2679 pe->peFlags = (char) 0;
\r
2680 pe->peRed = (char) (0xFF & color);
\r
2681 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2682 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2688 InitDrawingColors()
\r
2690 if (pLogPal == NULL) {
\r
2691 /* Allocate enough memory for a logical palette with
\r
2692 * PALETTESIZE entries and set the size and version fields
\r
2693 * of the logical palette structure.
\r
2695 pLogPal = (NPLOGPALETTE)
\r
2696 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2697 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2698 pLogPal->palVersion = 0x300;
\r
2700 pLogPal->palNumEntries = 0;
\r
2702 InsertInPalette(lightSquareColor);
\r
2703 InsertInPalette(darkSquareColor);
\r
2704 InsertInPalette(whitePieceColor);
\r
2705 InsertInPalette(blackPieceColor);
\r
2706 InsertInPalette(highlightSquareColor);
\r
2707 InsertInPalette(premoveHighlightColor);
\r
2709 /* create a logical color palette according the information
\r
2710 * in the LOGPALETTE structure.
\r
2712 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2714 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2715 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2716 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2717 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2718 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2720 /* [AS] Force rendering of the font-based pieces */
2721 if( fontBitmapSquareSize > 0 ) {
2722 fontBitmapSquareSize = 0;
2728 BoardWidth(int boardSize)
\r
2730 int lineGap = sizeInfo[boardSize].lineGap;
2732 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
2733 lineGap = appData.overrideLineGap;
2736 return (BOARD_SIZE + 1) * lineGap +
2737 BOARD_SIZE * sizeInfo[boardSize].squareSize;
\r
2740 /* Respond to board resize by dragging edge */
\r
2742 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2744 BoardSize newSize = NUM_SIZES - 1;
\r
2745 static int recurse = 0;
\r
2746 if (IsIconic(hwndMain)) return;
\r
2747 if (recurse > 0) return;
\r
2749 while (newSize > 0 &&
\r
2750 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2751 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2754 boardSize = newSize;
\r
2755 InitDrawingSizes(boardSize, flags);
\r
2762 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2764 int i, boardWidth;
\r
2765 ChessSquare piece;
\r
2766 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2768 SIZE clockSize, messageSize;
\r
2770 char buf[MSG_SIZ];
\r
2772 HMENU hmenu = GetMenu(hwndMain);
\r
2773 RECT crect, wrect;
\r
2775 LOGBRUSH logbrush;
\r
2777 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2778 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2779 squareSize = sizeInfo[boardSize].squareSize;
\r
2780 lineGap = sizeInfo[boardSize].lineGap;
\r
2782 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
2783 lineGap = appData.overrideLineGap;
2786 if (tinyLayout != oldTinyLayout) {
\r
2787 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2789 style &= ~WS_SYSMENU;
\r
2790 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2791 "&Minimize\tCtrl+F4");
\r
2793 style |= WS_SYSMENU;
\r
2794 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2796 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2798 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2799 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2800 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2802 DrawMenuBar(hwndMain);
\r
2805 boardWidth = BoardWidth(boardSize);
\r
2807 /* Get text area sizes */
\r
2808 hdc = GetDC(hwndMain);
\r
2809 if (appData.clockMode) {
\r
2810 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2812 sprintf(buf, "White");
\r
2814 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2815 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2816 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2817 str = "We only care about the height here";
\r
2818 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2819 SelectObject(hdc, oldFont);
\r
2820 ReleaseDC(hwndMain, hdc);
\r
2822 /* Compute where everything goes */
\r
2823 whiteRect.left = OUTER_MARGIN;
\r
2824 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2825 whiteRect.top = OUTER_MARGIN;
\r
2826 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2828 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2829 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2830 blackRect.top = whiteRect.top;
\r
2831 blackRect.bottom = whiteRect.bottom;
\r
2833 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2834 if (appData.showButtonBar) {
\r
2835 messageRect.right = blackRect.right
\r
2836 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2838 messageRect.right = blackRect.right;
\r
2840 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2841 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2843 boardRect.left = whiteRect.left;
\r
2844 boardRect.right = boardRect.left + boardWidth;
\r
2845 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2846 boardRect.bottom = boardRect.top + boardWidth;
\r
2848 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2849 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2850 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2851 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2852 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2853 GetWindowRect(hwndMain, &wrect);
\r
2854 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2855 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2856 /* compensate if menu bar wrapped */
\r
2857 GetClientRect(hwndMain, &crect);
\r
2858 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2859 winHeight += offby;
\r
2861 case WMSZ_TOPLEFT:
\r
2862 SetWindowPos(hwndMain, NULL,
\r
2863 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2864 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2867 case WMSZ_TOPRIGHT:
\r
2869 SetWindowPos(hwndMain, NULL,
\r
2870 wrect.left, wrect.bottom - winHeight,
\r
2871 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2874 case WMSZ_BOTTOMLEFT:
\r
2876 SetWindowPos(hwndMain, NULL,
\r
2877 wrect.right - winWidth, wrect.top,
\r
2878 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2881 case WMSZ_BOTTOMRIGHT:
\r
2885 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2886 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2891 for (i = 0; i < N_BUTTONS; i++) {
\r
2892 if (buttonDesc[i].hwnd != NULL) {
\r
2893 DestroyWindow(buttonDesc[i].hwnd);
\r
2894 buttonDesc[i].hwnd = NULL;
\r
2896 if (appData.showButtonBar) {
\r
2897 buttonDesc[i].hwnd =
\r
2898 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2899 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2900 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2901 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2902 (HMENU) buttonDesc[i].id,
\r
2903 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2905 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2906 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2907 MAKELPARAM(FALSE, 0));
\r
2909 if (buttonDesc[i].id == IDM_Pause)
\r
2910 hwndPause = buttonDesc[i].hwnd;
\r
2911 buttonDesc[i].wndproc = (WNDPROC)
\r
2912 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2915 if (gridPen != NULL) DeleteObject(gridPen);
\r
2916 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2917 if (premovePen != NULL) DeleteObject(premovePen);
\r
2918 if (lineGap != 0) {
\r
2919 logbrush.lbStyle = BS_SOLID;
\r
2920 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2922 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2923 lineGap, &logbrush, 0, NULL);
\r
2924 logbrush.lbColor = highlightSquareColor;
\r
2926 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2927 lineGap, &logbrush, 0, NULL);
\r
2929 logbrush.lbColor = premoveHighlightColor;
\r
2931 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2932 lineGap, &logbrush, 0, NULL);
\r
2934 for (i = 0; i < BOARD_SIZE + 1; i++) {
\r
2935 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2936 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2;
\r
2937 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2938 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2939 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2940 BOARD_SIZE * (squareSize + lineGap);
\r
2941 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x =
\r
2942 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left +
\r
2943 lineGap / 2 + (i * (squareSize + lineGap));
\r
2944 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y =
\r
2945 boardRect.top + BOARD_SIZE * (squareSize + lineGap);
\r
2946 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2950 if (boardSize == oldBoardSize) return;
\r
2951 oldBoardSize = boardSize;
\r
2952 oldTinyLayout = tinyLayout;
\r
2954 /* Load piece bitmaps for this board size */
\r
2955 for (i=0; i<=2; i++) {
\r
2956 for (piece = WhitePawn;
\r
2957 (int) piece <= (int) WhiteKing;
\r
2958 piece = (ChessSquare) ((int) piece + 1)) {
\r
2959 if (pieceBitmap[i][piece] != NULL)
\r
2960 DeleteObject(pieceBitmap[i][piece]);
\r
2964 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2965 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2966 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2967 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2968 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2969 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2970 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2971 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2972 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2973 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2974 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2975 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2976 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2977 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2978 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2979 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2980 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2981 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2986 PieceBitmap(ChessSquare p, int kind)
\r
2988 if ((int) p >= (int) BlackPawn)
\r
2989 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2991 return pieceBitmap[kind][(int) p];
\r
2994 /***************************************************************/
\r
2996 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2997 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2999 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3000 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3004 SquareToPos(int row, int column, int * x, int * y)
\r
3007 *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
3008 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3010 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3011 *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
3016 DrawCoordsOnDC(HDC hdc)
\r
3018 static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'};
\r
3019 static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'};
\r
3020 char str[2] = { NULLCHAR, NULLCHAR };
\r
3021 int oldMode, oldAlign, x, y, start, i;
\r
3025 if (!appData.showCoords)
\r
3028 start = flipView ? 0 : 8;
\r
3030 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3031 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3032 oldAlign = GetTextAlign(hdc);
\r
3033 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3035 y = boardRect.top + lineGap;
\r
3036 x = boardRect.left + lineGap;
\r
3038 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3039 for (i = 0; i < 8; i++) {
\r
3040 str[0] = files[start + i];
\r
3041 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3042 y += squareSize + lineGap;
\r
3045 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3046 for (i = 0; i < 8; i++) {
\r
3047 str[0] = ranks[start + i];
\r
3048 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3049 x += squareSize + lineGap;
\r
3052 SelectObject(hdc, oldBrush);
\r
3053 SetBkMode(hdc, oldMode);
\r
3054 SetTextAlign(hdc, oldAlign);
\r
3055 SelectObject(hdc, oldFont);
\r
3059 DrawGridOnDC(HDC hdc)
\r
3063 if (lineGap != 0) {
\r
3064 oldPen = SelectObject(hdc, gridPen);
\r
3065 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2);
\r
3066 SelectObject(hdc, oldPen);
\r
3070 #define HIGHLIGHT_PEN 0
\r
3071 #define PREMOVE_PEN 1
\r
3074 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3077 HPEN oldPen, hPen;
\r
3078 if (lineGap == 0) return;
\r
3080 x1 = boardRect.left +
\r
3081 lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap);
\r
3082 y1 = boardRect.top +
\r
3083 lineGap/2 + y * (squareSize + lineGap);
\r
3085 x1 = boardRect.left +
\r
3086 lineGap/2 + x * (squareSize + lineGap);
\r
3087 y1 = boardRect.top +
\r
3088 lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap);
\r
3090 hPen = pen ? premovePen : highlightPen;
\r
3091 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3092 MoveToEx(hdc, x1, y1, NULL);
\r
3093 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3094 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3095 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3096 LineTo(hdc, x1, y1);
\r
3097 SelectObject(hdc, oldPen);
\r
3101 DrawHighlightsOnDC(HDC hdc)
\r
3104 for (i=0; i<2; i++) {
\r
3105 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3106 DrawHighlightOnDC(hdc, TRUE,
\r
3107 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3110 for (i=0; i<2; i++) {
\r
3111 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3112 premoveHighlightInfo.sq[i].y >= 0) {
\r
3113 DrawHighlightOnDC(hdc, TRUE,
\r
3114 premoveHighlightInfo.sq[i].x,
\r
3115 premoveHighlightInfo.sq[i].y,
\r
3121 /* Note: sqcolor is used only in monoMode */
\r
3122 /* Note that this code is largely duplicated in woptions.c,
\r
3123 function DrawSampleSquare, so that needs to be updated too */
\r
3125 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3127 HBITMAP oldBitmap;
\r
3130 if (appData.blindfold) return;
\r
3132 /* [AS] Use font-based pieces if needed */
3133 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
3134 /* Create piece bitmaps, or do nothing if piece set is up to date */
3135 CreatePiecesFromFont();
3137 if( fontBitmapSquareSize == squareSize ) {
3138 int index = TranslatePieceToFontPiece( piece );
3140 SelectObject( tmphdc, hPieceMask[ index ] );
3144 squareSize, squareSize,
3149 SelectObject( tmphdc, hPieceFace[ index ] );
3153 squareSize, squareSize,
3162 if (appData.monoMode) {
\r
3163 SelectObject(tmphdc, PieceBitmap(piece,
\r
3164 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3165 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3166 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3169 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3170 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3171 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3173 /* Use black piece color for outline of white pieces */
\r
3174 /* Not sure this looks really good (though xboard does it).
\r
3175 Maybe better to have another selectable color, default black */
\r
3176 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3177 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3178 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3180 /* Use black for outline of white pieces */
\r
3181 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3182 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
3186 /* Use white piece color for details of black pieces */
\r
3187 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3188 WHITE_PIECE ones aren't always the right shape. */
\r
3189 /* Not sure this looks really good (though xboard does it).
\r
3190 Maybe better to have another selectable color, default medium gray? */
\r
3191 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3192 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3193 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3194 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3195 SelectObject(hdc, blackPieceBrush);
\r
3196 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3198 /* Use square color for details of black pieces */
\r
3199 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3200 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3201 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3204 SelectObject(hdc, oldBrush);
\r
3205 SelectObject(tmphdc, oldBitmap);
\r
3209 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
3210 int GetBackTextureMode( int algo )
3212 int result = BACK_TEXTURE_MODE_DISABLED;
3216 case BACK_TEXTURE_MODE_PLAIN:
3217 result = 1; /* Always use identity map */
3219 case BACK_TEXTURE_MODE_FULL_RANDOM:
3220 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
3228 [AS] Compute and save texture drawing info, otherwise we may not be able
3229 to handle redraws cleanly (as random numbers would always be different).
3231 VOID RebuildTextureSquareInfo()
3241 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
3243 if( liteBackTexture != NULL ) {
3244 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
3245 lite_w = bi.bmWidth;
3246 lite_h = bi.bmHeight;
3250 if( darkBackTexture != NULL ) {
3251 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
3252 dark_w = bi.bmWidth;
3253 dark_h = bi.bmHeight;
3257 for( row=0; row<BOARD_SIZE; row++ ) {
3258 for( col=0; col<BOARD_SIZE; col++ ) {
3259 if( (col + row) & 1 ) {
3261 if( lite_w >= squareSize && lite_h >= squareSize ) {
3262 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_SIZE;
3263 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_SIZE;
3264 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
3269 if( dark_w >= squareSize && dark_h >= squareSize ) {
3270 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_SIZE;
3271 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_SIZE;
3272 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
3279 /* [AS] Arrow highlighting support */
3281 static int A_WIDTH = 5; /* Width of arrow body */
3283 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
3284 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
3286 static double Sqr( double x )
3291 static int Round( double x )
3293 return (int) (x + 0.5);
3296 /* Draw an arrow between two points using current settings */
3297 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
3300 double dx, dy, j, k, x, y;
3303 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
3305 arrow[0].x = s_x + A_WIDTH;
3308 arrow[1].x = s_x + A_WIDTH;
3309 arrow[1].y = d_y - h;
3311 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
3312 arrow[2].y = d_y - h;
3317 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
3318 arrow[4].y = d_y - h;
3320 arrow[5].x = s_x - A_WIDTH;
3321 arrow[5].y = d_y - h;
3323 arrow[6].x = s_x - A_WIDTH;
3326 else if( d_y == s_y ) {
3327 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
3330 arrow[0].y = s_y + A_WIDTH;
3332 arrow[1].x = d_x - w;
3333 arrow[1].y = s_y + A_WIDTH;
3335 arrow[2].x = d_x - w;
3336 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
3341 arrow[4].x = d_x - w;
3342 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
3344 arrow[5].x = d_x - w;
3345 arrow[5].y = s_y - A_WIDTH;
3348 arrow[6].y = s_y - A_WIDTH;
3351 /* [AS] Needed a lot of paper for this! :-) */
3352 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
3353 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
3355 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
3357 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
3362 arrow[0].x = Round(x - j);
3363 arrow[0].y = Round(y + j*dx);
3365 arrow[1].x = Round(x + j);
3366 arrow[1].y = Round(y - j*dx);
3369 x = (double) d_x - k;
3370 y = (double) d_y - k*dy;
3373 x = (double) d_x + k;
3374 y = (double) d_y + k*dy;
3377 arrow[2].x = Round(x + j);
3378 arrow[2].y = Round(y - j*dx);
3380 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
3381 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
3386 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
3387 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
3389 arrow[6].x = Round(x - j);
3390 arrow[6].y = Round(y + j*dx);
3393 Polygon( hdc, arrow, 7 );
3396 /* [AS] Draw an arrow between two squares */
3397 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
3399 int s_x, s_y, d_x, d_y;
3406 if( s_col == d_col && s_row == d_row ) {
3410 /* Get source and destination points */
3411 SquareToPos( s_row, s_col, &s_x, &s_y);
3412 SquareToPos( d_row, d_col, &d_x, &d_y);
3415 d_y += squareSize / 4;
3417 else if( d_y < s_y ) {
3418 d_y += 3 * squareSize / 4;
3421 d_y += squareSize / 2;
3425 d_x += squareSize / 4;
3427 else if( d_x < s_x ) {
3428 d_x += 3 * squareSize / 4;
3431 d_x += squareSize / 2;
3434 s_x += squareSize / 2;
3435 s_y += squareSize / 2;
3438 A_WIDTH = squareSize / 14;
3441 stLB.lbStyle = BS_SOLID;
3442 stLB.lbColor = appData.highlightArrowColor;
3445 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
3446 holdpen = SelectObject( hdc, hpen );
3447 hbrush = CreateBrushIndirect( &stLB );
3448 holdbrush = SelectObject( hdc, hbrush );
3450 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
3452 SelectObject( hdc, holdpen );
3453 SelectObject( hdc, holdbrush );
3454 DeleteObject( hpen );
3455 DeleteObject( hbrush );
3458 BOOL HasHighlightInfo()
3460 BOOL result = FALSE;
3462 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
3463 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
3471 BOOL IsDrawArrowEnabled()
3473 BOOL result = FALSE;
3475 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
3482 VOID DrawArrowHighlight( HDC hdc )
3484 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
3485 DrawArrowBetweenSquares( hdc,
3486 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
3487 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
3491 HRGN GetArrowHighlightClipRegion( HDC hdc )
3495 if( HasHighlightInfo() ) {
3499 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
3500 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
3504 dx = MAX( x1, x2 ) + squareSize;
3505 dy = MAX( y1, y2 ) + squareSize;
3507 result = CreateRectRgn( sx, sy, dx, dy );
3514 Warning: this function modifies the behavior of several other functions.
3516 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
3517 needed. Unfortunately, the decision whether or not to perform a full or partial
3518 repaint is scattered all over the place, which is not good for features such as
3519 "arrow highlighting" that require a full repaint of the board.
3521 So, I've tried to patch the code where I thought it made sense (e.g. after or during
3522 user interaction, when speed is not so important) but especially to avoid errors
3523 in the displayed graphics.
3525 In such patched places, I always try refer to this function so there is a single
3526 place to maintain knowledge.
3528 To restore the original behavior, just return FALSE unconditionally.
3530 BOOL IsFullRepaintPreferrable()
3532 BOOL result = FALSE;
3534 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
3535 /* Arrow may appear on the board */
3543 This function is called by DrawPosition to know whether a full repaint must
3546 Only DrawPosition may directly call this function, which makes use of
3547 some state information. Other function should call DrawPosition specifying
3548 the repaint flag, and can use IsFullRepaintPreferrable if needed.
3550 BOOL DrawPositionNeedsFullRepaint()
3552 BOOL result = FALSE;
3555 Probably a slightly better policy would be to trigger a full repaint
3556 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
3557 but animation is fast enough that it's difficult to notice.
3559 if( animInfo.piece == EmptySquare ) {
3560 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
3569 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3571 int row, column, x, y, square_color, piece_color;
\r
3572 ChessSquare piece;
\r
3574 HDC texture_hdc = NULL;
3576 /* [AS] Initialize background textures if needed */
3577 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
3578 if( backTextureSquareSize != squareSize ) {
3579 backTextureSquareSize = squareSize;
3580 RebuildTextureSquareInfo();
3583 texture_hdc = CreateCompatibleDC( hdc );
3586 for (row = 0; row < BOARD_SIZE; row++) {
\r
3587 for (column = 0; column < BOARD_SIZE; column++) {
\r
3589 SquareToPos(row, column, &x, &y);
\r
3591 piece = board[row][column];
\r
3593 square_color = ((column + row) % 2) == 1;
\r
3594 piece_color = (int) piece < (int) BlackPawn;
\r
3596 if (appData.monoMode) {
\r
3597 if (piece == EmptySquare) {
\r
3598 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3599 square_color ? WHITENESS : BLACKNESS);
\r
3601 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3604 else if( backTextureSquareInfo[row][column].mode > 0 ) {
3605 /* [AS] Draw the square using a texture bitmap */
3606 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
3609 squareSize, squareSize,
3612 backTextureSquareInfo[row][column].mode,
3613 backTextureSquareInfo[row][column].x,
3614 backTextureSquareInfo[row][column].y );
3616 SelectObject( texture_hdc, hbm );
3618 if (piece != EmptySquare) {
3619 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
3623 oldBrush = SelectObject(hdc, square_color ?
\r
3624 lightSquareBrush : darkSquareBrush);
\r
3625 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3626 SelectObject(hdc, oldBrush);
\r
3627 if (piece != EmptySquare)
\r
3628 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3633 if( texture_hdc != NULL ) {
3634 DeleteDC( texture_hdc );
3638 #define MAX_CLIPS 200 /* more than enough */
\r
3641 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3643 static Board lastReq, lastDrawn;
\r
3644 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3645 static int lastDrawnFlipView = 0;
\r
3646 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3647 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3650 HBITMAP bufferBitmap;
\r
3651 HBITMAP oldBitmap;
\r
3653 HRGN clips[MAX_CLIPS];
\r
3654 ChessSquare dragged_piece = EmptySquare;
\r
3656 /* I'm undecided on this - this function figures out whether a full
\r
3657 * repaint is necessary on its own, so there's no real reason to have the
\r
3658 * caller tell it that. I think this can safely be set to FALSE - but
\r
3659 * if we trust the callers not to request full repaints unnessesarily, then
\r
3660 * we could skip some clipping work. In other words, only request a full
\r
3661 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3662 * gamestart and similar) --Hawk
\r
3664 Boolean fullrepaint = repaint;
\r
3666 if( DrawPositionNeedsFullRepaint() ) {
3672 static int repaint_count = 0;
3676 sprintf( buf, "FULL repaint: %d\n", repaint_count );
3677 OutputDebugString( buf );
3681 if (board == NULL) {
\r
3682 if (!lastReqValid) {
\r
3687 CopyBoard(lastReq, board);
\r
3691 if (doingSizing) {
\r
3695 if (IsIconic(hwndMain)) {
\r
3699 if (hdc == NULL) {
\r
3700 hdc = GetDC(hwndMain);
\r
3701 if (!appData.monoMode) {
\r
3702 SelectPalette(hdc, hPal, FALSE);
\r
3703 RealizePalette(hdc);
\r
3707 releaseDC = FALSE;
\r
3711 fprintf(debugFP, "*******************************\n"
\r
3713 "dragInfo.from (%d,%d)\n"
\r
3714 "dragInfo.start (%d,%d)\n"
\r
3715 "dragInfo.pos (%d,%d)\n"
\r
3716 "dragInfo.lastpos (%d,%d)\n",
\r
3717 repaint ? "TRUE" : "FALSE",
\r
3718 dragInfo.from.x, dragInfo.from.y,
\r
3719 dragInfo.start.x, dragInfo.start.y,
\r
3720 dragInfo.pos.x, dragInfo.pos.y,
\r
3721 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
3722 fprintf(debugFP, "prev: ");
\r
3723 for (row = 0; row < 8; row++) {
\r
3724 for (column = 0; column < 8; column++) {
\r
3725 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
3728 fprintf(debugFP, "\n");
\r
3729 fprintf(debugFP, "board: ");
\r
3730 for (row = 0; row < 8; row++) {
\r
3731 for (column = 0; column < 8; column++) {
\r
3732 fprintf(debugFP, "%d ", board[row][column]);
\r
3735 fprintf(debugFP, "\n");
\r
3739 /* Create some work-DCs */
\r
3740 hdcmem = CreateCompatibleDC(hdc);
\r
3741 tmphdc = CreateCompatibleDC(hdc);
\r
3743 /* Figure out which squares need updating by comparing the
\r
3744 * newest board with the last drawn board and checking if
\r
3745 * flipping has changed.
\r
3747 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3748 for (row = 0; row < 8; row++) {
\r
3749 for (column = 0; column < 8; column++) {
\r
3750 if (lastDrawn[row][column] != board[row][column]) {
\r
3751 SquareToPos(row, column, &x, &y);
\r
3752 clips[num_clips++] =
\r
3753 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3757 for (i=0; i<2; i++) {
\r
3758 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3759 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3760 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3761 lastDrawnHighlight.sq[i].y >= 0) {
\r
3762 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3763 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3764 clips[num_clips++] =
\r
3765 CreateRectRgn(x - lineGap, y - lineGap,
\r
3766 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3768 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3769 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3770 clips[num_clips++] =
\r
3771 CreateRectRgn(x - lineGap, y - lineGap,
\r
3772 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3776 for (i=0; i<2; i++) {
\r
3777 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3778 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3779 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3780 lastDrawnPremove.sq[i].y >= 0) {
\r
3781 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3782 lastDrawnPremove.sq[i].x, &x, &y);
\r
3783 clips[num_clips++] =
\r
3784 CreateRectRgn(x - lineGap, y - lineGap,
\r
3785 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3787 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3788 premoveHighlightInfo.sq[i].y >= 0) {
\r
3789 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3790 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3791 clips[num_clips++] =
\r
3792 CreateRectRgn(x - lineGap, y - lineGap,
\r
3793 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3798 fullrepaint = TRUE;
\r
3801 /* Create a buffer bitmap - this is the actual bitmap
\r
3802 * being written to. When all the work is done, we can
\r
3803 * copy it to the real DC (the screen). This avoids
\r
3804 * the problems with flickering.
\r
3806 GetClientRect(hwndMain, &Rect);
\r
3807 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3808 Rect.bottom-Rect.top+1);
\r
3809 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3810 if (!appData.monoMode) {
\r
3811 SelectPalette(hdcmem, hPal, FALSE);
\r
3814 /* Create clips for dragging */
\r
3815 if (!fullrepaint) {
\r
3816 if (dragInfo.from.x >= 0) {
\r
3817 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3818 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3820 if (dragInfo.start.x >= 0) {
\r
3821 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3822 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3824 if (dragInfo.pos.x >= 0) {
\r
3825 x = dragInfo.pos.x - squareSize / 2;
\r
3826 y = dragInfo.pos.y - squareSize / 2;
\r
3827 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3829 if (dragInfo.lastpos.x >= 0) {
\r
3830 x = dragInfo.lastpos.x - squareSize / 2;
\r
3831 y = dragInfo.lastpos.y - squareSize / 2;
\r
3832 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3836 /* If dragging is in progress, we temporarely remove the piece */
\r
3837 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3838 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3839 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3842 /* Are we animating a move?
\r
3844 * - remove the piece from the board (temporarely)
\r
3845 * - calculate the clipping region
\r
3847 if (!fullrepaint) {
\r
3848 if (animInfo.piece != EmptySquare) {
\r
3849 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3850 x = boardRect.left + animInfo.lastpos.x;
\r
3851 y = boardRect.top + animInfo.lastpos.y;
\r
3852 x2 = boardRect.left + animInfo.pos.x;
\r
3853 y2 = boardRect.top + animInfo.pos.y;
\r
3854 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3855 /* Slight kludge. The real problem is that after AnimateMove is
\r
3856 done, the position on the screen does not match lastDrawn.
\r
3857 This currently causes trouble only on e.p. captures in
\r
3858 atomic, where the piece moves to an empty square and then
\r
3859 explodes. The old and new positions both had an empty square
\r
3860 at the destination, but animation has drawn a piece there and
\r
3861 we have to remember to erase it. */
\r
3862 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3866 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3867 if (num_clips == 0)
\r
3868 fullrepaint = TRUE;
\r
3870 /* Set clipping on the memory DC */
\r
3871 if (!fullrepaint) {
\r
3872 SelectClipRgn(hdcmem, clips[0]);
\r
3873 for (x = 1; x < num_clips; x++) {
\r
3874 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3875 abort(); // this should never ever happen!
\r
3879 /* Do all the drawing to the memory DC */
\r
3880 DrawGridOnDC(hdcmem);
\r
3881 DrawHighlightsOnDC(hdcmem);
\r
3882 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3884 if( appData.highlightMoveWithArrow ) {
3885 DrawArrowHighlight(hdcmem);
3888 DrawCoordsOnDC(hdcmem);
\r
3890 /* Put the dragged piece back into place and draw it */
\r
3891 if (dragged_piece != EmptySquare) {
\r
3892 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3893 x = dragInfo.pos.x - squareSize / 2;
\r
3894 y = dragInfo.pos.y - squareSize / 2;
\r
3895 DrawPieceOnDC(hdcmem, dragged_piece,
\r
3896 ((int) dragged_piece < (int) BlackPawn),
\r
3897 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3900 /* Put the animated piece back into place and draw it */
\r
3901 if (animInfo.piece != EmptySquare) {
\r
3902 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3903 x = boardRect.left + animInfo.pos.x;
\r
3904 y = boardRect.top + animInfo.pos.y;
\r
3905 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3906 ((int) animInfo.piece < (int) BlackPawn),
\r
3907 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3910 /* Release the bufferBitmap by selecting in the old bitmap
\r
3911 * and delete the memory DC
\r
3913 SelectObject(hdcmem, oldBitmap);
\r
3916 /* Set clipping on the target DC */
\r
3917 if (!fullrepaint) {
\r
3918 SelectClipRgn(hdc, clips[0]);
\r
3919 for (x = 1; x < num_clips; x++) {
\r
3920 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3921 abort(); // this should never ever happen!
\r
3925 /* Copy the new bitmap onto the screen in one go.
\r
3926 * This way we avoid any flickering
\r
3928 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3929 BitBlt(hdc, boardRect.left, boardRect.top,
\r
3930 boardRect.right - boardRect.left,
\r
3931 boardRect.bottom - boardRect.top,
\r
3932 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3933 SelectObject(tmphdc, oldBitmap);
\r
3935 /* Massive cleanup */
\r
3936 for (x = 0; x < num_clips; x++)
\r
3937 DeleteObject(clips[x]);
\r
3940 DeleteObject(bufferBitmap);
\r
3943 ReleaseDC(hwndMain, hdc);
\r
3945 if (lastDrawnFlipView != flipView) {
\r
3947 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
3949 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
3952 CopyBoard(lastDrawn, board);
\r
3953 lastDrawnHighlight = highlightInfo;
\r
3954 lastDrawnPremove = premoveHighlightInfo;
\r
3955 lastDrawnFlipView = flipView;
\r
3956 lastDrawnValid = 1;
\r
3960 /*---------------------------------------------------------------------------*\
\r
3961 | CLIENT PAINT PROCEDURE
\r
3962 | This is the main event-handler for the WM_PAINT message.
\r
3964 \*---------------------------------------------------------------------------*/
\r
3966 PaintProc(HWND hwnd)
\r
3972 if(hdc = BeginPaint(hwnd, &ps)) {
\r
3973 if (IsIconic(hwnd)) {
\r
3974 DrawIcon(hdc, 2, 2, iconCurrent);
\r
3976 if (!appData.monoMode) {
\r
3977 SelectPalette(hdc, hPal, FALSE);
\r
3978 RealizePalette(hdc);
\r
3980 HDCDrawPosition(hdc, 1, NULL);
\r
3982 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3983 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
3984 ETO_CLIPPED|ETO_OPAQUE,
\r
3985 &messageRect, messageText, strlen(messageText), NULL);
\r
3986 SelectObject(hdc, oldFont);
\r
3987 DisplayBothClocks();
\r
3989 EndPaint(hwnd,&ps);
\r
3997 * If the user selects on a border boundary, return -1; if off the board,
\r
3998 * return -2. Otherwise map the event coordinate to the square.
\r
3999 * The offset boardRect.left or boardRect.top must already have been
\r
4000 * subtracted from x.
\r
4003 EventToSquare(int x)
\r
4010 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4012 x /= (squareSize + lineGap);
\r
4013 if (x >= BOARD_SIZE)
\r
4024 DropEnable dropEnables[] = {
\r
4025 { 'P', DP_Pawn, "Pawn" },
\r
4026 { 'N', DP_Knight, "Knight" },
\r
4027 { 'B', DP_Bishop, "Bishop" },
\r
4028 { 'R', DP_Rook, "Rook" },
\r
4029 { 'Q', DP_Queen, "Queen" },
\r
4033 SetupDropMenu(HMENU hmenu)
\r
4035 int i, count, enable;
\r
4037 extern char white_holding[], black_holding[];
\r
4038 char item[MSG_SIZ];
\r
4040 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4041 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4042 dropEnables[i].piece);
\r
4044 while (p && *p++ == dropEnables[i].piece) count++;
\r
4045 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4046 enable = count > 0 || !appData.testLegality
\r
4047 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4048 && !appData.icsActive);
\r
4049 ModifyMenu(hmenu, dropEnables[i].command,
\r
4050 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4051 dropEnables[i].command, item);
\r
4055 static int fromX = -1, fromY = -1, toX, toY;
\r
4057 /* Event handler for mouse messages */
\r
4059 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4063 static int recursive = 0;
\r
4065 BOOLEAN needsRedraw = FALSE;
4066 BOOLEAN saveAnimate;
\r
4067 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
4068 static BOOLEAN sameAgain = FALSE;
\r
4071 if (message == WM_MBUTTONUP) {
\r
4072 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4073 to the middle button: we simulate pressing the left button too!
\r
4075 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4076 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4082 pt.x = LOWORD(lParam);
\r
4083 pt.y = HIWORD(lParam);
\r
4084 x = EventToSquare(pt.x - boardRect.left);
\r
4085 y = EventToSquare(pt.y - boardRect.top);
\r
4086 if (!flipView && y >= 0) {
\r
4087 y = BOARD_SIZE - 1 - y;
\r
4089 if (flipView && x >= 0) {
\r
4090 x = BOARD_SIZE - 1 - x;
\r
4093 switch (message) {
\r
4094 case WM_LBUTTONDOWN:
\r
4096 sameAgain = FALSE;
\r
4098 /* Downclick vertically off board; check if on clock */
\r
4099 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4100 if (gameMode == EditPosition) {
\r
4101 SetWhiteToPlayEvent();
\r
4102 } else if (gameMode == IcsPlayingBlack ||
\r
4103 gameMode == MachinePlaysWhite) {
\r
4106 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4107 if (gameMode == EditPosition) {
\r
4108 SetBlackToPlayEvent();
\r
4109 } else if (gameMode == IcsPlayingWhite ||
\r
4110 gameMode == MachinePlaysBlack) {
\r
4114 if (!appData.highlightLastMove) {
\r
4115 ClearHighlights();
\r
4116 DrawPosition(forceFullRepaint || FALSE, NULL);
4118 fromX = fromY = -1;
\r
4119 dragInfo.start.x = dragInfo.start.y = -1;
\r
4120 dragInfo.from = dragInfo.start;
\r
4122 } else if (x < 0 || y < 0) {
\r
4124 } else if (fromX == x && fromY == y) {
\r
4125 /* Downclick on same square again */
\r
4126 ClearHighlights();
\r
4127 DrawPosition(forceFullRepaint || FALSE, NULL);
4128 sameAgain = TRUE;
\r
4129 } else if (fromX != -1) {
\r
4130 /* Downclick on different square */
\r
4131 ChessSquare pdown, pup;
\r
4132 pdown = boards[currentMove][fromY][fromX];
\r
4133 pup = boards[currentMove][y][x];
\r
4134 if (gameMode == EditPosition ||
\r
4135 !((WhitePawn <= pdown && pdown <= WhiteKing &&
\r
4136 WhitePawn <= pup && pup <= WhiteKing) ||
\r
4137 (BlackPawn <= pdown && pdown <= BlackKing &&
\r
4138 BlackPawn <= pup && pup <= BlackKing))) {
\r
4139 /* EditPosition, empty square, or different color piece;
\r
4140 click-click move is possible */
\r
4143 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
4144 if (appData.alwaysPromoteToQueen) {
\r
4145 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
4146 if (!appData.highlightLastMove) {
\r
4147 ClearHighlights();
\r
4148 DrawPosition(forceFullRepaint || FALSE, NULL);
4151 SetHighlights(fromX, fromY, toX, toY);
\r
4152 DrawPosition(forceFullRepaint || FALSE, NULL);
4153 PromotionPopup(hwnd);
\r
4155 } else { /* not a promotion */
\r
4156 if (appData.animate || appData.highlightLastMove) {
\r
4157 SetHighlights(fromX, fromY, toX, toY);
\r
4159 ClearHighlights();
\r
4161 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
4162 if (appData.animate && !appData.highlightLastMove) {
\r
4163 ClearHighlights();
\r
4164 DrawPosition(forceFullRepaint || FALSE, NULL);
4167 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4168 fromX = fromY = -1;
\r
4171 ClearHighlights();
\r
4172 DrawPosition(forceFullRepaint || FALSE, NULL);
4174 /* First downclick, or restart on a square with same color piece */
\r
4175 if (!frozen && OKToStartUserMove(x, y)) {
\r
4178 dragInfo.lastpos = pt;
\r
4179 dragInfo.from.x = fromX;
\r
4180 dragInfo.from.y = fromY;
\r
4181 dragInfo.start = dragInfo.from;
\r
4182 SetCapture(hwndMain);
\r
4184 fromX = fromY = -1;
\r
4185 dragInfo.start.x = dragInfo.start.y = -1;
\r
4186 dragInfo.from = dragInfo.start;
\r
4187 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
4191 case WM_LBUTTONUP:
\r
4193 if (fromX == -1) break;
\r
4194 if (x == fromX && y == fromY) {
\r
4195 dragInfo.from.x = dragInfo.from.y = -1;
\r
4196 /* Upclick on same square */
\r
4198 /* Clicked same square twice: abort click-click move */
\r
4199 fromX = fromY = -1;
\r
4201 ClearPremoveHighlights();
\r
4203 /* First square clicked: start click-click move */
\r
4204 SetHighlights(fromX, fromY, -1, -1);
\r
4206 DrawPosition(forceFullRepaint || FALSE, NULL);
4207 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4208 /* Errant click; ignore */
\r
4211 /* Finish drag move */
\r
4212 dragInfo.from.x = dragInfo.from.y = -1;
\r
4215 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4216 appData.animate = appData.animate && !appData.animateDragging;
\r
4217 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
4218 if (appData.alwaysPromoteToQueen) {
\r
4219 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
4221 DrawPosition(forceFullRepaint || FALSE, NULL);
4222 PromotionPopup(hwnd);
\r
4225 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
4227 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4228 appData.animate = saveAnimate;
\r
4229 fromX = fromY = -1;
\r
4230 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
4231 ClearHighlights();
\r
4233 if (appData.animate || appData.animateDragging ||
\r
4234 appData.highlightDragging || gotPremove) {
\r
4235 DrawPosition(forceFullRepaint || FALSE, NULL);
4238 dragInfo.start.x = dragInfo.start.y = -1;
\r
4239 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4242 case WM_MOUSEMOVE:
\r
4243 if ((appData.animateDragging || appData.highlightDragging)
\r
4244 && (wParam & MK_LBUTTON)
\r
4245 && dragInfo.from.x >= 0)
4247 BOOL full_repaint = FALSE;
4249 if (appData.animateDragging) {
\r
4250 dragInfo.pos = pt;
\r
4252 if (appData.highlightDragging) {
\r
4253 SetHighlights(fromX, fromY, x, y);
\r
4254 if( IsDrawArrowEnabled() && (x < 0 || x > 7 || y < 0 || y > y) ) {
4255 full_repaint = TRUE;
4259 DrawPosition( full_repaint, NULL);
4261 dragInfo.lastpos = dragInfo.pos;
\r
4265 case WM_MBUTTONDOWN:
\r
4266 case WM_RBUTTONDOWN:
\r
4269 fromX = fromY = -1;
\r
4270 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4271 dragInfo.start.x = dragInfo.start.y = -1;
\r
4272 dragInfo.from = dragInfo.start;
\r
4273 dragInfo.lastpos = dragInfo.pos;
\r
4274 if (appData.highlightDragging) {
\r
4275 ClearHighlights();
\r
4277 DrawPosition(TRUE, NULL);
\r
4279 switch (gameMode) {
\r
4280 case EditPosition:
\r
4281 case IcsExamining:
\r
4282 if (x < 0 || y < 0) break;
\r
4285 if (message == WM_MBUTTONDOWN) {
\r
4286 buttonCount = 3; /* even if system didn't think so */
\r
4287 if (wParam & MK_SHIFT)
\r
4288 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4290 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4291 } else { /* message == WM_RBUTTONDOWN */
\r
4293 if (buttonCount == 3) {
\r
4294 if (wParam & MK_SHIFT)
\r
4295 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4297 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4299 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4302 /* Just have one menu, on the right button. Windows users don't
\r
4303 think to try the middle one, and sometimes other software steals
\r
4304 it, or it doesn't really exist. */
\r
4305 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4309 case IcsPlayingWhite:
\r
4310 case IcsPlayingBlack:
\r
4312 case MachinePlaysWhite:
\r
4313 case MachinePlaysBlack:
\r
4314 if (appData.testLegality &&
\r
4315 gameInfo.variant != VariantBughouse &&
\r
4316 gameInfo.variant != VariantCrazyhouse) break;
\r
4317 if (x < 0 || y < 0) break;
\r
4320 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4321 SetupDropMenu(hmenu);
\r
4322 MenuPopup(hwnd, pt, hmenu, -1);
\r
4333 /* Preprocess messages for buttons in main window */
\r
4335 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4337 int id = GetWindowLong(hwnd, GWL_ID);
\r
4340 for (i=0; i<N_BUTTONS; i++) {
\r
4341 if (buttonDesc[i].id == id) break;
\r
4343 if (i == N_BUTTONS) return 0;
\r
4344 switch (message) {
\r
4349 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4350 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4357 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4360 if (appData.icsActive) {
\r
4361 if (GetKeyState(VK_SHIFT) < 0) {
\r
4363 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4364 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4368 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4369 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4376 if (appData.icsActive) {
\r
4377 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4378 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4380 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4382 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4383 PopUpMoveDialog((char)wParam);
\r
4389 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4392 /* Process messages for Promotion dialog box */
\r
4394 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4398 switch (message) {
\r
4399 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4400 /* Center the dialog over the application window */
\r
4401 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4402 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4403 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4404 gameInfo.variant == VariantGiveaway) ?
\r
4405 SW_SHOW : SW_HIDE);
\r
4408 case WM_COMMAND: /* message: received a command */
\r
4409 switch (LOWORD(wParam)) {
\r
4411 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4412 ClearHighlights();
\r
4413 DrawPosition(FALSE, NULL);
\r
4433 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4434 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4435 if (!appData.highlightLastMove) {
\r
4436 ClearHighlights();
\r
4437 DrawPosition(FALSE, NULL);
\r
4444 /* Pop up promotion dialog */
\r
4446 PromotionPopup(HWND hwnd)
\r
4450 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4451 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4452 hwnd, (DLGPROC)lpProc);
\r
4453 FreeProcInstance(lpProc);
\r
4456 /* Toggle ShowThinking */
\r
4458 ToggleShowThinking()
\r
4460 ShowThinkingEvent(!appData.showThinking);
\r
4464 LoadGameDialog(HWND hwnd, char* title)
\r
4468 char fileTitle[MSG_SIZ];
\r
4469 f = OpenFileDialog(hwnd, FALSE, "",
\r
4470 appData.oldSaveStyle ? "gam" : "pgn",
\r
4472 title, &number, fileTitle, NULL);
\r
4474 cmailMsgLoaded = FALSE;
\r
4475 if (number == 0) {
\r
4476 int error = GameListBuild(f);
\r
4478 DisplayError("Cannot build game list", error);
\r
4479 } else if (!ListEmpty(&gameList) &&
\r
4480 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4481 GameListPopUp(f, fileTitle);
\r
4484 GameListDestroy();
\r
4487 LoadGame(f, number, fileTitle, FALSE);
\r
4492 ChangedConsoleFont()
\r
4495 CHARRANGE tmpsel, sel;
\r
4496 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4497 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4498 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4501 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4502 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4503 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4504 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4505 * size. This was undocumented in the version of MSVC++ that I had
\r
4506 * when I wrote the code, but is apparently documented now.
\r
4508 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4509 cfmt.bCharSet = f->lf.lfCharSet;
\r
4510 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4511 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4512 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4513 /* Why are the following seemingly needed too? */
\r
4514 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4515 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4516 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4518 tmpsel.cpMax = -1; /*999999?*/
\r
4519 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4520 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4521 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4522 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4524 paraf.cbSize = sizeof(paraf);
\r
4525 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4526 paraf.dxStartIndent = 0;
\r
4527 paraf.dxOffset = WRAP_INDENT;
\r
4528 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4529 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4532 /*---------------------------------------------------------------------------*\
\r
4534 * Window Proc for main window
\r
4536 \*---------------------------------------------------------------------------*/
\r
4538 /* Process messages for main window, etc. */
\r
4540 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4543 int wmId, wmEvent;
\r
4547 char fileTitle[MSG_SIZ];
\r
4550 switch (message) {
\r
4552 case WM_PAINT: /* message: repaint portion of window */
\r
4556 case WM_ERASEBKGND:
\r
4557 if (IsIconic(hwnd)) {
\r
4558 /* Cheat; change the message */
\r
4559 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4561 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4565 case WM_LBUTTONDOWN:
\r
4566 case WM_MBUTTONDOWN:
\r
4567 case WM_RBUTTONDOWN:
\r
4568 case WM_LBUTTONUP:
\r
4569 case WM_MBUTTONUP:
\r
4570 case WM_RBUTTONUP:
\r
4571 case WM_MOUSEMOVE:
\r
4572 MouseEvent(hwnd, message, wParam, lParam);
\r
4577 if (appData.icsActive) {
\r
4578 if (wParam == '\t') {
\r
4579 if (GetKeyState(VK_SHIFT) < 0) {
\r
4581 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4582 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4586 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4587 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4591 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4592 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4594 SendMessage(h, message, wParam, lParam);
\r
4596 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4597 PopUpMoveDialog((char)wParam);
\r
4601 case WM_PALETTECHANGED:
\r
4602 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4604 HDC hdc = GetDC(hwndMain);
\r
4605 SelectPalette(hdc, hPal, TRUE);
\r
4606 nnew = RealizePalette(hdc);
\r
4608 paletteChanged = TRUE;
\r
4610 UpdateColors(hdc);
\r
4612 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
4615 ReleaseDC(hwnd, hdc);
\r
4619 case WM_QUERYNEWPALETTE:
\r
4620 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4622 HDC hdc = GetDC(hwndMain);
\r
4623 paletteChanged = FALSE;
\r
4624 SelectPalette(hdc, hPal, FALSE);
\r
4625 nnew = RealizePalette(hdc);
\r
4627 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4629 ReleaseDC(hwnd, hdc);
\r
4634 case WM_COMMAND: /* message: command from application menu */
\r
4635 wmId = LOWORD(wParam);
\r
4636 wmEvent = HIWORD(wParam);
\r
4641 AnalysisPopDown();
\r
4644 case IDM_NewGameFRC:
4645 if( NewGameFRC() == 0 ) {
4651 case IDM_LoadGame:
\r
4652 LoadGameDialog(hwnd, "Load Game from File");
\r
4655 case IDM_LoadNextGame:
\r
4659 case IDM_LoadPrevGame:
\r
4663 case IDM_ReloadGame:
\r
4667 case IDM_LoadPosition:
\r
4668 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4669 Reset(FALSE, TRUE);
\r
4672 f = OpenFileDialog(hwnd, FALSE, "",
\r
4673 appData.oldSaveStyle ? "pos" : "fen",
\r
4675 "Load Position from File", &number, fileTitle, NULL);
\r
4677 LoadPosition(f, number, fileTitle);
\r
4681 case IDM_LoadNextPosition:
\r
4682 ReloadPosition(1);
\r
4685 case IDM_LoadPrevPosition:
\r
4686 ReloadPosition(-1);
\r
4689 case IDM_ReloadPosition:
\r
4690 ReloadPosition(0);
\r
4693 case IDM_SaveGame:
\r
4694 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4695 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4696 appData.oldSaveStyle ? "gam" : "pgn",
\r
4698 "Save Game to File", NULL, fileTitle, NULL);
\r
4700 SaveGame(f, 0, "");
\r
4704 case IDM_SavePosition:
\r
4705 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4706 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4707 appData.oldSaveStyle ? "pos" : "fen",
\r
4709 "Save Position to File", NULL, fileTitle, NULL);
\r
4711 SavePosition(f, 0, "");
\r
4715 case IDM_CopyGame:
\r
4716 CopyGameToClipboard();
\r
4719 case IDM_PasteGame:
\r
4720 PasteGameFromClipboard();
\r
4723 case IDM_CopyGameListToClipboard:
4724 CopyGameListToClipboard();
4727 /* [AS] Autodetect FEN or PGN data */
4729 PasteGameOrFENFromClipboard();
4732 /* [AS] Move history */
4733 case IDM_ShowMoveHistory:
4734 if( MoveHistoryIsUp() ) {
4735 MoveHistoryPopDown();
4742 /* [AS] Eval graph */
4743 case IDM_ShowEvalGraph:
4744 if( EvalGraphIsUp() ) {
4752 /* [AS] Engine output */
4753 case IDM_ShowEngineOutput:
4754 if( EngineOutputIsUp() ) {
4755 EngineOutputPopDown();
4758 EngineOutputPopUp();
4762 /* [AS] User adjudication */
4763 case IDM_UserAdjudication_White:
4764 UserAdjudicationEvent( +1 );
4767 case IDM_UserAdjudication_Black:
4768 UserAdjudicationEvent( -1 );
4771 case IDM_UserAdjudication_Draw:
4772 UserAdjudicationEvent( 0 );
4775 /* [AS] Game list options dialog */
4776 case IDM_GameListOptions:
4780 case IDM_CopyPosition:
\r
4781 CopyFENToClipboard();
\r
4784 case IDM_PastePosition:
\r
4785 PasteFENFromClipboard();
\r
4788 case IDM_MailMove:
\r
4792 case IDM_ReloadCMailMsg:
\r
4793 Reset(TRUE, TRUE);
\r
4794 ReloadCmailMsgEvent(FALSE);
\r
4797 case IDM_Minimize:
\r
4798 ShowWindow(hwnd, SW_MINIMIZE);
\r
4805 case IDM_MachineWhite:
\r
4806 MachineWhiteEvent();
\r
4808 * refresh the tags dialog only if it's visible
\r
4810 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4812 tags = PGNTags(&gameInfo);
\r
4813 TagsPopUp(tags, CmailMsg());
\r
4818 case IDM_MachineBlack:
\r
4819 MachineBlackEvent();
\r
4821 * refresh the tags dialog only if it's visible
\r
4823 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
4825 tags = PGNTags(&gameInfo);
\r
4826 TagsPopUp(tags, CmailMsg());
\r
4831 case IDM_TwoMachines:
\r
4832 TwoMachinesEvent();
\r
4834 * refresh the tags dialog only if it's visible
\r
4836 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
4838 tags = PGNTags(&gameInfo);
\r
4839 TagsPopUp(tags, CmailMsg());
\r
4844 case IDM_AnalysisMode:
\r
4845 if (!first.analysisSupport) {
\r
4846 char buf[MSG_SIZ];
\r
4847 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4848 DisplayError(buf, 0);
\r
4850 if (!appData.showThinking) ToggleShowThinking();
\r
4851 AnalyzeModeEvent();
\r
4855 case IDM_AnalyzeFile:
\r
4856 if (!first.analysisSupport) {
\r
4857 char buf[MSG_SIZ];
\r
4858 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4859 DisplayError(buf, 0);
\r
4861 if (!appData.showThinking) ToggleShowThinking();
\r
4862 AnalyzeFileEvent();
\r
4863 LoadGameDialog(hwnd, "Analyze Game from File");
\r
4864 AnalysisPeriodicEvent(1);
\r
4868 case IDM_IcsClient:
\r
4872 case IDM_EditGame:
\r
4876 case IDM_EditPosition:
\r
4877 EditPositionEvent();
\r
4880 case IDM_Training:
\r
4884 case IDM_ShowGameList:
\r
4885 ShowGameListProc();
\r
4888 case IDM_EditTags:
\r
4892 case IDM_EditComment:
\r
4893 if (commentDialogUp && editComment) {
\r
4896 EditCommentEvent();
\r
4916 case IDM_CallFlag:
\r
4936 case IDM_StopObserving:
\r
4937 StopObservingEvent();
\r
4940 case IDM_StopExamining:
\r
4941 StopExaminingEvent();
\r
4944 case IDM_TypeInMove:
\r
4945 PopUpMoveDialog('\000');
\r
4948 case IDM_Backward:
\r
4950 SetFocus(hwndMain);
\r
4955 SetFocus(hwndMain);
\r
4960 SetFocus(hwndMain);
\r
4965 SetFocus(hwndMain);
\r
4972 case IDM_TruncateGame:
\r
4973 TruncateGameEvent();
\r
4980 case IDM_RetractMove:
\r
4981 RetractMoveEvent();
\r
4984 case IDM_FlipView:
\r
4985 flipView = !flipView;
\r
4986 DrawPosition(FALSE, NULL);
\r
4989 case IDM_GeneralOptions:
\r
4990 GeneralOptionsPopup(hwnd);
\r
4991 DrawPosition(TRUE, NULL);
4994 case IDM_BoardOptions:
\r
4995 BoardOptionsPopup(hwnd);
\r
4998 case IDM_EnginePlayOptions:
4999 EnginePlayOptionsPopup(hwnd);
5002 case IDM_OptionsUCI:
5003 UciOptionsPopup(hwnd);
5006 case IDM_IcsOptions:
\r
5007 IcsOptionsPopup(hwnd);
\r
5011 FontsOptionsPopup(hwnd);
\r
5015 SoundOptionsPopup(hwnd);
\r
5018 case IDM_CommPort:
\r
5019 CommPortOptionsPopup(hwnd);
\r
5022 case IDM_LoadOptions:
\r
5023 LoadOptionsPopup(hwnd);
\r
5026 case IDM_SaveOptions:
\r
5027 SaveOptionsPopup(hwnd);
\r
5030 case IDM_TimeControl:
\r
5031 TimeControlOptionsPopup(hwnd);
\r
5034 case IDM_SaveSettings:
\r
5035 SaveSettings(settingsFileName);
\r
5038 case IDM_SaveSettingsOnExit:
\r
5039 saveSettingsOnExit = !saveSettingsOnExit;
\r
5040 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5041 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5042 MF_CHECKED : MF_UNCHECKED));
\r
5053 case IDM_AboutGame:
\r
5058 appData.debugMode = !appData.debugMode;
\r
5059 if (appData.debugMode) {
\r
5060 char dir[MSG_SIZ];
\r
5061 GetCurrentDirectory(MSG_SIZ, dir);
\r
5062 SetCurrentDirectory(installDir);
\r
5063 debugFP = fopen(appData.nameOfDebugFile, "w");
5064 SetCurrentDirectory(dir);
\r
5065 setbuf(debugFP, NULL);
\r
5072 case IDM_HELPCONTENTS:
\r
5073 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5074 MessageBox (GetFocus(),
\r
5075 "Unable to activate help",
\r
5076 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5080 case IDM_HELPSEARCH:
\r
5081 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5082 MessageBox (GetFocus(),
\r
5083 "Unable to activate help",
\r
5084 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5088 case IDM_HELPHELP:
\r
5089 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5090 MessageBox (GetFocus(),
\r
5091 "Unable to activate help",
\r
5092 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5097 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5099 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5100 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5101 FreeProcInstance(lpProc);
\r
5104 case IDM_DirectCommand1:
\r
5105 AskQuestionEvent("Direct Command",
\r
5106 "Send to chess program:", "", "1");
\r
5108 case IDM_DirectCommand2:
\r
5109 AskQuestionEvent("Direct Command",
\r
5110 "Send to second chess program:", "", "2");
\r
5113 case EP_WhitePawn:
\r
5114 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5115 fromX = fromY = -1;
\r
5118 case EP_WhiteKnight:
\r
5119 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5120 fromX = fromY = -1;
\r
5123 case EP_WhiteBishop:
\r
5124 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5125 fromX = fromY = -1;
\r
5128 case EP_WhiteRook:
\r
5129 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5130 fromX = fromY = -1;
\r
5133 case EP_WhiteQueen:
\r
5134 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5135 fromX = fromY = -1;
\r
5138 case EP_WhiteKing:
\r
5139 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5140 fromX = fromY = -1;
\r
5143 case EP_BlackPawn:
\r
5144 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5145 fromX = fromY = -1;
\r
5148 case EP_BlackKnight:
\r
5149 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5150 fromX = fromY = -1;
\r
5153 case EP_BlackBishop:
\r
5154 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5155 fromX = fromY = -1;
\r
5158 case EP_BlackRook:
\r
5159 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5160 fromX = fromY = -1;
\r
5163 case EP_BlackQueen:
\r
5164 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5165 fromX = fromY = -1;
\r
5168 case EP_BlackKing:
\r
5169 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5170 fromX = fromY = -1;
\r
5173 case EP_EmptySquare:
\r
5174 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5175 fromX = fromY = -1;
\r
5178 case EP_ClearBoard:
\r
5179 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5180 fromX = fromY = -1;
\r
5184 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5185 fromX = fromY = -1;
\r
5189 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5190 fromX = fromY = -1;
\r
5194 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5195 fromX = fromY = -1;
\r
5199 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5200 fromX = fromY = -1;
\r
5204 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5205 fromX = fromY = -1;
\r
5209 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5210 fromX = fromY = -1;
\r
5214 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5215 fromX = fromY = -1;
\r
5219 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5225 case CLOCK_TIMER_ID:
\r
5226 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5227 clockTimerEvent = 0;
\r
5228 DecrementClocks(); /* call into back end */
\r
5230 case LOAD_GAME_TIMER_ID:
\r
5231 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5232 loadGameTimerEvent = 0;
\r
5233 AutoPlayGameLoop(); /* call into back end */
\r
5235 case ANALYSIS_TIMER_ID:
\r
5236 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
5237 appData.periodicUpdates) {
\r
5238 AnalysisPeriodicEvent(0);
\r
5240 KillTimer(hwnd, analysisTimerEvent);
\r
5241 analysisTimerEvent = 0;
\r
5244 case DELAYED_TIMER_ID:
\r
5245 KillTimer(hwnd, delayedTimerEvent);
\r
5246 delayedTimerEvent = 0;
\r
5247 delayedTimerCallback();
\r
5252 case WM_USER_Input:
\r
5253 InputEvent(hwnd, message, wParam, lParam);
\r
5256 /* [AS] Also move "attached" child windows */
5257 case WM_WINDOWPOSCHANGING:
5258 if( hwnd == hwndMain && appData.useStickyWindows ) {
5259 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
5261 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
5262 /* Window is moving */
5265 GetWindowRect( hwnd, &rcMain );
5267 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
5268 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
5269 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
5275 case WM_ENTERSIZEMOVE:
\r
5276 if (hwnd == hwndMain) {
\r
5277 doingSizing = TRUE;
\r
5280 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
5284 if (hwnd == hwndMain) {
\r
5285 lastSizing = wParam;
\r
5290 return OnMoving( &sd, hwnd, wParam, lParam );
5292 case WM_EXITSIZEMOVE:
\r
5293 if (hwnd == hwndMain) {
\r
5295 doingSizing = FALSE;
\r
5296 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5297 GetClientRect(hwnd, &client);
\r
5298 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5301 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
5304 case WM_DESTROY: /* message: window being destroyed */
\r
5305 PostQuitMessage(0);
\r
5309 if (hwnd == hwndMain) {
\r
5314 default: /* Passes it on if unprocessed */
\r
5315 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5320 /*---------------------------------------------------------------------------*\
\r
5322 * Misc utility routines
\r
5324 \*---------------------------------------------------------------------------*/
\r
5327 * Decent random number generator, at least not as bad as Windows
\r
5328 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5330 unsigned int randstate;
\r
5335 randstate = randstate * 1664525 + 1013904223;
\r
5336 return (int) randstate & 0x7fffffff;
\r
5340 mysrandom(unsigned int seed)
\r
5347 * returns TRUE if user selects a different color, FALSE otherwise
\r
5351 ChangeColor(HWND hwnd, COLORREF *which)
\r
5353 static BOOL firstTime = TRUE;
\r
5354 static DWORD customColors[16];
\r
5356 COLORREF newcolor;
\r
5361 /* Make initial colors in use available as custom colors */
\r
5362 /* Should we put the compiled-in defaults here instead? */
\r
5364 customColors[i++] = lightSquareColor & 0xffffff;
\r
5365 customColors[i++] = darkSquareColor & 0xffffff;
\r
5366 customColors[i++] = whitePieceColor & 0xffffff;
\r
5367 customColors[i++] = blackPieceColor & 0xffffff;
\r
5368 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5369 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5371 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5372 customColors[i++] = textAttribs[ccl].color;
\r
5374 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5375 firstTime = FALSE;
\r
5378 cc.lStructSize = sizeof(cc);
\r
5379 cc.hwndOwner = hwnd;
\r
5380 cc.hInstance = NULL;
\r
5381 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5382 cc.lpCustColors = (LPDWORD) customColors;
\r
5383 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5385 if (!ChooseColor(&cc)) return FALSE;
\r
5387 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5388 if (newcolor == *which) return FALSE;
\r
5389 *which = newcolor;
\r
5393 InitDrawingColors();
\r
5394 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5399 MyLoadSound(MySound *ms)
\r
5405 if (ms->data) free(ms->data);
\r
5408 switch (ms->name[0]) {
\r
5414 /* System sound from Control Panel. Don't preload here. */
\r
5418 if (ms->name[1] == NULLCHAR) {
\r
5419 /* "!" alone = silence */
\r
5422 /* Builtin wave resource. Error if not found. */
\r
5423 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5424 if (h == NULL) break;
\r
5425 ms->data = (void *)LoadResource(hInst, h);
\r
5426 if (h == NULL) break;
\r
5431 /* .wav file. Error if not found. */
\r
5432 f = fopen(ms->name, "rb");
\r
5433 if (f == NULL) break;
\r
5434 if (fstat(fileno(f), &st) < 0) break;
\r
5435 ms->data = malloc(st.st_size);
\r
5436 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5442 char buf[MSG_SIZ];
\r
5443 sprintf(buf, "Error loading sound %s", ms->name);
\r
5444 DisplayError(buf, GetLastError());
\r
5450 MyPlaySound(MySound *ms)
\r
5452 BOOLEAN ok = FALSE;
\r
5453 switch (ms->name[0]) {
\r
5459 /* System sound from Control Panel (deprecated feature).
\r
5460 "$" alone or an unset sound name gets default beep (still in use). */
\r
5461 if (ms->name[1]) {
\r
5462 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5464 if (!ok) ok = MessageBeep(MB_OK);
\r
5467 /* Builtin wave resource, or "!" alone for silence */
\r
5468 if (ms->name[1]) {
\r
5469 if (ms->data == NULL) return FALSE;
\r
5470 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5476 /* .wav file. Error if not found. */
\r
5477 if (ms->data == NULL) return FALSE;
\r
5478 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5481 /* Don't print an error: this can happen innocently if the sound driver
\r
5482 is busy; for instance, if another instance of WinBoard is playing
\r
5483 a sound at about the same time. */
\r
5486 char buf[MSG_SIZ];
\r
5487 sprintf(buf, "Error playing sound %s", ms->name);
\r
5488 DisplayError(buf, GetLastError());
\r
5496 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5499 OPENFILENAME *ofn;
\r
5500 static UINT *number; /* gross that this is static */
\r
5502 switch (message) {
\r
5503 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5504 /* Center the dialog over the application window */
\r
5505 ofn = (OPENFILENAME *) lParam;
\r
5506 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5507 number = (UINT *) ofn->lCustData;
\r
5508 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5512 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5513 return FALSE; /* Allow for further processing */
\r
5516 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5517 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5519 return FALSE; /* Allow for further processing */
\r
5525 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5527 static UINT *number;
\r
5528 OPENFILENAME *ofname;
\r
5531 case WM_INITDIALOG:
\r
5532 ofname = (OPENFILENAME *)lParam;
\r
5533 number = (UINT *)(ofname->lCustData);
\r
5536 ofnot = (OFNOTIFY *)lParam;
\r
5537 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5538 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5547 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
5548 char *nameFilt, char *dlgTitle, UINT *number,
\r
5549 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5551 OPENFILENAME openFileName;
\r
5552 char buf1[MSG_SIZ];
\r
5555 if (fileName == NULL) fileName = buf1;
\r
5556 if (defName == NULL) {
\r
5557 strcpy(fileName, "*.");
\r
5558 strcat(fileName, defExt);
\r
5560 strcpy(fileName, defName);
\r
5562 if (fileTitle) strcpy(fileTitle, "");
\r
5563 if (number) *number = 0;
\r
5565 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5566 openFileName.hwndOwner = hwnd;
\r
5567 openFileName.hInstance = (HANDLE) hInst;
\r
5568 openFileName.lpstrFilter = nameFilt;
\r
5569 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5570 openFileName.nMaxCustFilter = 0L;
\r
5571 openFileName.nFilterIndex = 1L;
\r
5572 openFileName.lpstrFile = fileName;
\r
5573 openFileName.nMaxFile = MSG_SIZ;
\r
5574 openFileName.lpstrFileTitle = fileTitle;
\r
5575 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5576 openFileName.lpstrInitialDir = NULL;
\r
5577 openFileName.lpstrTitle = dlgTitle;
\r
5578 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5579 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
5580 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5581 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5582 openFileName.nFileOffset = 0;
\r
5583 openFileName.nFileExtension = 0;
\r
5584 openFileName.lpstrDefExt = defExt;
\r
5585 openFileName.lCustData = (LONG) number;
\r
5586 openFileName.lpfnHook = oldDialog ?
\r
5587 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5588 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5590 if (write ? GetSaveFileName(&openFileName) :
\r
5591 GetOpenFileName(&openFileName)) {
\r
5592 /* open the file */
\r
5593 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
5595 MessageBox(hwnd, "File open failed", NULL,
\r
5596 MB_OK|MB_ICONEXCLAMATION);
\r
5600 int err = CommDlgExtendedError();
\r
5601 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
5610 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5612 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5615 * Get the first pop-up menu in the menu template. This is the
\r
5616 * menu that TrackPopupMenu displays.
\r
5618 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5620 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5623 * TrackPopup uses screen coordinates, so convert the
\r
5624 * coordinates of the mouse click to screen coordinates.
\r
5626 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5628 /* Draw and track the floating pop-up menu. */
\r
5629 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5630 pt.x, pt.y, 0, hwnd, NULL);
\r
5632 /* Destroy the menu.*/
\r
5633 DestroyMenu(hmenu);
\r
5638 int sizeX, sizeY, newSizeX, newSizeY;
\r
5640 } ResizeEditPlusButtonsClosure;
\r
5643 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5645 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5649 if (hChild == cl->hText) return TRUE;
\r
5650 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5651 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5652 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5653 ScreenToClient(cl->hDlg, &pt);
\r
5654 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5655 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5659 /* Resize a dialog that has a (rich) edit field filling most of
\r
5660 the top, with a row of buttons below */
\r
5662 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
5665 int newTextHeight, newTextWidth;
\r
5666 ResizeEditPlusButtonsClosure cl;
\r
5668 /*if (IsIconic(hDlg)) return;*/
\r
5669 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
5671 cl.hdwp = BeginDeferWindowPos(8);
\r
5673 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
5674 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5675 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5676 if (newTextHeight < 0) {
\r
5677 newSizeY += -newTextHeight;
\r
5678 newTextHeight = 0;
\r
5680 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
5681 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5687 cl.newSizeX = newSizeX;
\r
5688 cl.newSizeY = newSizeY;
\r
5689 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
5691 EndDeferWindowPos(cl.hdwp);
\r
5694 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
5696 RECT rChild, rParent;
\r
5697 int wChild, hChild, wParent, hParent;
\r
5698 int wScreen, hScreen, xNew, yNew;
\r
5701 /* Get the Height and Width of the child window */
\r
5702 GetWindowRect (hwndChild, &rChild);
\r
5703 wChild = rChild.right - rChild.left;
\r
5704 hChild = rChild.bottom - rChild.top;
\r
5706 /* Get the Height and Width of the parent window */
\r
5707 GetWindowRect (hwndParent, &rParent);
\r
5708 wParent = rParent.right - rParent.left;
\r
5709 hParent = rParent.bottom - rParent.top;
\r
5711 /* Get the display limits */
\r
5712 hdc = GetDC (hwndChild);
\r
5713 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
5714 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
5715 ReleaseDC(hwndChild, hdc);
\r
5717 /* Calculate new X position, then adjust for screen */
\r
5718 xNew = rParent.left + ((wParent - wChild) /2);
\r
5721 } else if ((xNew+wChild) > wScreen) {
\r
5722 xNew = wScreen - wChild;
\r
5725 /* Calculate new Y position, then adjust for screen */
\r
5727 yNew = rParent.top + ((hParent - hChild) /2);
\r
5730 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
5735 } else if ((yNew+hChild) > hScreen) {
\r
5736 yNew = hScreen - hChild;
\r
5739 /* Set it, and return */
\r
5740 return SetWindowPos (hwndChild, NULL,
\r
5741 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
5744 /* Center one window over another */
5745 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
5747 return CenterWindowEx( hwndChild, hwndParent, 0 );
5750 /*---------------------------------------------------------------------------*\
\r
5752 * Startup Dialog functions
\r
5754 \*---------------------------------------------------------------------------*/
\r
5756 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
5758 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5760 while (*cd != NULL) {
\r
5761 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
5767 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
5769 char buf1[ARG_MAX];
\r
5772 if (str[0] == '@') {
\r
5773 FILE* f = fopen(str + 1, "r");
\r
5775 DisplayFatalError(str + 1, errno, 2);
\r
5778 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
5780 buf1[len] = NULLCHAR;
\r
5784 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5787 char buf[MSG_SIZ];
\r
5788 char *end = strchr(str, '\n');
\r
5789 if (end == NULL) return;
\r
5790 memcpy(buf, str, end - str);
\r
5791 buf[end - str] = NULLCHAR;
\r
5792 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
5798 SetStartupDialogEnables(HWND hDlg)
\r
5800 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5801 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5802 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5803 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5804 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
5805 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
5806 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5807 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
5808 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
5809 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
5810 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5811 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
5812 IsDlgButtonChecked(hDlg, OPT_View));
\r
5816 QuoteForFilename(char *filename)
\r
5818 int dquote, space;
\r
5819 dquote = strchr(filename, '"') != NULL;
\r
5820 space = strchr(filename, ' ') != NULL;
\r
5821 if (dquote || space) {
\r
5833 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
5835 char buf[MSG_SIZ];
\r
5838 InitComboStringsFromOption(hwndCombo, nthnames);
\r
5839 q = QuoteForFilename(nthcp);
\r
5840 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
5841 if (*nthdir != NULLCHAR) {
\r
5842 q = QuoteForFilename(nthdir);
\r
5843 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
5845 if (*nthcp == NULLCHAR) {
\r
5846 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5847 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5848 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5849 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5854 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5856 char buf[MSG_SIZ];
\r
5860 switch (message) {
\r
5861 case WM_INITDIALOG:
\r
5862 /* Center the dialog */
\r
5863 CenterWindow (hDlg, GetDesktopWindow());
\r
5864 /* Initialize the dialog items */
\r
5865 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5866 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
5867 firstChessProgramNames);
\r
5868 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5869 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
5870 secondChessProgramNames);
\r
5871 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
5872 InitComboStringsFromOption(hwndCombo, icsNames);
\r
5873 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
5874 if (*appData.icsHelper != NULLCHAR) {
\r
5875 char *q = QuoteForFilename(appData.icsHelper);
\r
5876 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
5878 if (*appData.icsHost == NULLCHAR) {
\r
5879 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5880 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
5881 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5882 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5883 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5886 if (appData.icsActive) {
5887 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
5889 else if (appData.noChessProgram) {
5890 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
5893 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
5896 SetStartupDialogEnables(hDlg);
\r
5900 switch (LOWORD(wParam)) {
\r
5902 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
5903 strcpy(buf, "/fcp=");
\r
5904 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5906 ParseArgs(StringGet, &p);
\r
5907 strcpy(buf, "/scp=");
\r
5908 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5910 ParseArgs(StringGet, &p);
\r
5911 appData.noChessProgram = FALSE;
\r
5912 appData.icsActive = FALSE;
\r
5913 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
5914 strcpy(buf, "/ics /icshost=");
\r
5915 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5917 ParseArgs(StringGet, &p);
\r
5918 if (appData.zippyPlay) {
\r
5919 strcpy(buf, "/fcp=");
\r
5920 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5922 ParseArgs(StringGet, &p);
\r
5924 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
5925 appData.noChessProgram = TRUE;
\r
5926 appData.icsActive = FALSE;
\r
5928 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
5929 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
5932 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
5933 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
5935 ParseArgs(StringGet, &p);
\r
5937 EndDialog(hDlg, TRUE);
\r
5944 case IDM_HELPCONTENTS:
\r
5945 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5946 MessageBox (GetFocus(),
\r
5947 "Unable to activate help",
\r
5948 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5953 SetStartupDialogEnables(hDlg);
\r
5961 /*---------------------------------------------------------------------------*\
\r
5963 * About box dialog functions
\r
5965 \*---------------------------------------------------------------------------*/
\r
5967 /* Process messages for "About" dialog box */
\r
5969 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5971 switch (message) {
\r
5972 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5973 /* Center the dialog over the application window */
\r
5974 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5975 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
5978 case WM_COMMAND: /* message: received a command */
\r
5979 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
5980 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
5981 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5989 /*---------------------------------------------------------------------------*\
\r
5991 * Comment Dialog functions
\r
5993 \*---------------------------------------------------------------------------*/
\r
5996 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5998 static HANDLE hwndText = NULL;
\r
5999 int len, newSizeX, newSizeY, flags;
\r
6000 static int sizeX, sizeY;
\r
6005 switch (message) {
\r
6006 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6007 /* Initialize the dialog items */
\r
6008 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6009 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6010 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6011 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6012 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6013 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6014 SetWindowText(hDlg, commentTitle);
\r
6015 if (editComment) {
\r
6016 SetFocus(hwndText);
\r
6018 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6020 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6021 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6022 MAKELPARAM(FALSE, 0));
\r
6023 /* Size and position the dialog */
\r
6024 if (!commentDialog) {
\r
6025 commentDialog = hDlg;
\r
6026 flags = SWP_NOZORDER;
\r
6027 GetClientRect(hDlg, &rect);
\r
6028 sizeX = rect.right;
\r
6029 sizeY = rect.bottom;
\r
6030 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
6031 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
6032 WINDOWPLACEMENT wp;
\r
6033 EnsureOnScreen(&commentX, &commentY);
\r
6034 wp.length = sizeof(WINDOWPLACEMENT);
\r
6036 wp.showCmd = SW_SHOW;
\r
6037 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6038 wp.rcNormalPosition.left = commentX;
\r
6039 wp.rcNormalPosition.right = commentX + commentW;
\r
6040 wp.rcNormalPosition.top = commentY;
\r
6041 wp.rcNormalPosition.bottom = commentY + commentH;
\r
6042 SetWindowPlacement(hDlg, &wp);
\r
6044 GetClientRect(hDlg, &rect);
\r
6045 newSizeX = rect.right;
\r
6046 newSizeY = rect.bottom;
\r
6047 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6048 newSizeX, newSizeY);
\r
6055 case WM_COMMAND: /* message: received a command */
\r
6056 switch (LOWORD(wParam)) {
\r
6058 if (editComment) {
\r
6060 /* Read changed options from the dialog box */
\r
6061 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6062 len = GetWindowTextLength(hwndText);
\r
6063 str = (char *) malloc(len + 1);
\r
6064 GetWindowText(hwndText, str, len + 1);
\r
6073 ReplaceComment(commentIndex, str);
\r
6080 case OPT_CancelComment:
\r
6084 case OPT_ClearComment:
\r
6085 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6088 case OPT_EditComment:
\r
6089 EditCommentEvent();
\r
6098 newSizeX = LOWORD(lParam);
\r
6099 newSizeY = HIWORD(lParam);
\r
6100 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6105 case WM_GETMINMAXINFO:
\r
6106 /* Prevent resizing window too small */
\r
6107 mmi = (MINMAXINFO *) lParam;
\r
6108 mmi->ptMinTrackSize.x = 100;
\r
6109 mmi->ptMinTrackSize.y = 100;
\r
6116 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6121 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6123 if (str == NULL) str = "";
\r
6124 p = (char *) malloc(2 * strlen(str) + 2);
\r
6127 if (*str == '\n') *q++ = '\r';
\r
6131 if (commentText != NULL) free(commentText);
\r
6133 commentIndex = index;
\r
6134 commentTitle = title;
\r
6136 editComment = edit;
\r
6138 if (commentDialog) {
\r
6139 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6140 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
6142 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6143 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6144 hwndMain, (DLGPROC)lpProc);
\r
6145 FreeProcInstance(lpProc);
\r
6147 commentDialogUp = TRUE;
\r
6151 /*---------------------------------------------------------------------------*\
\r
6153 * Type-in move dialog functions
\r
6155 \*---------------------------------------------------------------------------*/
\r
6158 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6160 char move[MSG_SIZ];
\r
6162 ChessMove moveType;
\r
6163 int fromX, fromY, toX, toY;
\r
6166 switch (message) {
\r
6167 case WM_INITDIALOG:
\r
6168 move[0] = (char) lParam;
\r
6169 move[1] = NULLCHAR;
\r
6170 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
6171 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6172 SetWindowText(hInput, move);
\r
6174 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6178 switch (LOWORD(wParam)) {
\r
6180 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
6181 gameMode != Training) {
\r
6182 DisplayMoveError("Displayed move is not current");
\r
6184 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6185 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6186 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
6187 if (gameMode != Training)
\r
6188 forwardMostMove = currentMove;
\r
6189 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
6191 DisplayMoveError("Could not parse move");
\r
6194 EndDialog(hDlg, TRUE);
\r
6197 EndDialog(hDlg, FALSE);
\r
6208 PopUpMoveDialog(char firstchar)
\r
6212 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
6213 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
6214 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
6215 gameMode == EditPosition || gameMode == IcsExamining ||
\r
6216 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
6217 gameMode == Training) {
\r
6218 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6219 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6220 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6221 FreeProcInstance(lpProc);
\r
6225 /*---------------------------------------------------------------------------*\
\r
6229 \*---------------------------------------------------------------------------*/
\r
6231 /* Nonmodal error box */
\r
6232 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6233 WPARAM wParam, LPARAM lParam);
\r
6236 ErrorPopUp(char *title, char *content)
\r
6240 BOOLEAN modal = hwndMain == NULL;
\r
6258 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6259 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6262 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6264 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6265 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6266 hwndMain, (DLGPROC)lpProc);
\r
6267 FreeProcInstance(lpProc);
\r
6274 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6275 if (errorDialog == NULL) return;
\r
6276 DestroyWindow(errorDialog);
\r
6277 errorDialog = NULL;
\r
6281 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6286 switch (message) {
\r
6287 case WM_INITDIALOG:
\r
6288 GetWindowRect(hDlg, &rChild);
\r
6291 SetWindowPos(hDlg, NULL, rChild.left,
\r
6292 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6293 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6297 [AS] It seems that the above code wants to move the dialog up in the "caption
6298 area" of the main window, but it uses the dialog height as an hard-coded constant,
6299 and it doesn't work when you resize the dialog.
6300 For now, just give it a default position.
6302 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
6304 errorDialog = hDlg;
\r
6305 SetWindowText(hDlg, errorTitle);
\r
6306 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6307 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6311 switch (LOWORD(wParam)) {
\r
6314 if (errorDialog == hDlg) errorDialog = NULL;
\r
6315 DestroyWindow(hDlg);
\r
6326 /*---------------------------------------------------------------------------*\
\r
6328 * Ics Interaction console functions
\r
6330 \*---------------------------------------------------------------------------*/
\r
6332 #define HISTORY_SIZE 64
\r
6333 static char *history[HISTORY_SIZE];
\r
6334 int histIn = 0, histP = 0;
\r
6337 SaveInHistory(char *cmd)
\r
6339 if (history[histIn] != NULL) {
\r
6340 free(history[histIn]);
\r
6341 history[histIn] = NULL;
\r
6343 if (*cmd == NULLCHAR) return;
\r
6344 history[histIn] = StrSave(cmd);
\r
6345 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6346 if (history[histIn] != NULL) {
\r
6347 free(history[histIn]);
\r
6348 history[histIn] = NULL;
\r
6354 PrevInHistory(char *cmd)
\r
6357 if (histP == histIn) {
\r
6358 if (history[histIn] != NULL) free(history[histIn]);
\r
6359 history[histIn] = StrSave(cmd);
\r
6361 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6362 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6364 return history[histP];
\r
6370 if (histP == histIn) return NULL;
\r
6371 histP = (histP + 1) % HISTORY_SIZE;
\r
6372 return history[histP];
\r
6379 BOOLEAN immediate;
\r
6380 } IcsTextMenuEntry;
\r
6381 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
6382 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
6385 ParseIcsTextMenu(char *icsTextMenuString)
\r
6388 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
6389 char *p = icsTextMenuString;
\r
6390 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6393 if (e->command != NULL) {
\r
6395 e->command = NULL;
\r
6399 e = icsTextMenuEntry;
\r
6400 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6401 if (*p == ';' || *p == '\n') {
\r
6402 e->item = strdup("-");
\r
6403 e->command = NULL;
\r
6405 } else if (*p == '-') {
\r
6406 e->item = strdup("-");
\r
6407 e->command = NULL;
\r
6411 char *q, *r, *s, *t;
\r
6413 q = strchr(p, ',');
\r
6414 if (q == NULL) break;
\r
6416 r = strchr(q + 1, ',');
\r
6417 if (r == NULL) break;
\r
6419 s = strchr(r + 1, ',');
\r
6420 if (s == NULL) break;
\r
6423 t = strchr(s + 1, c);
\r
6426 t = strchr(s + 1, c);
\r
6428 if (t != NULL) *t = NULLCHAR;
\r
6429 e->item = strdup(p);
\r
6430 e->command = strdup(q + 1);
\r
6431 e->getname = *(r + 1) != '0';
\r
6432 e->immediate = *(s + 1) != '0';
\r
6436 if (t == NULL) break;
\r
6445 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6449 hmenu = LoadMenu(hInst, "TextMenu");
\r
6450 h = GetSubMenu(hmenu, 0);
\r
6452 if (strcmp(e->item, "-") == 0) {
\r
6453 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6455 if (e->item[0] == '|') {
\r
6456 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6457 IDM_CommandX + i, &e->item[1]);
\r
6459 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
6468 WNDPROC consoleTextWindowProc;
\r
6471 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6473 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6474 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6478 SetWindowText(hInput, command);
\r
6480 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6482 sel.cpMin = 999999;
\r
6483 sel.cpMax = 999999;
\r
6484 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6489 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6490 if (sel.cpMin == sel.cpMax) {
\r
6491 /* Expand to surrounding word */
\r
6494 tr.chrg.cpMax = sel.cpMin;
\r
6495 tr.chrg.cpMin = --sel.cpMin;
\r
6496 if (sel.cpMin < 0) break;
\r
6497 tr.lpstrText = name;
\r
6498 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6499 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6503 tr.chrg.cpMin = sel.cpMax;
\r
6504 tr.chrg.cpMax = ++sel.cpMax;
\r
6505 tr.lpstrText = name;
\r
6506 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6507 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6510 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6511 MessageBeep(MB_ICONEXCLAMATION);
\r
6515 tr.lpstrText = name;
\r
6516 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6518 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6519 MessageBeep(MB_ICONEXCLAMATION);
\r
6522 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6525 sprintf(buf, "%s %s", command, name);
\r
6526 SetWindowText(hInput, buf);
\r
6527 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6529 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
6530 SetWindowText(hInput, buf);
\r
6531 sel.cpMin = 999999;
\r
6532 sel.cpMax = 999999;
\r
6533 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6539 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6544 switch (message) {
\r
6546 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6549 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6552 sel.cpMin = 999999;
\r
6553 sel.cpMax = 999999;
\r
6554 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6555 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6560 if (wParam == '\t') {
\r
6561 if (GetKeyState(VK_SHIFT) < 0) {
\r
6563 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6564 if (buttonDesc[0].hwnd) {
\r
6565 SetFocus(buttonDesc[0].hwnd);
\r
6567 SetFocus(hwndMain);
\r
6571 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
6574 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6576 SendMessage(hInput, message, wParam, lParam);
\r
6580 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6582 return SendMessage(hInput, message, wParam, lParam);
\r
6583 case WM_MBUTTONDOWN:
\r
6584 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6585 case WM_RBUTTONDOWN:
\r
6586 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6587 /* Move selection here if it was empty */
\r
6589 pt.x = LOWORD(lParam);
\r
6590 pt.y = HIWORD(lParam);
\r
6591 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6592 if (sel.cpMin == sel.cpMax) {
\r
6593 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6594 sel.cpMax = sel.cpMin;
\r
6595 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6597 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6600 case WM_RBUTTONUP:
\r
6601 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6602 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6603 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6606 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6607 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6608 if (sel.cpMin == sel.cpMax) {
\r
6609 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6610 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6612 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6613 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6615 pt.x = LOWORD(lParam);
\r
6616 pt.y = HIWORD(lParam);
\r
6617 MenuPopup(hwnd, pt, hmenu, -1);
\r
6621 switch (LOWORD(wParam)) {
\r
6622 case IDM_QuickPaste:
\r
6624 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6625 if (sel.cpMin == sel.cpMax) {
\r
6626 MessageBeep(MB_ICONEXCLAMATION);
\r
6629 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6630 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6631 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6636 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6639 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6642 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6646 int i = LOWORD(wParam) - IDM_CommandX;
\r
6647 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
6648 icsTextMenuEntry[i].command != NULL) {
\r
6649 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
6650 icsTextMenuEntry[i].getname,
\r
6651 icsTextMenuEntry[i].immediate);
\r
6659 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
6662 WNDPROC consoleInputWindowProc;
\r
6665 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6667 char buf[MSG_SIZ];
\r
6669 static BOOL sendNextChar = FALSE;
\r
6670 static BOOL quoteNextChar = FALSE;
\r
6671 InputSource *is = consoleInputSource;
\r
6675 switch (message) {
\r
6677 if (!appData.localLineEditing || sendNextChar) {
\r
6678 is->buf[0] = (CHAR) wParam;
\r
6680 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6681 sendNextChar = FALSE;
\r
6684 if (quoteNextChar) {
\r
6685 buf[0] = (char) wParam;
\r
6686 buf[1] = NULLCHAR;
\r
6687 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
6688 quoteNextChar = FALSE;
\r
6692 case '\r': /* Enter key */
\r
6693 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
6694 if (consoleEcho) SaveInHistory(is->buf);
\r
6695 is->buf[is->count++] = '\n';
\r
6696 is->buf[is->count] = NULLCHAR;
\r
6697 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6698 if (consoleEcho) {
\r
6699 ConsoleOutput(is->buf, is->count, TRUE);
\r
6700 } else if (appData.localLineEditing) {
\r
6701 ConsoleOutput("\n", 1, TRUE);
\r
6704 case '\033': /* Escape key */
\r
6705 SetWindowText(hwnd, "");
\r
6706 cf.cbSize = sizeof(CHARFORMAT);
\r
6707 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6708 if (consoleEcho) {
\r
6709 cf.crTextColor = textAttribs[ColorNormal].color;
\r
6711 cf.crTextColor = COLOR_ECHOOFF;
\r
6713 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
6714 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6716 case '\t': /* Tab key */
\r
6717 if (GetKeyState(VK_SHIFT) < 0) {
\r
6719 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
6722 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6723 if (buttonDesc[0].hwnd) {
\r
6724 SetFocus(buttonDesc[0].hwnd);
\r
6726 SetFocus(hwndMain);
\r
6730 case '\023': /* Ctrl+S */
\r
6731 sendNextChar = TRUE;
\r
6733 case '\021': /* Ctrl+Q */
\r
6734 quoteNextChar = TRUE;
\r
6743 GetWindowText(hwnd, buf, MSG_SIZ);
\r
6744 p = PrevInHistory(buf);
\r
6746 SetWindowText(hwnd, p);
\r
6747 sel.cpMin = 999999;
\r
6748 sel.cpMax = 999999;
\r
6749 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6754 p = NextInHistory();
\r
6756 SetWindowText(hwnd, p);
\r
6757 sel.cpMin = 999999;
\r
6758 sel.cpMax = 999999;
\r
6759 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6765 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6769 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
6773 case WM_MBUTTONDOWN:
\r
6774 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6775 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6777 case WM_RBUTTONUP:
\r
6778 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6779 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6780 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6784 hmenu = LoadMenu(hInst, "InputMenu");
\r
6785 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6786 if (sel.cpMin == sel.cpMax) {
\r
6787 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6788 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
6790 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6791 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6793 pt.x = LOWORD(lParam);
\r
6794 pt.y = HIWORD(lParam);
\r
6795 MenuPopup(hwnd, pt, hmenu, -1);
\r
6799 switch (LOWORD(wParam)) {
\r
6801 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
6803 case IDM_SelectAll:
\r
6805 sel.cpMax = -1; /*999999?*/
\r
6806 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6809 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6812 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6815 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6820 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
6823 #define CO_MAX 100000
\r
6824 #define CO_TRIM 1000
\r
6827 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6830 static HWND hText, hInput, hFocus;
\r
6831 InputSource *is = consoleInputSource;
\r
6833 static int sizeX, sizeY;
\r
6834 int newSizeX, newSizeY;
\r
6837 switch (message) {
\r
6838 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6839 hwndConsole = hDlg;
\r
6840 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
6841 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
6843 consoleTextWindowProc = (WNDPROC)
\r
6844 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
6845 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6846 consoleInputWindowProc = (WNDPROC)
\r
6847 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
6848 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6849 Colorize(ColorNormal, TRUE);
\r
6850 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
6851 ChangedConsoleFont();
\r
6852 GetClientRect(hDlg, &rect);
\r
6853 sizeX = rect.right;
\r
6854 sizeY = rect.bottom;
\r
6855 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
6856 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
6857 WINDOWPLACEMENT wp;
\r
6858 EnsureOnScreen(&consoleX, &consoleY);
\r
6859 wp.length = sizeof(WINDOWPLACEMENT);
\r
6861 wp.showCmd = SW_SHOW;
\r
6862 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6863 wp.rcNormalPosition.left = consoleX;
\r
6864 wp.rcNormalPosition.right = consoleX + consoleW;
\r
6865 wp.rcNormalPosition.top = consoleY;
\r
6866 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
6867 SetWindowPlacement(hDlg, &wp);
\r
6881 if (IsIconic(hDlg)) break;
\r
6882 newSizeX = LOWORD(lParam);
\r
6883 newSizeY = HIWORD(lParam);
\r
6884 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
6885 RECT rectText, rectInput;
\r
6887 int newTextHeight, newTextWidth;
\r
6888 GetWindowRect(hText, &rectText);
\r
6889 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6890 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6891 if (newTextHeight < 0) {
\r
6892 newSizeY += -newTextHeight;
\r
6893 newTextHeight = 0;
\r
6895 SetWindowPos(hText, NULL, 0, 0,
\r
6896 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6897 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
6898 pt.x = rectInput.left;
\r
6899 pt.y = rectInput.top + newSizeY - sizeY;
\r
6900 ScreenToClient(hDlg, &pt);
\r
6901 SetWindowPos(hInput, NULL,
\r
6902 pt.x, pt.y, /* needs client coords */
\r
6903 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
6904 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
6910 case WM_GETMINMAXINFO:
\r
6911 /* Prevent resizing window too small */
\r
6912 mmi = (MINMAXINFO *) lParam;
\r
6913 mmi->ptMinTrackSize.x = 100;
\r
6914 mmi->ptMinTrackSize.y = 100;
\r
6918 case WM_ENTERSIZEMOVE:
6919 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
6922 return OnSizing( &sd, hDlg, wParam, lParam );
6925 return OnMoving( &sd, hDlg, wParam, lParam );
6927 case WM_EXITSIZEMOVE:
6928 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
6931 return DefWindowProc(hDlg, message, wParam, lParam);
\r
6939 if (hwndConsole) return;
\r
6940 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
6941 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
6946 ConsoleOutput(char* data, int length, int forceVisible)
\r
6951 char buf[CO_MAX+1];
\r
6954 static int delayLF = 0;
\r
6955 CHARRANGE savesel, sel;
\r
6957 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
6965 while (length--) {
\r
6973 } else if (*p == '\007') {
\r
6974 MyPlaySound(&sounds[(int)SoundBell]);
\r
6981 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
6982 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6983 /* Save current selection */
\r
6984 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
6985 exlen = GetWindowTextLength(hText);
\r
6986 /* Find out whether current end of text is visible */
\r
6987 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
6988 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
6989 /* Trim existing text if it's too long */
\r
6990 if (exlen + (q - buf) > CO_MAX) {
\r
6991 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
6994 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6995 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
6997 savesel.cpMin -= trim;
\r
6998 savesel.cpMax -= trim;
\r
6999 if (exlen < 0) exlen = 0;
\r
7000 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7001 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7003 /* Append the new text */
\r
7004 sel.cpMin = exlen;
\r
7005 sel.cpMax = exlen;
\r
7006 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7007 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7008 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7009 if (forceVisible || exlen == 0 ||
\r
7010 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7011 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7012 /* Scroll to make new end of text visible if old end of text
\r
7013 was visible or new text is an echo of user typein */
\r
7014 sel.cpMin = 9999999;
\r
7015 sel.cpMax = 9999999;
\r
7016 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7017 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7018 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7019 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7021 if (savesel.cpMax == exlen || forceVisible) {
\r
7022 /* Move insert point to new end of text if it was at the old
\r
7023 end of text or if the new text is an echo of user typein */
\r
7024 sel.cpMin = 9999999;
\r
7025 sel.cpMax = 9999999;
\r
7026 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7028 /* Restore previous selection */
\r
7029 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7031 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7038 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7039 RECT *rect, char *color)
\r
7043 COLORREF oldFg, oldBg;
\r
7046 if (appData.clockMode) {
\r
7048 sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));
\r
7050 sprintf(buf, "%s: %s", color, TimeString(timeRemaining));
\r
7057 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7058 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7060 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7061 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7063 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7065 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7066 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7067 rect, str, strlen(str), NULL);
\r
7069 (void) SetTextColor(hdc, oldFg);
\r
7070 (void) SetBkColor(hdc, oldBg);
\r
7071 (void) SelectObject(hdc, oldFont);
\r
7076 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7083 if (appData.debugMode) {
7084 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
7087 return ERROR_INVALID_USER_BUFFER;
7090 ResetEvent(ovl->hEvent);
\r
7091 ovl->Offset = ovl->OffsetHigh = 0;
\r
7092 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7096 err = GetLastError();
\r
7097 if (err == ERROR_IO_PENDING) {
\r
7098 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7102 err = GetLastError();
\r
7109 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7114 ResetEvent(ovl->hEvent);
\r
7115 ovl->Offset = ovl->OffsetHigh = 0;
\r
7116 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7120 err = GetLastError();
\r
7121 if (err == ERROR_IO_PENDING) {
\r
7122 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7126 err = GetLastError();
\r
7132 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
7133 void CheckForInputBufferFull( InputSource * is )
7135 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
7136 /* Look for end of line */
7139 while( p < is->next && *p != '\n' ) {
7143 if( p >= is->next ) {
7144 if (appData.debugMode) {
7145 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
7148 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
7149 is->count = (DWORD) -1;
7156 InputThread(LPVOID arg)
\r
7161 is = (InputSource *) arg;
\r
7162 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7163 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7164 while (is->hThread != NULL) {
\r
7165 is->error = DoReadFile(is->hFile, is->next,
\r
7166 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7167 &is->count, &ovl);
\r
7168 if (is->error == NO_ERROR) {
\r
7169 is->next += is->count;
\r
7171 if (is->error == ERROR_BROKEN_PIPE) {
\r
7172 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7175 is->count = (DWORD) -1;
\r
7176 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
7181 CheckForInputBufferFull( is );
7183 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7185 if( is->count == ((DWORD) -1) ) break; /* [AS] */
7187 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7190 CloseHandle(ovl.hEvent);
\r
7191 CloseHandle(is->hFile);
\r
7193 if (appData.debugMode) {
7194 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
7201 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7203 NonOvlInputThread(LPVOID arg)
\r
7210 is = (InputSource *) arg;
\r
7211 while (is->hThread != NULL) {
\r
7212 is->error = ReadFile(is->hFile, is->next,
\r
7213 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7214 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7215 if (is->error == NO_ERROR) {
\r
7216 /* Change CRLF to LF */
\r
7217 if (is->next > is->buf) {
\r
7219 i = is->count + 1;
\r
7227 if (prev == '\r' && *p == '\n') {
\r
7239 if (is->error == ERROR_BROKEN_PIPE) {
\r
7240 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7243 is->count = (DWORD) -1;
\r
7247 CheckForInputBufferFull( is );
7249 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7251 if( is->count == ((DWORD) -1) ) break; /* [AS] */
7253 if (is->count < 0) break; /* Quit on error */
\r
7255 CloseHandle(is->hFile);
\r
7260 SocketInputThread(LPVOID arg)
\r
7264 is = (InputSource *) arg;
\r
7265 while (is->hThread != NULL) {
\r
7266 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7267 if ((int)is->count == SOCKET_ERROR) {
\r
7268 is->count = (DWORD) -1;
\r
7269 is->error = WSAGetLastError();
\r
7271 is->error = NO_ERROR;
\r
7272 is->next += is->count;
\r
7273 if (is->count == 0 && is->second == is) {
\r
7274 /* End of file on stderr; quit with no message */
\r
7278 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7280 if( is->count == ((DWORD) -1) ) break; /* [AS] */
7282 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7288 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7292 is = (InputSource *) lParam;
\r
7293 if (is->lineByLine) {
\r
7294 /* Feed in lines one by one */
\r
7295 char *p = is->buf;
\r
7297 while (q < is->next) {
\r
7298 if (*q++ == '\n') {
\r
7299 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7304 /* Move any partial line to the start of the buffer */
\r
7306 while (p < is->next) {
\r
7311 if (is->error != NO_ERROR || is->count == 0) {
\r
7312 /* Notify backend of the error. Note: If there was a partial
\r
7313 line at the end, it is not flushed through. */
\r
7314 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7317 /* Feed in the whole chunk of input at once */
\r
7318 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7319 is->next = is->buf;
\r
7323 /*---------------------------------------------------------------------------*\
\r
7325 * Menu enables. Used when setting various modes.
\r
7327 \*---------------------------------------------------------------------------*/
\r
7335 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7337 while (enab->item > 0) {
\r
7338 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7343 Enables gnuEnables[] = {
\r
7344 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7345 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7346 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7347 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7348 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7349 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7350 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7351 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7352 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7353 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7357 Enables icsEnables[] = {
\r
7358 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7359 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7360 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7361 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7362 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7363 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7364 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7365 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7366 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7367 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7368 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7369 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7374 Enables zippyEnables[] = {
\r
7375 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7376 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7377 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7382 Enables ncpEnables[] = {
\r
7383 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7384 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7385 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7386 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7387 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7388 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7389 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7390 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7391 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7392 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7393 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7394 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7395 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7396 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7397 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7401 Enables trainingOnEnables[] = {
\r
7402 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7403 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7404 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7405 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7406 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7407 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7408 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7409 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7413 Enables trainingOffEnables[] = {
\r
7414 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7415 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7416 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7417 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7418 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7419 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7420 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7421 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7425 /* These modify either ncpEnables or gnuEnables */
\r
7426 Enables cmailEnables[] = {
\r
7427 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7428 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7429 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7430 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7431 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7432 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7433 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7437 Enables machineThinkingEnables[] = {
\r
7438 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7439 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7440 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7441 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7442 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7443 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7444 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7445 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7446 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7447 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7448 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7449 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7450 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7451 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7452 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7456 Enables userThinkingEnables[] = {
\r
7457 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7458 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7459 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7460 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7461 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7462 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7463 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7464 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7465 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7466 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7467 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7468 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7469 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7470 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7471 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7475 /*---------------------------------------------------------------------------*\
\r
7477 * Front-end interface functions exported by XBoard.
\r
7478 * Functions appear in same order as prototypes in frontend.h.
\r
7480 \*---------------------------------------------------------------------------*/
\r
7484 static UINT prevChecked = 0;
\r
7485 static int prevPausing = 0;
\r
7488 if (pausing != prevPausing) {
\r
7489 prevPausing = pausing;
\r
7490 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7491 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
7492 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
7495 switch (gameMode) {
\r
7496 case BeginningOfGame:
\r
7497 if (appData.icsActive)
\r
7498 nowChecked = IDM_IcsClient;
\r
7499 else if (appData.noChessProgram)
\r
7500 nowChecked = IDM_EditGame;
\r
7502 nowChecked = IDM_MachineBlack;
\r
7504 case MachinePlaysBlack:
\r
7505 nowChecked = IDM_MachineBlack;
\r
7507 case MachinePlaysWhite:
\r
7508 nowChecked = IDM_MachineWhite;
\r
7510 case TwoMachinesPlay:
\r
7511 nowChecked = IDM_TwoMachines;
\r
7514 nowChecked = IDM_AnalysisMode;
\r
7517 nowChecked = IDM_AnalyzeFile;
\r
7520 nowChecked = IDM_EditGame;
\r
7522 case PlayFromGameFile:
\r
7523 nowChecked = IDM_LoadGame;
\r
7525 case EditPosition:
\r
7526 nowChecked = IDM_EditPosition;
\r
7529 nowChecked = IDM_Training;
\r
7531 case IcsPlayingWhite:
\r
7532 case IcsPlayingBlack:
\r
7533 case IcsObserving:
\r
7535 nowChecked = IDM_IcsClient;
\r
7542 if (prevChecked != 0)
\r
7543 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7544 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
7545 if (nowChecked != 0)
\r
7546 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7547 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
7549 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
7550 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
7551 MF_BYCOMMAND|MF_ENABLED);
\r
7553 (void) EnableMenuItem(GetMenu(hwndMain),
\r
7554 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
7557 prevChecked = nowChecked;
\r
7563 HMENU hmenu = GetMenu(hwndMain);
\r
7564 SetMenuEnables(hmenu, icsEnables);
\r
7565 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
7566 MF_BYPOSITION|MF_ENABLED);
\r
7568 if (appData.zippyPlay) {
\r
7569 SetMenuEnables(hmenu, zippyEnables);
\r
7577 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
7583 HMENU hmenu = GetMenu(hwndMain);
\r
7584 SetMenuEnables(hmenu, ncpEnables);
\r
7585 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
7586 MF_BYPOSITION|MF_GRAYED);
\r
7587 DrawMenuBar(hwndMain);
\r
7593 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
7597 SetTrainingModeOn()
\r
7600 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
7601 for (i = 0; i < N_BUTTONS; i++) {
\r
7602 if (buttonDesc[i].hwnd != NULL)
\r
7603 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
7608 VOID SetTrainingModeOff()
\r
7611 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
7612 for (i = 0; i < N_BUTTONS; i++) {
\r
7613 if (buttonDesc[i].hwnd != NULL)
\r
7614 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
7620 SetUserThinkingEnables()
\r
7622 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
7626 SetMachineThinkingEnables()
\r
7628 HMENU hMenu = GetMenu(hwndMain);
\r
7629 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
7631 SetMenuEnables(hMenu, machineThinkingEnables);
\r
7633 if (gameMode == MachinePlaysBlack) {
\r
7634 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
7635 } else if (gameMode == MachinePlaysWhite) {
\r
7636 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
7637 } else if (gameMode == TwoMachinesPlay) {
\r
7638 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
7644 DisplayTitle(char *str)
\r
7646 char title[MSG_SIZ], *host;
\r
7647 if (str[0] != NULLCHAR) {
\r
7648 strcpy(title, str);
\r
7649 } else if (appData.icsActive) {
\r
7650 if (appData.icsCommPort[0] != NULLCHAR)
\r
7653 host = appData.icsHost;
\r
7654 sprintf(title, "%s: %s", szTitle, host);
\r
7655 } else if (appData.noChessProgram) {
\r
7656 strcpy(title, szTitle);
\r
7658 strcpy(title, szTitle);
\r
7659 strcat(title, ": ");
\r
7660 strcat(title, first.tidy);
\r
7662 SetWindowText(hwndMain, title);
\r
7667 DisplayMessage(char *str1, char *str2)
\r
7671 int remain = MESSAGE_TEXT_MAX - 1;
\r
7674 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
7675 messageText[0] = NULLCHAR;
\r
7677 len = strlen(str1);
\r
7678 if (len > remain) len = remain;
\r
7679 strncpy(messageText, str1, len);
\r
7680 messageText[len] = NULLCHAR;
\r
7683 if (*str2 && remain >= 2) {
\r
7685 strcat(messageText, " ");
\r
7688 len = strlen(str2);
\r
7689 if (len > remain) len = remain;
\r
7690 strncat(messageText, str2, len);
\r
7692 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
7694 if (IsIconic(hwndMain)) return;
\r
7695 hdc = GetDC(hwndMain);
\r
7696 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
7697 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7698 &messageRect, messageText, strlen(messageText), NULL);
\r
7699 (void) SelectObject(hdc, oldFont);
\r
7700 (void) ReleaseDC(hwndMain, hdc);
\r
7704 DisplayError(char *str, int error)
\r
7706 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
7712 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7713 NULL, error, LANG_NEUTRAL,
\r
7714 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7716 sprintf(buf, "%s:\n%s", str, buf2);
\r
7718 ErrorMap *em = errmap;
\r
7719 while (em->err != 0 && em->err != error) em++;
\r
7720 if (em->err != 0) {
\r
7721 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7723 sprintf(buf, "%s:\nError code %d", str, error);
\r
7728 ErrorPopUp("Error", buf);
\r
7733 DisplayMoveError(char *str)
\r
7735 fromX = fromY = -1;
\r
7736 ClearHighlights();
\r
7737 DrawPosition(FALSE, NULL);
\r
7738 if (appData.popupMoveErrors) {
\r
7739 ErrorPopUp("Error", str);
\r
7741 DisplayMessage(str, "");
\r
7742 moveErrorMessageUp = TRUE;
\r
7747 DisplayFatalError(char *str, int error, int exitStatus)
\r
7749 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
7751 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
7754 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7755 NULL, error, LANG_NEUTRAL,
\r
7756 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7758 sprintf(buf, "%s:\n%s", str, buf2);
\r
7760 ErrorMap *em = errmap;
\r
7761 while (em->err != 0 && em->err != error) em++;
\r
7762 if (em->err != 0) {
\r
7763 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7765 sprintf(buf, "%s:\nError code %d", str, error);
\r
7770 if (appData.debugMode) {
\r
7771 fprintf(debugFP, "%s: %s\n", label, str);
\r
7773 if (appData.popupExitMessage) {
\r
7774 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
7775 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
7777 ExitEvent(exitStatus);
\r
7782 DisplayInformation(char *str)
\r
7784 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
7789 DisplayNote(char *str)
\r
7791 ErrorPopUp("Note", str);
\r
7796 char *title, *question, *replyPrefix;
\r
7801 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7803 static QuestionParams *qp;
\r
7804 char reply[MSG_SIZ];
\r
7807 switch (message) {
\r
7808 case WM_INITDIALOG:
\r
7809 qp = (QuestionParams *) lParam;
\r
7810 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7811 SetWindowText(hDlg, qp->title);
\r
7812 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
7813 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
7817 switch (LOWORD(wParam)) {
\r
7819 strcpy(reply, qp->replyPrefix);
\r
7820 if (*reply) strcat(reply, " ");
\r
7821 len = strlen(reply);
\r
7822 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
7823 strcat(reply, "\n");
\r
7824 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
7825 EndDialog(hDlg, TRUE);
\r
7826 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
7829 EndDialog(hDlg, FALSE);
\r
7840 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
7842 QuestionParams qp;
\r
7846 qp.question = question;
\r
7847 qp.replyPrefix = replyPrefix;
\r
7849 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
7850 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
7851 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
7852 FreeProcInstance(lpProc);
\r
7855 /* [AS] Pick FRC position */
7856 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
7858 static int * lpIndexFRC;
7865 lpIndexFRC = (int *) lParam;
7867 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
7869 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
7870 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
7871 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
7872 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
7877 switch( LOWORD(wParam) ) {
7879 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
7880 EndDialog( hDlg, 0 );
7883 EndDialog( hDlg, 1 );
7886 if( HIWORD(wParam) == EN_CHANGE ) {
7887 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
7889 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
7892 case IDC_NFG_Random:
7893 sprintf( buf, "%d", myrandom() % 960 );
7894 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
7907 int index = appData.defaultFrcPosition;
7908 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
7910 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
7913 appData.defaultFrcPosition = index;
7919 /* [AS] Game list options */
7925 static GLT_Item GLT_ItemInfo[] = {
7926 { GLT_EVENT, "Event" },
7927 { GLT_SITE, "Site" },
7928 { GLT_DATE, "Date" },
7929 { GLT_ROUND, "Round" },
7930 { GLT_PLAYERS, "Players" },
7931 { GLT_RESULT, "Result" },
7932 { GLT_WHITE_ELO, "White Rating" },
7933 { GLT_BLACK_ELO, "Black Rating" },
7934 { GLT_TIME_CONTROL,"Time Control" },
7935 { GLT_VARIANT, "Variant" },
7936 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
7940 const char * GLT_FindItem( char id )
7942 const char * result = 0;
7944 GLT_Item * list = GLT_ItemInfo;
7946 while( list->id != 0 ) {
7947 if( list->id == id ) {
7948 result = list->name;
7958 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
7960 const char * name = GLT_FindItem( id );
7964 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
7967 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
7972 void GLT_TagsToList( HWND hDlg, char * tags )
7976 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
7979 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
7983 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
7988 if( strchr( tags, *pc ) == 0 ) {
7989 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
7994 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
7997 char GLT_ListItemToTag( HWND hDlg, int index )
8002 GLT_Item * list = GLT_ItemInfo;
8004 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
8005 while( list->id != 0 ) {
8006 if( strcmp( list->name, name ) == 0 ) {
8018 void GLT_MoveSelection( HWND hDlg, int delta )
8020 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
8021 int idx2 = idx1 + delta;
8022 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
8024 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
8027 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
8028 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
8029 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
8030 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
8034 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
8036 static char glt[64];
8037 static char * lpUserGLT;
8042 lpUserGLT = (char *) lParam;
8044 strcpy( glt, lpUserGLT );
8046 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
8048 /* Initialize list */
8049 GLT_TagsToList( hDlg, glt );
8051 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
8056 switch( LOWORD(wParam) ) {
8059 char * pc = lpUserGLT;
8061 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
8065 id = GLT_ListItemToTag( hDlg, idx );
8069 } while( id != '\0' );
8071 EndDialog( hDlg, 0 );
8074 EndDialog( hDlg, 1 );
8077 case IDC_GLT_Default:
8078 strcpy( glt, GLT_DEFAULT_TAGS );
8079 GLT_TagsToList( hDlg, glt );
8082 case IDC_GLT_Restore:
8083 strcpy( glt, lpUserGLT );
8084 GLT_TagsToList( hDlg, glt );
8088 GLT_MoveSelection( hDlg, -1 );
8092 GLT_MoveSelection( hDlg, +1 );
8102 int GameListOptions()
8106 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
8108 strcpy( glt, appData.gameListTags );
8110 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
8113 /* [AS] Memory leak here! */
8114 appData.gameListTags = strdup( glt );
8122 DisplayIcsInteractionTitle(char *str)
\r
8124 char consoleTitle[MSG_SIZ];
\r
8126 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8127 SetWindowText(hwndConsole, consoleTitle);
\r
8131 DrawPosition(int fullRedraw, Board board)
\r
8133 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8140 fromX = fromY = -1;
\r
8141 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8142 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8143 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8144 dragInfo.lastpos = dragInfo.pos;
\r
8145 dragInfo.start.x = dragInfo.start.y = -1;
\r
8146 dragInfo.from = dragInfo.start;
\r
8148 DrawPosition(TRUE, NULL);
\r
8154 CommentPopUp(char *title, char *str)
\r
8156 HWND hwnd = GetActiveWindow();
\r
8157 EitherCommentPopUp(0, title, str, FALSE);
\r
8158 SetActiveWindow(hwnd);
\r
8162 CommentPopDown(void)
\r
8164 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8165 if (commentDialog) {
\r
8166 ShowWindow(commentDialog, SW_HIDE);
\r
8168 commentDialogUp = FALSE;
\r
8172 EditCommentPopUp(int index, char *title, char *str)
\r
8174 EitherCommentPopUp(index, title, str, TRUE);
\r
8181 MyPlaySound(&sounds[(int)SoundMove]);
\r
8184 VOID PlayIcsWinSound()
\r
8186 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8189 VOID PlayIcsLossSound()
\r
8191 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8194 VOID PlayIcsDrawSound()
\r
8196 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8199 VOID PlayIcsUnfinishedSound()
\r
8201 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8207 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8215 consoleEcho = TRUE;
\r
8216 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8217 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8218 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8227 consoleEcho = FALSE;
\r
8228 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8229 /* This works OK: set text and background both to the same color */
\r
8231 cf.crTextColor = COLOR_ECHOOFF;
\r
8232 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8233 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8236 /* No Raw()...? */
\r
8238 void Colorize(ColorClass cc, int continuation)
\r
8240 currentColorClass = cc;
\r
8241 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8242 consoleCF.crTextColor = textAttribs[cc].color;
\r
8243 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8244 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8250 static char buf[MSG_SIZ];
\r
8251 DWORD bufsiz = MSG_SIZ;
\r
8253 if (!GetUserName(buf, &bufsiz)) {
\r
8254 /*DisplayError("Error getting user name", GetLastError());*/
\r
8255 strcpy(buf, "User");
\r
8263 static char buf[MSG_SIZ];
\r
8264 DWORD bufsiz = MSG_SIZ;
\r
8266 if (!GetComputerName(buf, &bufsiz)) {
\r
8267 /*DisplayError("Error getting host name", GetLastError());*/
\r
8268 strcpy(buf, "Unknown");
\r
8275 ClockTimerRunning()
\r
8277 return clockTimerEvent != 0;
\r
8283 if (clockTimerEvent == 0) return FALSE;
\r
8284 KillTimer(hwndMain, clockTimerEvent);
\r
8285 clockTimerEvent = 0;
\r
8290 StartClockTimer(long millisec)
\r
8292 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8293 (UINT) millisec, NULL);
\r
8297 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8300 hdc = GetDC(hwndMain);
\r
8301 if (!IsIconic(hwndMain)) {
\r
8302 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");
\r
8304 if (highlight && iconCurrent == iconBlack) {
\r
8305 iconCurrent = iconWhite;
\r
8306 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8307 if (IsIconic(hwndMain)) {
\r
8308 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8311 (void) ReleaseDC(hwndMain, hdc);
\r
8313 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8317 DisplayBlackClock(long timeRemaining, int highlight)
\r
8320 hdc = GetDC(hwndMain);
\r
8321 if (!IsIconic(hwndMain)) {
\r
8322 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");
\r
8324 if (highlight && iconCurrent == iconWhite) {
\r
8325 iconCurrent = iconBlack;
\r
8326 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8327 if (IsIconic(hwndMain)) {
\r
8328 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8331 (void) ReleaseDC(hwndMain, hdc);
\r
8333 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8338 LoadGameTimerRunning()
\r
8340 return loadGameTimerEvent != 0;
\r
8344 StopLoadGameTimer()
\r
8346 if (loadGameTimerEvent == 0) return FALSE;
\r
8347 KillTimer(hwndMain, loadGameTimerEvent);
\r
8348 loadGameTimerEvent = 0;
\r
8353 StartLoadGameTimer(long millisec)
\r
8355 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8356 (UINT) millisec, NULL);
\r
8364 char fileTitle[MSG_SIZ];
\r
8366 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8367 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
8368 appData.oldSaveStyle ? "gam" : "pgn",
\r
8370 "Save Game to File", NULL, fileTitle, NULL);
\r
8372 SaveGame(f, 0, "");
\r
8379 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8381 if (delayedTimerEvent != 0) {
\r
8382 if (appData.debugMode) {
\r
8383 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8385 KillTimer(hwndMain, delayedTimerEvent);
\r
8386 delayedTimerEvent = 0;
\r
8387 delayedTimerCallback();
\r
8389 delayedTimerCallback = cb;
\r
8390 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8391 (UINT) millisec, NULL);
\r
8394 DelayedEventCallback
\r
8397 if (delayedTimerEvent) {
\r
8398 return delayedTimerCallback;
\r
8405 CancelDelayedEvent()
\r
8407 if (delayedTimerEvent) {
\r
8408 KillTimer(hwndMain, delayedTimerEvent);
\r
8409 delayedTimerEvent = 0;
\r
8413 /* Start a child process running the given program.
\r
8414 The process's standard output can be read from "from", and its
\r
8415 standard input can be written to "to".
\r
8416 Exit with fatal error if anything goes wrong.
\r
8417 Returns an opaque pointer that can be used to destroy the process
\r
8421 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8423 #define BUFSIZE 4096
\r
8425 HANDLE hChildStdinRd, hChildStdinWr,
\r
8426 hChildStdoutRd, hChildStdoutWr;
\r
8427 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8428 SECURITY_ATTRIBUTES saAttr;
\r
8430 PROCESS_INFORMATION piProcInfo;
\r
8431 STARTUPINFO siStartInfo;
\r
8433 char buf[MSG_SIZ];
\r
8436 if (appData.debugMode) {
\r
8437 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8442 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8443 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8444 saAttr.bInheritHandle = TRUE;
\r
8445 saAttr.lpSecurityDescriptor = NULL;
\r
8448 * The steps for redirecting child's STDOUT:
\r
8449 * 1. Create anonymous pipe to be STDOUT for child.
\r
8450 * 2. Create a noninheritable duplicate of read handle,
\r
8451 * and close the inheritable read handle.
\r
8454 /* Create a pipe for the child's STDOUT. */
\r
8455 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8456 return GetLastError();
\r
8459 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8460 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8461 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8462 FALSE, /* not inherited */
\r
8463 DUPLICATE_SAME_ACCESS);
\r
8465 return GetLastError();
\r
8467 CloseHandle(hChildStdoutRd);
\r
8470 * The steps for redirecting child's STDIN:
\r
8471 * 1. Create anonymous pipe to be STDIN for child.
\r
8472 * 2. Create a noninheritable duplicate of write handle,
\r
8473 * and close the inheritable write handle.
\r
8476 /* Create a pipe for the child's STDIN. */
\r
8477 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8478 return GetLastError();
\r
8481 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8482 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8483 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8484 FALSE, /* not inherited */
\r
8485 DUPLICATE_SAME_ACCESS);
\r
8487 return GetLastError();
\r
8489 CloseHandle(hChildStdinWr);
\r
8491 /* Arrange to (1) look in dir for the child .exe file, and
\r
8492 * (2) have dir be the child's working directory. Interpret
\r
8493 * dir relative to the directory WinBoard loaded from. */
\r
8494 GetCurrentDirectory(MSG_SIZ, buf);
\r
8495 SetCurrentDirectory(installDir);
\r
8496 SetCurrentDirectory(dir);
\r
8498 /* Now create the child process. */
\r
8500 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8501 siStartInfo.lpReserved = NULL;
\r
8502 siStartInfo.lpDesktop = NULL;
\r
8503 siStartInfo.lpTitle = NULL;
\r
8504 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8505 siStartInfo.cbReserved2 = 0;
\r
8506 siStartInfo.lpReserved2 = NULL;
\r
8507 siStartInfo.hStdInput = hChildStdinRd;
\r
8508 siStartInfo.hStdOutput = hChildStdoutWr;
\r
8509 siStartInfo.hStdError = hChildStdoutWr;
\r
8511 fSuccess = CreateProcess(NULL,
\r
8512 cmdLine, /* command line */
\r
8513 NULL, /* process security attributes */
\r
8514 NULL, /* primary thread security attrs */
\r
8515 TRUE, /* handles are inherited */
\r
8516 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
8517 NULL, /* use parent's environment */
\r
8519 &siStartInfo, /* STARTUPINFO pointer */
\r
8520 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
8522 err = GetLastError();
\r
8523 SetCurrentDirectory(buf); /* return to prev directory */
\r
8528 /* Close the handles we don't need in the parent */
\r
8529 CloseHandle(piProcInfo.hThread);
\r
8530 CloseHandle(hChildStdinRd);
\r
8531 CloseHandle(hChildStdoutWr);
\r
8533 /* Prepare return value */
\r
8534 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8535 cp->kind = CPReal;
\r
8536 cp->hProcess = piProcInfo.hProcess;
\r
8537 cp->pid = piProcInfo.dwProcessId;
\r
8538 cp->hFrom = hChildStdoutRdDup;
\r
8539 cp->hTo = hChildStdinWrDup;
\r
8541 *pr = (void *) cp;
\r
8543 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
8544 2000 where engines sometimes don't see the initial command(s)
\r
8545 from WinBoard and hang. I don't understand how that can happen,
\r
8546 but the Sleep is harmless, so I've put it in. Others have also
\r
8547 reported what may be the same problem, so hopefully this will fix
\r
8548 it for them too. */
\r
8556 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
8560 cp = (ChildProc *) pr;
\r
8561 if (cp == NULL) return;
\r
8563 switch (cp->kind) {
\r
8565 /* TerminateProcess is considered harmful, so... */
\r
8566 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
8567 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
8568 /* The following doesn't work because the chess program
\r
8569 doesn't "have the same console" as WinBoard. Maybe
\r
8570 we could arrange for this even though neither WinBoard
\r
8571 nor the chess program uses a console for stdio? */
\r
8572 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
8574 /* [AS] Special termination modes for misbehaving programs... */
8576 if ( appData.debugMode) {
8577 fprintf( debugFP, "Terminating process %u\n", cp->pid );
8580 TerminateProcess( cp->hProcess, 0 );
8582 else if( signal == 10 ) {
8583 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
8585 if( dw != WAIT_OBJECT_0 ) {
8586 if ( appData.debugMode) {
8587 fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
8590 TerminateProcess( cp->hProcess, 0 );
8594 CloseHandle(cp->hProcess);
\r
8598 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
8602 closesocket(cp->sock);
\r
8607 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
8608 closesocket(cp->sock);
\r
8609 closesocket(cp->sock2);
\r
8617 InterruptChildProcess(ProcRef pr)
\r
8621 cp = (ChildProc *) pr;
\r
8622 if (cp == NULL) return;
\r
8623 switch (cp->kind) {
\r
8625 /* The following doesn't work because the chess program
\r
8626 doesn't "have the same console" as WinBoard. Maybe
\r
8627 we could arrange for this even though neither WinBoard
\r
8628 nor the chess program uses a console for stdio */
\r
8629 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
8634 /* Can't interrupt */
\r
8638 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
8645 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
8647 char cmdLine[MSG_SIZ];
\r
8649 if (port[0] == NULLCHAR) {
\r
8650 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
8652 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
8654 return StartChildProcess(cmdLine, "", pr);
\r
8658 /* Code to open TCP sockets */
\r
8661 OpenTCP(char *host, char *port, ProcRef *pr)
\r
8666 struct sockaddr_in sa, mysa;
\r
8667 struct hostent FAR *hp;
\r
8668 unsigned short uport;
\r
8669 WORD wVersionRequested;
\r
8672 /* Initialize socket DLL */
\r
8673 wVersionRequested = MAKEWORD(1, 1);
\r
8674 err = WSAStartup(wVersionRequested, &wsaData);
\r
8675 if (err != 0) return err;
\r
8678 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8679 err = WSAGetLastError();
\r
8684 /* Bind local address using (mostly) don't-care values.
\r
8686 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8687 mysa.sin_family = AF_INET;
\r
8688 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8689 uport = (unsigned short) 0;
\r
8690 mysa.sin_port = htons(uport);
\r
8691 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8692 == SOCKET_ERROR) {
\r
8693 err = WSAGetLastError();
\r
8698 /* Resolve remote host name */
\r
8699 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8700 if (!(hp = gethostbyname(host))) {
\r
8701 unsigned int b0, b1, b2, b3;
\r
8703 err = WSAGetLastError();
\r
8705 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8706 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8707 hp->h_addrtype = AF_INET;
\r
8709 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8710 hp->h_addr_list[0] = (char *) malloc(4);
\r
8711 hp->h_addr_list[0][0] = (char) b0;
\r
8712 hp->h_addr_list[0][1] = (char) b1;
\r
8713 hp->h_addr_list[0][2] = (char) b2;
\r
8714 hp->h_addr_list[0][3] = (char) b3;
\r
8720 sa.sin_family = hp->h_addrtype;
\r
8721 uport = (unsigned short) atoi(port);
\r
8722 sa.sin_port = htons(uport);
\r
8723 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8725 /* Make connection */
\r
8726 if (connect(s, (struct sockaddr *) &sa,
\r
8727 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8728 err = WSAGetLastError();
\r
8733 /* Prepare return value */
\r
8734 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8735 cp->kind = CPSock;
\r
8737 *pr = (ProcRef *) cp;
\r
8743 OpenCommPort(char *name, ProcRef *pr)
\r
8748 char fullname[MSG_SIZ];
\r
8750 if (*name != '\\')
\r
8751 sprintf(fullname, "\\\\.\\%s", name);
\r
8753 strcpy(fullname, name);
\r
8755 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
8756 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
8757 if (h == (HANDLE) -1) {
\r
8758 return GetLastError();
\r
8762 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
8764 /* Accumulate characters until a 100ms pause, then parse */
\r
8765 ct.ReadIntervalTimeout = 100;
\r
8766 ct.ReadTotalTimeoutMultiplier = 0;
\r
8767 ct.ReadTotalTimeoutConstant = 0;
\r
8768 ct.WriteTotalTimeoutMultiplier = 0;
\r
8769 ct.WriteTotalTimeoutConstant = 0;
\r
8770 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
8772 /* Prepare return value */
\r
8773 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8774 cp->kind = CPComm;
\r
8777 *pr = (ProcRef *) cp;
\r
8783 OpenLoopback(ProcRef *pr)
\r
8785 DisplayFatalError("Not implemented", 0, 1);
\r
8791 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
8796 struct sockaddr_in sa, mysa;
\r
8797 struct hostent FAR *hp;
\r
8798 unsigned short uport;
\r
8799 WORD wVersionRequested;
\r
8802 char stderrPortStr[MSG_SIZ];
\r
8804 /* Initialize socket DLL */
\r
8805 wVersionRequested = MAKEWORD(1, 1);
\r
8806 err = WSAStartup(wVersionRequested, &wsaData);
\r
8807 if (err != 0) return err;
\r
8809 /* Resolve remote host name */
\r
8810 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8811 if (!(hp = gethostbyname(host))) {
\r
8812 unsigned int b0, b1, b2, b3;
\r
8814 err = WSAGetLastError();
\r
8816 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8817 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8818 hp->h_addrtype = AF_INET;
\r
8820 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8821 hp->h_addr_list[0] = (char *) malloc(4);
\r
8822 hp->h_addr_list[0][0] = (char) b0;
\r
8823 hp->h_addr_list[0][1] = (char) b1;
\r
8824 hp->h_addr_list[0][2] = (char) b2;
\r
8825 hp->h_addr_list[0][3] = (char) b3;
\r
8831 sa.sin_family = hp->h_addrtype;
\r
8832 uport = (unsigned short) 514;
\r
8833 sa.sin_port = htons(uport);
\r
8834 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8836 /* Bind local socket to unused "privileged" port address
\r
8838 s = INVALID_SOCKET;
\r
8839 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8840 mysa.sin_family = AF_INET;
\r
8841 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8842 for (fromPort = 1023;; fromPort--) {
\r
8843 if (fromPort < 0) {
\r
8845 return WSAEADDRINUSE;
\r
8847 if (s == INVALID_SOCKET) {
\r
8848 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8849 err = WSAGetLastError();
\r
8854 uport = (unsigned short) fromPort;
\r
8855 mysa.sin_port = htons(uport);
\r
8856 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8857 == SOCKET_ERROR) {
\r
8858 err = WSAGetLastError();
\r
8859 if (err == WSAEADDRINUSE) continue;
\r
8863 if (connect(s, (struct sockaddr *) &sa,
\r
8864 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8865 err = WSAGetLastError();
\r
8866 if (err == WSAEADDRINUSE) {
\r
8877 /* Bind stderr local socket to unused "privileged" port address
\r
8879 s2 = INVALID_SOCKET;
\r
8880 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8881 mysa.sin_family = AF_INET;
\r
8882 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8883 for (fromPort = 1023;; fromPort--) {
\r
8884 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
8885 if (fromPort < 0) {
\r
8886 (void) closesocket(s);
\r
8888 return WSAEADDRINUSE;
\r
8890 if (s2 == INVALID_SOCKET) {
\r
8891 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8892 err = WSAGetLastError();
\r
8898 uport = (unsigned short) fromPort;
\r
8899 mysa.sin_port = htons(uport);
\r
8900 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8901 == SOCKET_ERROR) {
\r
8902 err = WSAGetLastError();
\r
8903 if (err == WSAEADDRINUSE) continue;
\r
8904 (void) closesocket(s);
\r
8908 if (listen(s2, 1) == SOCKET_ERROR) {
\r
8909 err = WSAGetLastError();
\r
8910 if (err == WSAEADDRINUSE) {
\r
8912 s2 = INVALID_SOCKET;
\r
8915 (void) closesocket(s);
\r
8916 (void) closesocket(s2);
\r
8922 prevStderrPort = fromPort; // remember port used
\r
8923 sprintf(stderrPortStr, "%d", fromPort);
\r
8925 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
8926 err = WSAGetLastError();
\r
8927 (void) closesocket(s);
\r
8928 (void) closesocket(s2);
\r
8933 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
8934 err = WSAGetLastError();
\r
8935 (void) closesocket(s);
\r
8936 (void) closesocket(s2);
\r
8940 if (*user == NULLCHAR) user = UserName();
\r
8941 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
8942 err = WSAGetLastError();
\r
8943 (void) closesocket(s);
\r
8944 (void) closesocket(s2);
\r
8948 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
8949 err = WSAGetLastError();
\r
8950 (void) closesocket(s);
\r
8951 (void) closesocket(s2);
\r
8956 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
8957 err = WSAGetLastError();
\r
8958 (void) closesocket(s);
\r
8959 (void) closesocket(s2);
\r
8963 (void) closesocket(s2); /* Stop listening */
\r
8965 /* Prepare return value */
\r
8966 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8967 cp->kind = CPRcmd;
\r
8970 *pr = (ProcRef *) cp;
\r
8977 AddInputSource(ProcRef pr, int lineByLine,
\r
8978 InputCallback func, VOIDSTAR closure)
\r
8980 InputSource *is, *is2 = NULL;
8981 ChildProc *cp = (ChildProc *) pr;
\r
8983 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
8984 is->lineByLine = lineByLine;
\r
8986 is->closure = closure;
\r
8987 is->second = NULL;
\r
8988 is->next = is->buf;
\r
8989 if (pr == NoProc) {
\r
8990 is->kind = CPReal;
\r
8991 consoleInputSource = is;
\r
8993 is->kind = cp->kind;
\r
8995 [AS] Try to avoid a race condition if the thread is given control too early:
8996 we create all threads suspended so that the is->hThread variable can be
8997 safely assigned, then let the threads start with ResumeThread.
8999 switch (cp->kind) {
\r
9001 is->hFile = cp->hFrom;
\r
9002 cp->hFrom = NULL; /* now owned by InputThread */
\r
9004 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9005 (LPVOID) is, CREATE_SUSPENDED, &is->id);
9009 is->hFile = cp->hFrom;
\r
9010 cp->hFrom = NULL; /* now owned by InputThread */
\r
9012 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9013 (LPVOID) is, CREATE_SUSPENDED, &is->id);
9017 is->sock = cp->sock;
\r
9019 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9020 (LPVOID) is, CREATE_SUSPENDED, &is->id);
9024 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9026 is->sock = cp->sock;
\r
9028 is2->sock = cp->sock2;
\r
9029 is2->second = is2;
\r
9031 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9032 (LPVOID) is, CREATE_SUSPENDED, &is->id);
9034 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9035 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
9039 if( is->hThread != NULL ) {
9040 ResumeThread( is->hThread );
9043 if( is2 != NULL && is2->hThread != NULL ) {
9044 ResumeThread( is2->hThread );
9048 return (InputSourceRef) is;
\r
9052 RemoveInputSource(InputSourceRef isr)
\r
9056 is = (InputSource *) isr;
\r
9057 is->hThread = NULL; /* tell thread to stop */
\r
9058 CloseHandle(is->hThread);
\r
9059 if (is->second != NULL) {
\r
9060 is->second->hThread = NULL;
\r
9061 CloseHandle(is->second->hThread);
\r
9067 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9070 int outCount = SOCKET_ERROR;
\r
9071 ChildProc *cp = (ChildProc *) pr;
\r
9072 static OVERLAPPED ovl;
\r
9074 if (pr == NoProc) {
\r
9075 ConsoleOutput(message, count, FALSE);
\r
9079 if (ovl.hEvent == NULL) {
\r
9080 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9082 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9084 switch (cp->kind) {
\r
9087 outCount = send(cp->sock, message, count, 0);
\r
9088 if (outCount == SOCKET_ERROR) {
\r
9089 *outError = WSAGetLastError();
\r
9091 *outError = NO_ERROR;
\r
9096 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9097 &dOutCount, NULL)) {
\r
9098 *outError = NO_ERROR;
\r
9099 outCount = (int) dOutCount;
\r
9101 *outError = GetLastError();
\r
9106 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9107 &dOutCount, &ovl);
\r
9108 if (*outError == NO_ERROR) {
\r
9109 outCount = (int) dOutCount;
\r
9117 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9120 /* Ignore delay, not implemented for WinBoard */
\r
9121 return OutputToProcess(pr, message, count, outError);
\r
9126 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9127 char *buf, int count, int error)
\r
9129 DisplayFatalError("Not implemented", 0, 1);
\r
9132 /* see wgamelist.c for Game List functions */
\r
9133 /* see wedittags.c for Edit Tags functions */
\r
9140 char buf[MSG_SIZ];
\r
9143 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9144 f = fopen(buf, "r");
\r
9146 ProcessICSInitScript(f);
\r
9154 StartAnalysisClock()
\r
9156 if (analysisTimerEvent) return;
\r
9157 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9158 (UINT) 2000, NULL);
\r
9162 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9164 static HANDLE hwndText;
\r
9166 static int sizeX, sizeY;
\r
9167 int newSizeX, newSizeY, flags;
\r
9170 switch (message) {
\r
9171 case WM_INITDIALOG: /* message: initialize dialog box */
\r
9172 /* Initialize the dialog items */
\r
9173 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
9174 SetWindowText(hDlg, analysisTitle);
\r
9175 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
9176 /* Size and position the dialog */
\r
9177 if (!analysisDialog) {
\r
9178 analysisDialog = hDlg;
\r
9179 flags = SWP_NOZORDER;
\r
9180 GetClientRect(hDlg, &rect);
\r
9181 sizeX = rect.right;
\r
9182 sizeY = rect.bottom;
\r
9183 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
9184 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
9185 WINDOWPLACEMENT wp;
\r
9186 EnsureOnScreen(&analysisX, &analysisY);
\r
9187 wp.length = sizeof(WINDOWPLACEMENT);
\r
9189 wp.showCmd = SW_SHOW;
\r
9190 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
9191 wp.rcNormalPosition.left = analysisX;
\r
9192 wp.rcNormalPosition.right = analysisX + analysisW;
\r
9193 wp.rcNormalPosition.top = analysisY;
\r
9194 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
9195 SetWindowPlacement(hDlg, &wp);
\r
9197 GetClientRect(hDlg, &rect);
\r
9198 newSizeX = rect.right;
\r
9199 newSizeY = rect.bottom;
\r
9200 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
9201 newSizeX, newSizeY);
\r
9208 case WM_COMMAND: /* message: received a command */
\r
9209 switch (LOWORD(wParam)) {
\r
9219 newSizeX = LOWORD(lParam);
\r
9220 newSizeY = HIWORD(lParam);
\r
9221 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
9226 case WM_GETMINMAXINFO:
\r
9227 /* Prevent resizing window too small */
\r
9228 mmi = (MINMAXINFO *) lParam;
\r
9229 mmi->ptMinTrackSize.x = 100;
\r
9230 mmi->ptMinTrackSize.y = 100;
\r
9237 AnalysisPopUp(char* title, char* str)
\r
9243 EngineOutputPopUp();
9246 if (str == NULL) str = "";
\r
9247 p = (char *) malloc(2 * strlen(str) + 2);
\r
9250 if (*str == '\n') *q++ = '\r';
\r
9254 if (analysisText != NULL) free(analysisText);
\r
9257 if (analysisDialog) {
\r
9258 SetWindowText(analysisDialog, title);
\r
9259 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
9260 ShowWindow(analysisDialog, SW_SHOW);
\r
9262 analysisTitle = title;
\r
9263 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
9264 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
9265 hwndMain, (DLGPROC)lpProc);
\r
9266 FreeProcInstance(lpProc);
\r
9268 analysisDialogUp = TRUE;
\r
9274 if (analysisDialog) {
\r
9275 ShowWindow(analysisDialog, SW_HIDE);
\r
9277 analysisDialogUp = FALSE;
\r
9282 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9284 highlightInfo.sq[0].x = fromX;
\r
9285 highlightInfo.sq[0].y = fromY;
\r
9286 highlightInfo.sq[1].x = toX;
\r
9287 highlightInfo.sq[1].y = toY;
\r
9293 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9294 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9298 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9300 premoveHighlightInfo.sq[0].x = fromX;
\r
9301 premoveHighlightInfo.sq[0].y = fromY;
\r
9302 premoveHighlightInfo.sq[1].x = toX;
\r
9303 premoveHighlightInfo.sq[1].y = toY;
\r
9307 ClearPremoveHighlights()
\r
9309 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9310 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9314 ShutDownFrontEnd()
\r
9316 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9317 DeleteClipboardTempFiles();
\r
9323 if (IsIconic(hwndMain))
\r
9324 ShowWindow(hwndMain, SW_RESTORE);
\r
9326 SetActiveWindow(hwndMain);
\r
9330 * Prototypes for animation support routines
\r
9332 static void ScreenSquare(int column, int row, POINT * pt);
\r
9333 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9334 POINT frames[], int * nFrames);
\r
9340 AnimateMove(board, fromX, fromY, toX, toY)
\r
9347 ChessSquare piece;
\r
9348 POINT start, finish, mid;
\r
9349 POINT frames[kFactor * 2 + 1];
\r
9352 if (!appData.animate) return;
\r
9353 if (doingSizing) return;
\r
9354 if (fromY < 0 || fromX < 0) return;
\r
9355 piece = board[fromY][fromX];
\r
9356 if (piece >= EmptySquare) return;
\r
9358 ScreenSquare(fromX, fromY, &start);
\r
9359 ScreenSquare(toX, toY, &finish);
\r
9361 /* All pieces except knights move in straight line */
\r
9362 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9363 mid.x = start.x + (finish.x - start.x) / 2;
\r
9364 mid.y = start.y + (finish.y - start.y) / 2;
\r
9366 /* Knight: make diagonal movement then straight */
\r
9367 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9368 mid.x = start.x + (finish.x - start.x) / 2;
\r
9372 mid.y = start.y + (finish.y - start.y) / 2;
\r
9376 /* Don't use as many frames for very short moves */
\r
9377 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9378 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9380 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9382 animInfo.from.x = fromX;
\r
9383 animInfo.from.y = fromY;
\r
9384 animInfo.to.x = toX;
\r
9385 animInfo.to.y = toY;
\r
9386 animInfo.lastpos = start;
\r
9387 animInfo.piece = piece;
\r
9388 for (n = 0; n < nFrames; n++) {
\r
9389 animInfo.pos = frames[n];
\r
9390 DrawPosition(FALSE, NULL);
\r
9391 animInfo.lastpos = animInfo.pos;
\r
9392 Sleep(appData.animSpeed);
\r
9394 animInfo.pos = finish;
\r
9395 DrawPosition(FALSE, NULL);
\r
9396 animInfo.piece = EmptySquare;
\r
9399 /* Convert board position to corner of screen rect and color */
\r
9402 ScreenSquare(column, row, pt)
\r
9403 int column; int row; POINT * pt;
\r
9406 pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
9407 pt->y = lineGap + row * (squareSize + lineGap);
\r
9409 pt->x = lineGap + column * (squareSize + lineGap);
\r
9410 pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
9414 /* Generate a series of frame coords from start->mid->finish.
\r
9415 The movement rate doubles until the half way point is
\r
9416 reached, then halves back down to the final destination,
\r
9417 which gives a nice slow in/out effect. The algorithmn
\r
9418 may seem to generate too many intermediates for short
\r
9419 moves, but remember that the purpose is to attract the
\r
9420 viewers attention to the piece about to be moved and
\r
9421 then to where it ends up. Too few frames would be less
\r
9425 Tween(start, mid, finish, factor, frames, nFrames)
\r
9426 POINT * start; POINT * mid;
\r
9427 POINT * finish; int factor;
\r
9428 POINT frames[]; int * nFrames;
\r
9430 int n, fraction = 1, count = 0;
\r
9432 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9433 for (n = 0; n < factor; n++)
\r
9435 for (n = 0; n < factor; n++) {
\r
9436 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9437 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9439 fraction = fraction / 2;
\r
9443 frames[count] = *mid;
\r
9446 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9448 for (n = 0; n < factor; n++) {
\r
9449 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9450 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9452 fraction = fraction * 2;
\r
9458 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
9463 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
9464 first, last, current, current >= 0 ? movelist[current] : "n/a" );
9466 OutputDebugString( buf );
9469 MoveHistorySet( movelist, first, last, current, pvInfoList );
9471 EvalGraphSet( first, last, current, pvInfoList );
9474 void SetProgramStats( int which, int depth, unsigned long nodes, int score, int time, char * pv, char * hint )
9479 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
9480 which, depth, nodes, score / 100.0, time / 100.0, pv == 0 ? "n/a" : pv );
9482 OutputDebugString( buf );
9485 EngineOutputUpdate( which, depth, nodes, score, time, pv, hint );