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), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
243 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
244 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
245 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
246 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
247 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
248 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
249 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
250 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
251 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
252 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
253 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
254 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
255 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
256 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
257 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
258 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
259 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
262 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
271 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
272 #define N_BUTTONS 5
\r
274 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
276 {"<<", IDM_ToStart, NULL, NULL},
\r
277 {"<", IDM_Backward, NULL, NULL},
\r
278 {"P", IDM_Pause, NULL, NULL},
\r
279 {">", IDM_Forward, NULL, NULL},
\r
280 {">>", IDM_ToEnd, NULL, NULL},
\r
283 int tinyLayout = 0, smallLayout = 0;
\r
284 #define MENU_BAR_ITEMS 6
\r
285 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
286 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
287 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
291 MySound sounds[(int)NSoundClasses];
\r
292 MyTextAttribs textAttribs[(int)NColorClasses];
\r
294 MyColorizeAttribs colorizeAttribs[] = {
\r
295 { (COLORREF)0, 0, "Shout Text" },
\r
296 { (COLORREF)0, 0, "SShout/CShout" },
\r
297 { (COLORREF)0, 0, "Channel 1 Text" },
\r
298 { (COLORREF)0, 0, "Channel Text" },
\r
299 { (COLORREF)0, 0, "Kibitz Text" },
\r
300 { (COLORREF)0, 0, "Tell Text" },
\r
301 { (COLORREF)0, 0, "Challenge Text" },
\r
302 { (COLORREF)0, 0, "Request Text" },
\r
303 { (COLORREF)0, 0, "Seek Text" },
\r
304 { (COLORREF)0, 0, "Normal Text" },
\r
305 { (COLORREF)0, 0, "None" }
\r
310 static char *commentTitle;
\r
311 static char *commentText;
\r
312 static int commentIndex;
\r
313 static Boolean editComment = FALSE;
\r
314 HWND commentDialog = NULL;
\r
315 BOOLEAN commentDialogUp = FALSE;
\r
316 static int commentX, commentY, commentH, commentW;
\r
318 static char *analysisTitle;
\r
319 static char *analysisText;
\r
320 HWND analysisDialog = NULL;
\r
321 BOOLEAN analysisDialogUp = FALSE;
\r
322 static int analysisX, analysisY, analysisH, analysisW;
\r
324 char errorTitle[MSG_SIZ];
\r
325 char errorMessage[2*MSG_SIZ];
\r
326 HWND errorDialog = NULL;
\r
327 BOOLEAN moveErrorMessageUp = FALSE;
\r
328 BOOLEAN consoleEcho = TRUE;
\r
329 CHARFORMAT consoleCF;
\r
330 COLORREF consoleBackgroundColor;
\r
332 char *programVersion;
\r
338 typedef int CPKind;
\r
347 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
350 #define INPUT_SOURCE_BUF_SIZE 4096
\r
352 typedef struct _InputSource {
\r
359 char buf[INPUT_SOURCE_BUF_SIZE];
\r
363 InputCallback func;
\r
364 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
368 InputSource *consoleInputSource;
\r
373 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
374 VOID ConsoleCreate();
\r
376 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
377 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
378 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
379 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
381 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
382 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
383 void ParseIcsTextMenu(char *icsTextMenuString);
\r
384 VOID PopUpMoveDialog(char firstchar);
\r
385 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
389 int GameListOptions();
391 HWND moveHistoryDialog = NULL;
392 BOOLEAN moveHistoryDialogUp = FALSE;
394 WindowPlacement wpMoveHistory;
396 HWND evalGraphDialog = NULL;
397 BOOLEAN evalGraphDialogUp = FALSE;
399 WindowPlacement wpEvalGraph;
401 HWND engineOutputDialog = NULL;
402 BOOLEAN engineOutputDialogUp = FALSE;
404 WindowPlacement wpEngineOutput;
406 VOID MoveHistoryPopUp();
407 VOID MoveHistoryPopDown();
408 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
409 BOOL MoveHistoryIsUp();
411 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
412 VOID EvalGraphPopUp();
413 VOID EvalGraphPopDown();
414 BOOL EvalGraphIsUp();
416 VOID EngineOutputPopUp();
417 VOID EngineOutputPopDown();
418 BOOL EngineOutputIsUp();
419 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
422 * Setting "frozen" should disable all user input other than deleting
\r
423 * the window. We do this while engines are initializing themselves.
\r
425 static int frozen = 0;
\r
426 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
432 if (frozen) return;
\r
434 hmenu = GetMenu(hwndMain);
\r
435 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
436 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
438 DrawMenuBar(hwndMain);
\r
441 /* Undo a FreezeUI */
\r
447 if (!frozen) return;
\r
449 hmenu = GetMenu(hwndMain);
\r
450 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
451 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
453 DrawMenuBar(hwndMain);
\r
456 /*---------------------------------------------------------------------------*\
\r
460 \*---------------------------------------------------------------------------*/
\r
463 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
464 LPSTR lpCmdLine, int nCmdShow)
\r
467 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
471 LoadLibrary("RICHED32.DLL");
\r
472 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
474 if (!InitApplication(hInstance)) {
\r
477 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
481 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
482 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
483 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
485 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
487 while (GetMessage(&msg, /* message structure */
\r
488 NULL, /* handle of window receiving the message */
\r
489 0, /* lowest message to examine */
\r
490 0)) /* highest message to examine */
\r
492 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
493 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
494 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
495 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
496 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
497 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
498 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
499 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
500 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
501 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
502 TranslateMessage(&msg); /* Translates virtual key codes */
\r
503 DispatchMessage(&msg); /* Dispatches message to window */
\r
508 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
511 /*---------------------------------------------------------------------------*\
\r
513 * Initialization functions
\r
515 \*---------------------------------------------------------------------------*/
\r
518 InitApplication(HINSTANCE hInstance)
\r
522 /* Fill in window class structure with parameters that describe the */
\r
525 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
526 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
527 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
528 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
529 wc.hInstance = hInstance; /* Owner of this class */
\r
530 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
531 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
532 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
533 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
534 wc.lpszClassName = szAppName; /* Name to register as */
\r
536 /* Register the window class and return success/failure code. */
\r
537 if (!RegisterClass(&wc)) return FALSE;
\r
539 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
540 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
542 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
543 wc.hInstance = hInstance;
\r
544 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
545 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
546 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
547 wc.lpszMenuName = NULL;
\r
548 wc.lpszClassName = szConsoleName;
\r
550 if (!RegisterClass(&wc)) return FALSE;
\r
555 /* Set by InitInstance, used by EnsureOnScreen */
\r
556 int screenHeight, screenWidth;
\r
559 EnsureOnScreen(int *x, int *y)
\r
561 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
562 if (*x > screenWidth - 32) *x = 0;
\r
563 if (*y > screenHeight - 32) *y = 0;
\r
567 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
569 HWND hwnd; /* Main window handle. */
\r
571 WINDOWPLACEMENT wp;
\r
574 hInst = hInstance; /* Store instance handle in our global variable */
\r
576 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
577 *filepart = NULLCHAR;
\r
579 GetCurrentDirectory(MSG_SIZ, installDir);
\r
581 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
582 if (appData.debugMode) {
\r
583 debugFP = fopen(appData.nameOfDebugFile, "w");
584 setbuf(debugFP, NULL);
\r
589 InitEngineUCI( installDir, &first );
590 InitEngineUCI( installDir, &second );
592 /* Create a main window for this application instance. */
\r
593 hwnd = CreateWindow(szAppName, szTitle,
\r
594 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
595 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
596 NULL, NULL, hInstance, NULL);
\r
599 /* If window could not be created, return "failure" */
\r
604 iconWhite = LoadIcon(hInstance, "icon_white");
\r
605 iconBlack = LoadIcon(hInstance, "icon_black");
\r
606 iconCurrent = iconWhite;
\r
607 InitDrawingColors();
\r
608 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
609 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
610 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
611 /* Compute window size for each board size, and use the largest
\r
612 size that fits on this screen as the default. */
\r
613 InitDrawingSizes((BoardSize)ibs, 0);
\r
614 if (boardSize == (BoardSize)-1 &&
\r
615 winHeight <= screenHeight && winWidth <= screenWidth) {
\r
616 boardSize = (BoardSize)ibs;
\r
619 InitDrawingSizes(boardSize, 0);
\r
621 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
623 /* [AS] Load textures if specified */
624 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
626 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
627 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
628 liteBackTextureMode = appData.liteBackTextureMode;
630 if (liteBackTexture == NULL && appData.debugMode) {
631 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
635 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
636 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
637 darkBackTextureMode = appData.darkBackTextureMode;
639 if (darkBackTexture == NULL && appData.debugMode) {
640 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
644 mysrandom( (unsigned) time(NULL) );
646 /* Make a console window if needed */
\r
647 if (appData.icsActive) {
\r
651 /* [AS] Restore layout */
652 if( wpMoveHistory.visible ) {
656 if( wpEvalGraph.visible ) {
660 if( wpEngineOutput.visible ) {
666 /* Make the window visible; update its client area; and return "success" */
\r
667 EnsureOnScreen(&boardX, &boardY);
\r
668 wp.length = sizeof(WINDOWPLACEMENT);
\r
670 wp.showCmd = nCmdShow;
\r
671 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
672 wp.rcNormalPosition.left = boardX;
\r
673 wp.rcNormalPosition.right = boardX + winWidth;
\r
674 wp.rcNormalPosition.top = boardY;
\r
675 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
676 SetWindowPlacement(hwndMain, &wp);
\r
678 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
679 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
681 /* [AS] Disable the FRC stuff if not playing the proper variant */
682 if( gameInfo.variant != VariantFischeRandom ) {
683 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
688 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
689 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
691 ShowWindow(hwndConsole, nCmdShow);
\r
693 UpdateWindow(hwnd);
\r
701 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
702 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
703 ArgSettingsFilename
\r
711 String *pString; // ArgString
\r
712 int *pInt; // ArgInt
\r
713 float *pFloat; // ArgFloat
\r
714 Boolean *pBoolean; // ArgBoolean
\r
715 COLORREF *pColor; // ArgColor
\r
716 ColorClass cc; // ArgAttribs
\r
717 String *pFilename; // ArgFilename
\r
718 BoardSize *pBoardSize; // ArgBoardSize
\r
719 int whichFont; // ArgFont
\r
720 DCB *pDCB; // ArgCommSettings
\r
721 String *pFilename; // ArgSettingsFilename
\r
729 ArgDescriptor argDescriptors[] = {
\r
730 /* positional arguments */
\r
731 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
732 { "", ArgNone, NULL },
\r
733 /* keyword arguments */
\r
734 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
735 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
736 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
737 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
738 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
739 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
740 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
741 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
742 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
743 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
744 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
745 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
746 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
747 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
748 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
749 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
750 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
751 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
753 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
755 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
757 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
758 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
760 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
761 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
762 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
763 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
764 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
765 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
766 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
767 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
768 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
769 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
770 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
771 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
772 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
773 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
774 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
775 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
776 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
777 /*!!bitmapDirectory?*/
\r
778 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
779 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
780 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
781 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
782 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
783 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
784 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
785 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
786 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
787 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
788 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
789 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
790 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
791 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
792 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
793 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
794 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
795 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
796 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
797 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
798 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
799 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
800 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
801 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
802 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
803 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
804 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
805 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
806 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
807 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
808 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
809 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
810 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
811 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
812 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
813 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
814 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
815 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
816 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
817 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
818 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
819 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
820 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
821 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
822 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
823 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
824 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
825 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
826 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
827 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
828 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
829 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
830 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
831 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
832 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
833 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
834 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
835 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
836 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
837 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
838 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
839 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
840 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
841 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
842 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
843 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
844 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
845 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
846 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
847 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
848 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
849 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
850 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
851 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
852 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
853 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
854 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
855 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
856 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
857 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
858 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
859 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
860 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
861 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
862 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
863 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
864 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
865 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
866 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
867 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
868 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
869 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
870 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
871 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
872 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
873 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
874 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
875 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
876 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
877 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
878 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
879 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
880 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
881 TRUE }, /* must come after all fonts */
\r
882 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
883 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
884 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
885 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
886 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
887 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
888 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
889 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
890 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
891 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
892 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
893 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
894 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
895 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
896 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
897 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
898 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
899 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
900 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
901 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
902 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
903 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
904 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
905 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
906 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
907 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
908 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
909 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
910 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
911 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
912 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
914 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
915 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
917 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
918 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
919 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
920 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
921 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
922 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
923 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
924 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
925 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
926 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
927 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
928 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
929 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
930 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
931 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
932 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
933 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
934 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
935 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
936 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
937 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
938 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
939 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
940 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
941 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
942 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
943 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
944 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
945 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
946 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
947 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
948 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
949 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
950 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
951 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
952 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
953 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
954 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
955 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
956 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
957 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
958 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
959 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
960 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
961 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
962 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
963 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
964 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
965 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
966 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
967 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
968 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
969 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
970 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
971 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
972 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
973 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
974 { "highlightLastMove", ArgBoolean,
\r
975 (LPVOID) &appData.highlightLastMove, TRUE },
\r
976 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
977 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
978 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
979 { "highlightDragging", ArgBoolean,
\r
980 (LPVOID) &appData.highlightDragging, TRUE },
\r
981 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
982 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
983 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
984 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
985 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
986 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
987 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
988 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
989 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
990 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
991 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
992 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
993 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
994 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
995 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
996 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
997 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
998 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
999 { "soundShout", ArgFilename,
\r
1000 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1001 { "soundSShout", ArgFilename,
\r
1002 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1003 { "soundChannel1", ArgFilename,
\r
1004 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1005 { "soundChannel", ArgFilename,
\r
1006 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1007 { "soundKibitz", ArgFilename,
\r
1008 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1009 { "soundTell", ArgFilename,
\r
1010 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1011 { "soundChallenge", ArgFilename,
\r
1012 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1013 { "soundRequest", ArgFilename,
\r
1014 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1015 { "soundSeek", ArgFilename,
\r
1016 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1017 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1018 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1019 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1020 { "soundIcsLoss", ArgFilename,
\r
1021 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1022 { "soundIcsDraw", ArgFilename,
\r
1023 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1024 { "soundIcsUnfinished", ArgFilename,
\r
1025 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1026 { "soundIcsAlarm", ArgFilename,
\r
1027 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1028 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1029 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1030 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1031 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1032 { "reuseChessPrograms", ArgBoolean,
\r
1033 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1034 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1035 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1036 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1037 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1038 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1039 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1040 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1041 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1042 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1043 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1044 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1045 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1046 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1047 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1048 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1049 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1050 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1051 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1052 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1053 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1054 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1055 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1056 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1057 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1058 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1059 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1060 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1061 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1062 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1063 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1064 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1065 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1066 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1067 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1068 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1069 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1070 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1072 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1074 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1075 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1076 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1077 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
1078 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
1079 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1080 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1081 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1082 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1083 /* [AS] New features */
1084 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
1085 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
1086 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
1087 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
1088 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
1089 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
1090 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
1091 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
1092 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
1093 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
1094 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
1095 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
1096 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
1097 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
1098 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
1099 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
1100 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
1101 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
1102 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
1103 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
1104 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
1105 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
1106 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
1107 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
1108 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
1109 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
1110 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
1111 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
1112 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
1113 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
1114 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
1115 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
1116 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
1117 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
1118 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
1119 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
1120 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
1121 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
1122 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
1123 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
1124 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
1125 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
1126 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
1127 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
1128 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
1129 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
1130 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
1131 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
1133 /* [AS] Layout stuff */
1134 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
1135 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
1136 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
1137 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
1138 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
1140 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
1141 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
1142 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
1143 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
1144 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
1146 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
1147 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
1148 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
1149 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
1150 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
1153 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1154 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1155 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1156 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1157 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1158 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1159 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1160 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1161 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1162 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1163 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1164 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1165 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1167 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1168 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1169 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1170 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1171 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1172 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1173 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1175 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1176 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1177 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1178 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1179 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1180 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1181 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1182 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1183 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1184 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1185 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1186 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1187 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1188 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1189 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1190 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1191 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1192 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1194 { NULL, ArgNone, NULL, FALSE }
\r
1198 /* Kludge for indirection files on command line */
\r
1199 char* lastIndirectionFilename;
\r
1200 ArgDescriptor argDescriptorIndirection =
\r
1201 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1205 ExitArgError(char *msg, char *badArg)
\r
1207 char buf[MSG_SIZ];
\r
1209 sprintf(buf, "%s %s", msg, badArg);
\r
1210 DisplayFatalError(buf, 0, 2);
\r
1214 /* Command line font name parser. NULL name means do nothing.
\r
1215 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1216 For backward compatibility, syntax without the colon is also
\r
1217 accepted, but font names with digits in them won't work in that case.
\r
1220 ParseFontName(char *name, MyFontParams *mfp)
\r
1223 if (name == NULL) return;
\r
1225 q = strchr(p, ':');
\r
1227 if (q - p >= sizeof(mfp->faceName))
\r
1228 ExitArgError("Font name too long:", name);
\r
1229 memcpy(mfp->faceName, p, q - p);
\r
1230 mfp->faceName[q - p] = NULLCHAR;
\r
1233 q = mfp->faceName;
\r
1234 while (*p && !isdigit(*p)) {
\r
1236 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1237 ExitArgError("Font name too long:", name);
\r
1239 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1242 if (!*p) ExitArgError("Font point size missing:", name);
\r
1243 mfp->pointSize = (float) atof(p);
\r
1244 mfp->bold = (strchr(p, 'b') != NULL);
\r
1245 mfp->italic = (strchr(p, 'i') != NULL);
\r
1246 mfp->underline = (strchr(p, 'u') != NULL);
\r
1247 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1250 /* Color name parser.
\r
1251 X version accepts X color names, but this one
\r
1252 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1254 ParseColorName(char *name)
\r
1256 int red, green, blue, count;
\r
1257 char buf[MSG_SIZ];
\r
1259 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1261 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1262 &red, &green, &blue);
\r
1265 sprintf(buf, "Can't parse color name %s", name);
\r
1266 DisplayError(buf, 0);
\r
1267 return RGB(0, 0, 0);
\r
1269 return PALETTERGB(red, green, blue);
\r
1273 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1275 char *e = argValue;
\r
1279 if (*e == 'b') eff |= CFE_BOLD;
\r
1280 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1281 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1282 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1283 else if (*e == '#' || isdigit(*e)) break;
\r
1287 *color = ParseColorName(e);
\r
1292 ParseBoardSize(char *name)
\r
1294 BoardSize bs = SizeTiny;
\r
1295 while (sizeInfo[bs].name != NULL) {
\r
1296 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1299 ExitArgError("Unrecognized board size value", name);
\r
1300 return bs; /* not reached */
\r
1305 StringGet(void *getClosure)
\r
1307 char **p = (char **) getClosure;
\r
1312 FileGet(void *getClosure)
\r
1315 FILE* f = (FILE*) getClosure;
\r
1324 /* Parse settings file named "name". If file found, return the
\r
1325 full name in fullname and return TRUE; else return FALSE */
\r
1327 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1332 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1333 f = fopen(fullname, "r");
\r
1335 ParseArgs(FileGet, f);
\r
1344 ParseArgs(GetFunc get, void *cl)
\r
1346 char argName[ARG_MAX];
\r
1347 char argValue[ARG_MAX];
\r
1348 ArgDescriptor *ad;
\r
1357 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1358 if (ch == NULLCHAR) break;
\r
1360 /* Comment to end of line */
\r
1362 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1364 } else if (ch == '/' || ch == '-') {
\r
1367 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1368 ch != '\n' && ch != '\t') {
\r
1374 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1375 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1377 if (ad->argName == NULL)
\r
1378 ExitArgError("Unrecognized argument", argName);
\r
1380 } else if (ch == '@') {
\r
1381 /* Indirection file */
\r
1382 ad = &argDescriptorIndirection;
\r
1385 /* Positional argument */
\r
1386 ad = &argDescriptors[posarg++];
\r
1387 strcpy(argName, ad->argName);
\r
1390 if (ad->argType == ArgTrue) {
\r
1391 *(Boolean *) ad->argLoc = TRUE;
\r
1394 if (ad->argType == ArgFalse) {
\r
1395 *(Boolean *) ad->argLoc = FALSE;
\r
1399 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1400 if (ch == NULLCHAR || ch == '\n') {
\r
1401 ExitArgError("No value provided for argument", argName);
\r
1405 // Quoting with { }. No characters have to (or can) be escaped.
\r
1406 // Thus the string cannot contain a '}' character.
\r
1426 } else if (ch == '\'' || ch == '"') {
\r
1427 // Quoting with ' ' or " ", with \ as escape character.
\r
1428 // Inconvenient for long strings that may contain Windows filenames.
\r
1445 if (ch == start) {
\r
1454 if (ad->argType == ArgFilename
\r
1455 || ad->argType == ArgSettingsFilename) {
\r
1461 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1485 for (i = 0; i < 3; i++) {
\r
1486 if (ch >= '0' && ch <= '7') {
\r
1487 octval = octval*8 + (ch - '0');
\r
1494 *q++ = (char) octval;
\r
1505 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1512 switch (ad->argType) {
\r
1514 *(int *) ad->argLoc = atoi(argValue);
\r
1518 *(float *) ad->argLoc = (float) atof(argValue);
\r
1523 *(char **) ad->argLoc = strdup(argValue);
\r
1526 case ArgSettingsFilename:
\r
1528 char fullname[MSG_SIZ];
\r
1529 if (ParseSettingsFile(argValue, fullname)) {
\r
1530 if (ad->argLoc != NULL) {
\r
1531 *(char **) ad->argLoc = strdup(fullname);
\r
1534 if (ad->argLoc != NULL) {
\r
1536 ExitArgError("Failed to open indirection file", argValue);
\r
1543 switch (argValue[0]) {
\r
1546 *(Boolean *) ad->argLoc = TRUE;
\r
1550 *(Boolean *) ad->argLoc = FALSE;
\r
1553 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1559 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1562 case ArgAttribs: {
\r
1563 ColorClass cc = (ColorClass)ad->argLoc;
\r
1564 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1568 case ArgBoardSize:
\r
1569 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1573 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1576 case ArgCommSettings:
\r
1577 ParseCommSettings(argValue, &dcb);
\r
1581 ExitArgError("Unrecognized argument", argValue);
\r
1588 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1590 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1591 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1594 lf->lfEscapement = 0;
\r
1595 lf->lfOrientation = 0;
\r
1596 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1597 lf->lfItalic = mfp->italic;
\r
1598 lf->lfUnderline = mfp->underline;
\r
1599 lf->lfStrikeOut = mfp->strikeout;
\r
1600 lf->lfCharSet = DEFAULT_CHARSET;
\r
1601 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1602 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1603 lf->lfQuality = DEFAULT_QUALITY;
\r
1604 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1605 strcpy(lf->lfFaceName, mfp->faceName);
\r
1609 CreateFontInMF(MyFont *mf)
\r
1611 LFfromMFP(&mf->lf, &mf->mfp);
\r
1612 if (mf->hf) DeleteObject(mf->hf);
\r
1613 mf->hf = CreateFontIndirect(&mf->lf);
\r
1617 SetDefaultTextAttribs()
\r
1620 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1621 ParseAttribs(&textAttribs[cc].color,
\r
1622 &textAttribs[cc].effects,
\r
1623 defaultTextAttribs[cc]);
\r
1628 SetDefaultSounds()
\r
1632 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1633 textAttribs[cc].sound.name = strdup("");
\r
1634 textAttribs[cc].sound.data = NULL;
\r
1636 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1637 sounds[sc].name = strdup("");
\r
1638 sounds[sc].data = NULL;
\r
1640 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1648 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1649 MyLoadSound(&textAttribs[cc].sound);
\r
1651 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1652 MyLoadSound(&sounds[sc]);
\r
1657 InitAppData(LPSTR lpCmdLine)
\r
1660 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1663 programName = szAppName;
\r
1665 /* Initialize to defaults */
\r
1666 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1667 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1668 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1669 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1670 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1671 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1672 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1673 SetDefaultTextAttribs();
\r
1674 SetDefaultSounds();
\r
1675 appData.movesPerSession = MOVES_PER_SESSION;
\r
1676 appData.initString = INIT_STRING;
\r
1677 appData.secondInitString = INIT_STRING;
\r
1678 appData.firstComputerString = COMPUTER_STRING;
\r
1679 appData.secondComputerString = COMPUTER_STRING;
\r
1680 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1681 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1682 appData.firstPlaysBlack = FALSE;
\r
1683 appData.noChessProgram = FALSE;
\r
1684 chessProgram = FALSE;
\r
1685 appData.firstHost = FIRST_HOST;
\r
1686 appData.secondHost = SECOND_HOST;
\r
1687 appData.firstDirectory = FIRST_DIRECTORY;
\r
1688 appData.secondDirectory = SECOND_DIRECTORY;
\r
1689 appData.bitmapDirectory = "";
\r
1690 appData.remoteShell = REMOTE_SHELL;
\r
1691 appData.remoteUser = "";
\r
1692 appData.timeDelay = TIME_DELAY;
\r
1693 appData.timeControl = TIME_CONTROL;
\r
1694 appData.timeIncrement = TIME_INCREMENT;
\r
1695 appData.icsActive = FALSE;
\r
1696 appData.icsHost = "";
\r
1697 appData.icsPort = ICS_PORT;
\r
1698 appData.icsCommPort = ICS_COMM_PORT;
\r
1699 appData.icsLogon = ICS_LOGON;
\r
1700 appData.icsHelper = "";
\r
1701 appData.useTelnet = FALSE;
\r
1702 appData.telnetProgram = TELNET_PROGRAM;
\r
1703 appData.gateway = "";
\r
1704 appData.loadGameFile = "";
\r
1705 appData.loadGameIndex = 0;
\r
1706 appData.saveGameFile = "";
\r
1707 appData.autoSaveGames = FALSE;
\r
1708 appData.loadPositionFile = "";
\r
1709 appData.loadPositionIndex = 1;
\r
1710 appData.savePositionFile = "";
\r
1711 appData.matchMode = FALSE;
\r
1712 appData.matchGames = 0;
\r
1713 appData.monoMode = FALSE;
\r
1714 appData.debugMode = FALSE;
\r
1715 appData.clockMode = TRUE;
\r
1716 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1717 appData.Iconic = FALSE; /*unused*/
\r
1718 appData.searchTime = "";
\r
1719 appData.searchDepth = 0;
\r
1720 appData.showCoords = FALSE;
\r
1721 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1722 appData.autoCallFlag = FALSE;
\r
1723 appData.flipView = FALSE;
\r
1724 appData.autoFlipView = TRUE;
\r
1725 appData.cmailGameName = "";
\r
1726 appData.alwaysPromoteToQueen = FALSE;
\r
1727 appData.oldSaveStyle = FALSE;
\r
1728 appData.quietPlay = FALSE;
\r
1729 appData.showThinking = FALSE;
\r
1730 appData.ponderNextMove = TRUE;
\r
1731 appData.periodicUpdates = TRUE;
\r
1732 appData.popupExitMessage = TRUE;
\r
1733 appData.popupMoveErrors = FALSE;
\r
1734 appData.autoObserve = FALSE;
\r
1735 appData.autoComment = FALSE;
\r
1736 appData.animate = TRUE;
\r
1737 appData.animSpeed = 10;
\r
1738 appData.animateDragging = TRUE;
\r
1739 appData.highlightLastMove = TRUE;
\r
1740 appData.getMoveList = TRUE;
\r
1741 appData.testLegality = TRUE;
\r
1742 appData.premove = TRUE;
\r
1743 appData.premoveWhite = FALSE;
\r
1744 appData.premoveWhiteText = "";
\r
1745 appData.premoveBlack = FALSE;
\r
1746 appData.premoveBlackText = "";
\r
1747 appData.icsAlarm = TRUE;
\r
1748 appData.icsAlarmTime = 5000;
\r
1749 appData.autoRaiseBoard = TRUE;
\r
1750 appData.localLineEditing = TRUE;
\r
1751 appData.colorize = TRUE;
\r
1752 appData.reuseFirst = TRUE;
\r
1753 appData.reuseSecond = TRUE;
\r
1754 appData.blindfold = FALSE;
\r
1755 dcb.DCBlength = sizeof(DCB);
\r
1756 dcb.BaudRate = 9600;
\r
1757 dcb.fBinary = TRUE;
\r
1758 dcb.fParity = FALSE;
\r
1759 dcb.fOutxCtsFlow = FALSE;
\r
1760 dcb.fOutxDsrFlow = FALSE;
\r
1761 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1762 dcb.fDsrSensitivity = FALSE;
\r
1763 dcb.fTXContinueOnXoff = TRUE;
\r
1764 dcb.fOutX = FALSE;
\r
1766 dcb.fNull = FALSE;
\r
1767 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1768 dcb.fAbortOnError = FALSE;
\r
1769 dcb.wReserved = 0;
\r
1771 dcb.Parity = SPACEPARITY;
\r
1772 dcb.StopBits = ONESTOPBIT;
\r
1773 settingsFileName = SETTINGS_FILE;
\r
1774 saveSettingsOnExit = TRUE;
\r
1775 boardX = CW_USEDEFAULT;
\r
1776 boardY = CW_USEDEFAULT;
\r
1777 consoleX = CW_USEDEFAULT;
\r
1778 consoleY = CW_USEDEFAULT;
\r
1779 consoleW = CW_USEDEFAULT;
\r
1780 consoleH = CW_USEDEFAULT;
\r
1781 analysisX = CW_USEDEFAULT;
\r
1782 analysisY = CW_USEDEFAULT;
\r
1783 analysisW = CW_USEDEFAULT;
\r
1784 analysisH = CW_USEDEFAULT;
\r
1785 commentX = CW_USEDEFAULT;
\r
1786 commentY = CW_USEDEFAULT;
\r
1787 commentW = CW_USEDEFAULT;
\r
1788 commentH = CW_USEDEFAULT;
\r
1789 editTagsX = CW_USEDEFAULT;
\r
1790 editTagsY = CW_USEDEFAULT;
\r
1791 editTagsW = CW_USEDEFAULT;
\r
1792 editTagsH = CW_USEDEFAULT;
\r
1793 gameListX = CW_USEDEFAULT;
\r
1794 gameListY = CW_USEDEFAULT;
\r
1795 gameListW = CW_USEDEFAULT;
\r
1796 gameListH = CW_USEDEFAULT;
\r
1797 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1798 icsNames = ICS_NAMES;
\r
1799 firstChessProgramNames = FCP_NAMES;
\r
1800 secondChessProgramNames = SCP_NAMES;
\r
1801 appData.initialMode = "";
\r
1802 appData.variant = "normal";
\r
1803 appData.firstProtocolVersion = PROTOVER;
\r
1804 appData.secondProtocolVersion = PROTOVER;
\r
1805 appData.showButtonBar = TRUE;
\r
1807 /* [AS] New properties (see comments in header file) */
1808 appData.firstScoreIsAbsolute = FALSE;
1809 appData.secondScoreIsAbsolute = FALSE;
1810 appData.saveExtendedInfoInPGN = FALSE;
1811 appData.hideThinkingFromHuman = FALSE;
1812 appData.liteBackTextureFile = "";
1813 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
1814 appData.darkBackTextureFile = "";
1815 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
1816 appData.renderPiecesWithFont = "";
1817 appData.fontToPieceTable = "";
1818 appData.fontBackColorWhite = 0;
1819 appData.fontForeColorWhite = 0;
1820 appData.fontBackColorBlack = 0;
1821 appData.fontForeColorBlack = 0;
1822 appData.fontPieceSize = 80;
1823 appData.overrideLineGap = 1;
1824 appData.adjudicateLossThreshold = 0;
1825 appData.delayBeforeQuit = 0;
1826 appData.delayAfterQuit = 0;
1827 appData.nameOfDebugFile = "winboard.debug";
1828 appData.pgnEventHeader = "Computer Chess Game";
1829 appData.defaultFrcPosition = -1;
1830 appData.gameListTags = GLT_DEFAULT_TAGS;
1831 appData.saveOutOfBookInfo = TRUE;
1832 appData.showEvalInMoveHistory = TRUE;
1833 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
1834 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
1835 appData.highlightMoveWithArrow = FALSE;
1836 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
1837 appData.useStickyWindows = TRUE;
1838 appData.adjudicateDrawMoves = 0;
1839 appData.autoDisplayComment = TRUE;
1840 appData.autoDisplayTags = TRUE;
1841 appData.firstIsUCI = FALSE;
1842 appData.secondIsUCI = FALSE;
1843 appData.firstHasOwnBookUCI = TRUE;
1844 appData.secondHasOwnBookUCI = TRUE;
1845 appData.polyglotDir = "";
1846 appData.usePolyglotBook = FALSE;
1847 appData.polyglotBook = "";
1848 appData.defaultHashSize = 64;
1849 appData.defaultCacheSizeEGTB = 4;
1850 appData.defaultPathEGTB = "c:\\egtb";
1852 InitWindowPlacement( &wpMoveHistory );
1853 InitWindowPlacement( &wpEvalGraph );
1854 InitWindowPlacement( &wpEngineOutput );
1857 appData.zippyTalk = ZIPPY_TALK;
\r
1858 appData.zippyPlay = ZIPPY_PLAY;
\r
1859 appData.zippyLines = ZIPPY_LINES;
\r
1860 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1861 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1862 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1863 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1864 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1865 appData.zippyUseI = ZIPPY_USE_I;
\r
1866 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1867 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1868 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1869 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1870 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1871 appData.zippyAbort = ZIPPY_ABORT;
\r
1872 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1873 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1874 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1877 /* Point font array elements to structures and
\r
1878 parse default font names */
\r
1879 for (i=0; i<NUM_FONTS; i++) {
\r
1880 for (j=0; j<NUM_SIZES; j++) {
\r
1881 font[j][i] = &fontRec[j][i];
\r
1882 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1886 /* Parse default settings file if any */
\r
1887 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1888 settingsFileName = strdup(buf);
\r
1891 /* Parse command line */
\r
1892 ParseArgs(StringGet, &lpCmdLine);
\r
1894 /* Propagate options that affect others */
\r
1895 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1896 if (appData.icsActive || appData.noChessProgram) {
\r
1897 chessProgram = FALSE; /* not local chess program mode */
\r
1900 /* Open startup dialog if needed */
\r
1901 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1902 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1903 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1904 *appData.secondChessProgram == NULLCHAR))) {
\r
1907 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1908 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1909 FreeProcInstance(lpProc);
\r
1912 /* Make sure save files land in the right (?) directory */
\r
1913 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1914 appData.saveGameFile = strdup(buf);
\r
1916 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1917 appData.savePositionFile = strdup(buf);
\r
1920 /* Finish initialization for fonts and sounds */
\r
1921 for (i=0; i<NUM_FONTS; i++) {
\r
1922 for (j=0; j<NUM_SIZES; j++) {
\r
1923 CreateFontInMF(font[j][i]);
\r
1926 /* xboard, and older WinBoards, controlled the move sound with the
\r
1927 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1928 always turn the option on (so that the backend will call us),
\r
1929 then let the user turn the sound off by setting it to silence if
\r
1930 desired. To accommodate old winboard.ini files saved by old
\r
1931 versions of WinBoard, we also turn off the sound if the option
\r
1932 was initially set to false. */
\r
1933 if (!appData.ringBellAfterMoves) {
\r
1934 sounds[(int)SoundMove].name = strdup("");
\r
1935 appData.ringBellAfterMoves = TRUE;
\r
1937 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1938 SetCurrentDirectory(installDir);
\r
1940 SetCurrentDirectory(currDir);
\r
1942 p = icsTextMenuString;
\r
1943 if (p[0] == '@') {
\r
1944 FILE* f = fopen(p + 1, "r");
\r
1946 DisplayFatalError(p + 1, errno, 2);
\r
1949 i = fread(buf, 1, sizeof(buf)-1, f);
\r
1951 buf[i] = NULLCHAR;
\r
1954 ParseIcsTextMenu(strdup(p));
\r
1961 HMENU hmenu = GetMenu(hwndMain);
\r
1963 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1964 MF_BYCOMMAND|((appData.icsActive &&
\r
1965 *appData.icsCommPort != NULLCHAR) ?
\r
1966 MF_ENABLED : MF_GRAYED));
\r
1967 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1968 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1969 MF_CHECKED : MF_UNCHECKED));
\r
1974 SaveSettings(char* name)
\r
1977 ArgDescriptor *ad;
\r
1978 WINDOWPLACEMENT wp;
\r
1979 char dir[MSG_SIZ];
\r
1981 if (!hwndMain) return;
\r
1983 GetCurrentDirectory(MSG_SIZ, dir);
\r
1984 SetCurrentDirectory(installDir);
\r
1985 f = fopen(name, "w");
\r
1986 SetCurrentDirectory(dir);
\r
1988 DisplayError(name, errno);
\r
1991 fprintf(f, ";\n");
\r
1992 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
1993 fprintf(f, ";\n");
\r
1994 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
1995 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
1996 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
1997 fprintf(f, ";\n");
\r
1999 wp.length = sizeof(WINDOWPLACEMENT);
\r
2000 GetWindowPlacement(hwndMain, &wp);
\r
2001 boardX = wp.rcNormalPosition.left;
\r
2002 boardY = wp.rcNormalPosition.top;
\r
2004 if (hwndConsole) {
\r
2005 GetWindowPlacement(hwndConsole, &wp);
\r
2006 consoleX = wp.rcNormalPosition.left;
\r
2007 consoleY = wp.rcNormalPosition.top;
\r
2008 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2009 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2012 if (analysisDialog) {
\r
2013 GetWindowPlacement(analysisDialog, &wp);
\r
2014 analysisX = wp.rcNormalPosition.left;
\r
2015 analysisY = wp.rcNormalPosition.top;
\r
2016 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2017 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2020 if (commentDialog) {
\r
2021 GetWindowPlacement(commentDialog, &wp);
\r
2022 commentX = wp.rcNormalPosition.left;
\r
2023 commentY = wp.rcNormalPosition.top;
\r
2024 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2025 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2028 if (editTagsDialog) {
\r
2029 GetWindowPlacement(editTagsDialog, &wp);
\r
2030 editTagsX = wp.rcNormalPosition.left;
\r
2031 editTagsY = wp.rcNormalPosition.top;
\r
2032 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2033 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2036 if (gameListDialog) {
\r
2037 GetWindowPlacement(gameListDialog, &wp);
\r
2038 gameListX = wp.rcNormalPosition.left;
\r
2039 gameListY = wp.rcNormalPosition.top;
\r
2040 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2041 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2044 /* [AS] Move history */
2045 wpMoveHistory.visible = MoveHistoryIsUp();
2047 if( moveHistoryDialog ) {
2048 GetWindowPlacement(moveHistoryDialog, &wp);
2049 wpMoveHistory.x = wp.rcNormalPosition.left;
2050 wpMoveHistory.y = wp.rcNormalPosition.top;
2051 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
2052 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
2055 /* [AS] Eval graph */
2056 wpEvalGraph.visible = EvalGraphIsUp();
2058 if( evalGraphDialog ) {
2059 GetWindowPlacement(evalGraphDialog, &wp);
2060 wpEvalGraph.x = wp.rcNormalPosition.left;
2061 wpEvalGraph.y = wp.rcNormalPosition.top;
2062 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
2063 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
2066 /* [AS] Engine output */
2067 wpEngineOutput.visible = EngineOutputIsUp();
2069 if( engineOutputDialog ) {
2070 GetWindowPlacement(engineOutputDialog, &wp);
2071 wpEngineOutput.x = wp.rcNormalPosition.left;
2072 wpEngineOutput.y = wp.rcNormalPosition.top;
2073 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
2074 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
2077 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2078 if (!ad->save) continue;
\r
2079 switch (ad->argType) {
\r
2082 char *p = *(char **)ad->argLoc;
\r
2083 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2084 /* Quote multiline values or \-containing values
\r
2085 with { } if possible */
\r
2086 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2088 /* Else quote with " " */
\r
2089 fprintf(f, "/%s=\"", ad->argName);
\r
2091 if (*p == '\n') fprintf(f, "\n");
\r
2092 else if (*p == '\r') fprintf(f, "\\r");
\r
2093 else if (*p == '\t') fprintf(f, "\\t");
\r
2094 else if (*p == '\b') fprintf(f, "\\b");
\r
2095 else if (*p == '\f') fprintf(f, "\\f");
\r
2096 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2097 else if (*p == '\"') fprintf(f, "\\\"");
\r
2098 else if (*p == '\\') fprintf(f, "\\\\");
\r
2102 fprintf(f, "\"\n");
\r
2107 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2110 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2113 fprintf(f, "/%s=%s\n", ad->argName,
\r
2114 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2117 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2120 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2124 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2125 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2126 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2131 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2132 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2133 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2134 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2135 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2136 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2137 (ta->effects) ? " " : "",
\r
2138 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2142 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2143 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2145 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2148 case ArgBoardSize:
\r
2149 fprintf(f, "/%s=%s\n", ad->argName,
\r
2150 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2155 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2156 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2157 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2158 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2159 ad->argName, mfp->faceName, mfp->pointSize,
\r
2160 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2161 mfp->bold ? "b" : "",
\r
2162 mfp->italic ? "i" : "",
\r
2163 mfp->underline ? "u" : "",
\r
2164 mfp->strikeout ? "s" : "");
\r
2168 case ArgCommSettings:
\r
2169 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2177 /*---------------------------------------------------------------------------*\
\r
2179 * GDI board drawing routines
\r
2181 \*---------------------------------------------------------------------------*/
\r
2183 /* [AS] Draw square using background texture */
2184 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
2189 return; /* Should never happen! */
2192 SetGraphicsMode( dst, GM_ADVANCED );
2204 x.eDx = (FLOAT) dw + dx - 1;
2207 SetWorldTransform( dst, &x );
2216 x.eDy = (FLOAT) dh + dy - 1;
2218 SetWorldTransform( dst, &x );
2230 SetWorldTransform( dst, &x );
2234 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
2242 SetWorldTransform( dst, &x );
2244 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
2263 static HFONT hPieceFont = NULL;
2264 static HBITMAP hPieceMask[12];
2265 static HBITMAP hPieceFace[12];
2266 static int fontBitmapSquareSize = 0;
2267 static char pieceToFontChar[12] = { 'p', 'n', 'b', 'r', 'q', 'k', 'o', 'm', 'v', 't', 'w', 'l' };
2269 static BOOL SetPieceToFontCharTable( const char * map )
2271 BOOL result = FALSE;
2273 if( map != NULL && strlen(map) == 12 ) {
2276 for( i=0; i<12; i++ ) {
2277 pieceToFontChar[i] = map[i];
2286 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
2289 BYTE r1 = GetRValue( color );
2290 BYTE g1 = GetGValue( color );
2291 BYTE b1 = GetBValue( color );
2297 /* Create a uniform background first */
2298 hbrush = CreateSolidBrush( color );
2299 SetRect( &rc, 0, 0, squareSize, squareSize );
2300 FillRect( hdc, &rc, hbrush );
2301 DeleteObject( hbrush );
2304 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
2305 int steps = squareSize / 2;
2308 for( i=0; i<steps; i++ ) {
2309 BYTE r = r1 - (r1-r2) * i / steps;
2310 BYTE g = g1 - (g1-g2) * i / steps;
2311 BYTE b = b1 - (b1-b2) * i / steps;
2313 hbrush = CreateSolidBrush( RGB(r,g,b) );
2314 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
2315 FillRect( hdc, &rc, hbrush );
2316 DeleteObject(hbrush);
2319 else if( mode == 2 ) {
2320 /* Diagonal gradient, good more or less for every piece */
2322 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
2324 int steps = squareSize;
2327 triangle[0].x = squareSize - steps;
2328 triangle[0].y = squareSize;
2329 triangle[1].x = squareSize;
2330 triangle[1].y = squareSize;
2331 triangle[2].x = squareSize;
2332 triangle[2].y = squareSize - steps;
2334 for( i=0; i<steps; i++ ) {
2335 BYTE r = r1 - (r1-r2) * i / steps;
2336 BYTE g = g1 - (g1-g2) * i / steps;
2337 BYTE b = b1 - (b1-b2) * i / steps;
2339 hbrush = CreateSolidBrush( RGB(r,g,b) );
2340 hbrush_old = SelectObject( hdc, hbrush );
2341 Polygon( hdc, triangle, 3 );
2342 SelectObject( hdc, hbrush_old );
2343 DeleteObject(hbrush);
2348 SelectObject( hdc, hpen );
2353 [AS] The method I use to create the bitmaps it a bit tricky, but it
2354 seems to work ok. The main problem here is to find the "inside" of a chess
2355 piece: follow the steps as explained below.
2357 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
2361 COLORREF chroma = RGB(0xFF,0x00,0xFF);
2365 int backColor = whitePieceColor;
2366 int foreColor = blackPieceColor;
2367 int shapeIndex = index < 6 ? index+6 : index;
2369 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
2370 backColor = appData.fontBackColorWhite;
2371 foreColor = appData.fontForeColorWhite;
2373 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
2374 backColor = appData.fontBackColorBlack;
2375 foreColor = appData.fontForeColorBlack;
2379 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2381 hbm_old = SelectObject( hdc, hbm );
2385 rc.right = squareSize;
2386 rc.bottom = squareSize;
2388 /* Step 1: background is now black */
2389 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
2391 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
2393 pt.x = (squareSize - sz.cx) / 2;
2394 pt.y = (squareSize - sz.cy) / 2;
2396 SetBkMode( hdc, TRANSPARENT );
2397 SetTextColor( hdc, chroma );
2398 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
2399 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2401 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
2402 /* Step 3: the area outside the piece is filled with white */
2403 FloodFill( hdc, 0, 0, chroma );
2404 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
2406 Step 4: this is the tricky part, the area inside the piece is filled with black,
2407 but if the start point is not inside the piece we're lost!
2408 There should be a better way to do this... if we could create a region or path
2409 from the fill operation we would be fine for example.
2411 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
2413 SetTextColor( hdc, 0 );
2415 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
2416 draw the piece again in black for safety.
2418 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2420 SelectObject( hdc, hbm_old );
2422 if( hPieceMask[index] != NULL ) {
2423 DeleteObject( hPieceMask[index] );
2426 hPieceMask[index] = hbm;
2429 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2431 SelectObject( hdc, hbm );
2434 HDC dc1 = CreateCompatibleDC( hdc_window );
2435 HDC dc2 = CreateCompatibleDC( hdc_window );
2436 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2438 SelectObject( dc1, hPieceMask[index] );
2439 SelectObject( dc2, bm2 );
2440 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
2441 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
2444 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
2445 the piece background and deletes (makes transparent) the rest.
2446 Thanks to that mask, we are free to paint the background with the greates
2447 freedom, as we'll be able to mask off the unwanted parts when finished.
2448 We use this, to make gradients and give the pieces a "roundish" look.
2450 SetPieceBackground( hdc, backColor, 2 );
2451 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
2455 DeleteObject( bm2 );
2458 SetTextColor( hdc, foreColor );
2459 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2461 SelectObject( hdc, hbm_old );
2463 if( hPieceFace[index] != NULL ) {
2464 DeleteObject( hPieceFace[index] );
2467 hPieceFace[index] = hbm;
2470 static int TranslatePieceToFontPiece( int piece )
2502 void CreatePiecesFromFont()
2505 HDC hdc_window = NULL;
2511 if( fontBitmapSquareSize < 0 ) {
2512 /* Something went seriously wrong in the past: do not try to recreate fonts! */
2516 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
2517 fontBitmapSquareSize = -1;
2521 if( fontBitmapSquareSize != squareSize ) {
2522 hdc_window = GetDC( hwndMain );
2523 hdc = CreateCompatibleDC( hdc_window );
2525 if( hPieceFont != NULL ) {
2526 DeleteObject( hPieceFont );
2529 for( i=0; i<12; i++ ) {
2530 hPieceMask[i] = NULL;
2531 hPieceFace[i] = NULL;
2537 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
2538 fontHeight = appData.fontPieceSize;
2541 fontHeight = (fontHeight * squareSize) / 100;
2543 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
2545 lf.lfEscapement = 0;
2546 lf.lfOrientation = 0;
2547 lf.lfWeight = FW_NORMAL;
2551 lf.lfCharSet = DEFAULT_CHARSET;
2552 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
2553 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2554 lf.lfQuality = PROOF_QUALITY;
2555 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
2556 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
2557 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
2559 hPieceFont = CreateFontIndirect( &lf );
2561 if( hPieceFont == NULL ) {
2562 fontBitmapSquareSize = -2;
2565 /* Setup font-to-piece character table */
2566 if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) {
2567 /* No (or wrong) global settings, try to detect the font */
2568 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
2570 SetPieceToFontCharTable("phbrqkojntwl");
2572 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
2573 /* DiagramTT* family */
2574 SetPieceToFontCharTable("PNLRQKpnlrqk");
2577 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
2578 SetPieceToFontCharTable("pnbrqkomvtwl");
2582 /* Create bitmaps */
2583 hfont_old = SelectObject( hdc, hPieceFont );
2585 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
2586 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
2587 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
2588 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
2589 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
2590 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
2591 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
2592 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
2593 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
2594 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
2595 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
2596 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
2598 SelectObject( hdc, hfont_old );
2600 fontBitmapSquareSize = squareSize;
2608 if( hdc_window != NULL ) {
2609 ReleaseDC( hwndMain, hdc_window );
2614 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2618 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2619 if (gameInfo.event &&
\r
2620 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2621 strcmp(name, "k80s") == 0) {
\r
2622 strcpy(name, "tim");
\r
2624 return LoadBitmap(hinst, name);
\r
2628 /* Insert a color into the program's logical palette
\r
2629 structure. This code assumes the given color is
\r
2630 the result of the RGB or PALETTERGB macro, and it
\r
2631 knows how those macros work (which is documented).
\r
2634 InsertInPalette(COLORREF color)
\r
2636 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2638 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2639 DisplayFatalError("Too many colors", 0, 1);
\r
2640 pLogPal->palNumEntries--;
\r
2644 pe->peFlags = (char) 0;
\r
2645 pe->peRed = (char) (0xFF & color);
\r
2646 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2647 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2653 InitDrawingColors()
\r
2655 if (pLogPal == NULL) {
\r
2656 /* Allocate enough memory for a logical palette with
\r
2657 * PALETTESIZE entries and set the size and version fields
\r
2658 * of the logical palette structure.
\r
2660 pLogPal = (NPLOGPALETTE)
\r
2661 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2662 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2663 pLogPal->palVersion = 0x300;
\r
2665 pLogPal->palNumEntries = 0;
\r
2667 InsertInPalette(lightSquareColor);
\r
2668 InsertInPalette(darkSquareColor);
\r
2669 InsertInPalette(whitePieceColor);
\r
2670 InsertInPalette(blackPieceColor);
\r
2671 InsertInPalette(highlightSquareColor);
\r
2672 InsertInPalette(premoveHighlightColor);
\r
2674 /* create a logical color palette according the information
\r
2675 * in the LOGPALETTE structure.
\r
2677 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2679 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2680 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2681 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2682 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2683 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2685 /* [AS] Force rendering of the font-based pieces */
2686 if( fontBitmapSquareSize > 0 ) {
2687 fontBitmapSquareSize = 0;
2693 BoardWidth(int boardSize)
\r
2695 int lineGap = sizeInfo[boardSize].lineGap;
2697 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
2698 lineGap = appData.overrideLineGap;
2701 return (BOARD_SIZE + 1) * lineGap +
2702 BOARD_SIZE * sizeInfo[boardSize].squareSize;
\r
2705 /* Respond to board resize by dragging edge */
\r
2707 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2709 BoardSize newSize = NUM_SIZES - 1;
\r
2710 static int recurse = 0;
\r
2711 if (IsIconic(hwndMain)) return;
\r
2712 if (recurse > 0) return;
\r
2714 while (newSize > 0 &&
\r
2715 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2716 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2719 boardSize = newSize;
\r
2720 InitDrawingSizes(boardSize, flags);
\r
2727 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2729 int i, boardWidth;
\r
2730 ChessSquare piece;
\r
2731 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2733 SIZE clockSize, messageSize;
\r
2735 char buf[MSG_SIZ];
\r
2737 HMENU hmenu = GetMenu(hwndMain);
\r
2738 RECT crect, wrect;
\r
2740 LOGBRUSH logbrush;
\r
2742 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2743 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2744 squareSize = sizeInfo[boardSize].squareSize;
\r
2745 lineGap = sizeInfo[boardSize].lineGap;
\r
2747 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
2748 lineGap = appData.overrideLineGap;
2751 if (tinyLayout != oldTinyLayout) {
\r
2752 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2754 style &= ~WS_SYSMENU;
\r
2755 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2756 "&Minimize\tCtrl+F4");
\r
2758 style |= WS_SYSMENU;
\r
2759 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2761 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2763 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2764 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2765 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2767 DrawMenuBar(hwndMain);
\r
2770 boardWidth = BoardWidth(boardSize);
\r
2772 /* Get text area sizes */
\r
2773 hdc = GetDC(hwndMain);
\r
2774 if (appData.clockMode) {
\r
2775 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2777 sprintf(buf, "White");
\r
2779 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2780 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2781 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2782 str = "We only care about the height here";
\r
2783 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2784 SelectObject(hdc, oldFont);
\r
2785 ReleaseDC(hwndMain, hdc);
\r
2787 /* Compute where everything goes */
\r
2788 whiteRect.left = OUTER_MARGIN;
\r
2789 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2790 whiteRect.top = OUTER_MARGIN;
\r
2791 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2793 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2794 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2795 blackRect.top = whiteRect.top;
\r
2796 blackRect.bottom = whiteRect.bottom;
\r
2798 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2799 if (appData.showButtonBar) {
\r
2800 messageRect.right = blackRect.right
\r
2801 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2803 messageRect.right = blackRect.right;
\r
2805 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2806 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2808 boardRect.left = whiteRect.left;
\r
2809 boardRect.right = boardRect.left + boardWidth;
\r
2810 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2811 boardRect.bottom = boardRect.top + boardWidth;
\r
2813 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2814 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2815 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2816 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2817 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2818 GetWindowRect(hwndMain, &wrect);
\r
2819 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2820 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2821 /* compensate if menu bar wrapped */
\r
2822 GetClientRect(hwndMain, &crect);
\r
2823 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2824 winHeight += offby;
\r
2826 case WMSZ_TOPLEFT:
\r
2827 SetWindowPos(hwndMain, NULL,
\r
2828 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2829 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2832 case WMSZ_TOPRIGHT:
\r
2834 SetWindowPos(hwndMain, NULL,
\r
2835 wrect.left, wrect.bottom - winHeight,
\r
2836 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2839 case WMSZ_BOTTOMLEFT:
\r
2841 SetWindowPos(hwndMain, NULL,
\r
2842 wrect.right - winWidth, wrect.top,
\r
2843 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2846 case WMSZ_BOTTOMRIGHT:
\r
2850 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2851 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2856 for (i = 0; i < N_BUTTONS; i++) {
\r
2857 if (buttonDesc[i].hwnd != NULL) {
\r
2858 DestroyWindow(buttonDesc[i].hwnd);
\r
2859 buttonDesc[i].hwnd = NULL;
\r
2861 if (appData.showButtonBar) {
\r
2862 buttonDesc[i].hwnd =
\r
2863 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2864 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2865 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2866 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2867 (HMENU) buttonDesc[i].id,
\r
2868 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2870 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2871 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2872 MAKELPARAM(FALSE, 0));
\r
2874 if (buttonDesc[i].id == IDM_Pause)
\r
2875 hwndPause = buttonDesc[i].hwnd;
\r
2876 buttonDesc[i].wndproc = (WNDPROC)
\r
2877 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2880 if (gridPen != NULL) DeleteObject(gridPen);
\r
2881 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2882 if (premovePen != NULL) DeleteObject(premovePen);
\r
2883 if (lineGap != 0) {
\r
2884 logbrush.lbStyle = BS_SOLID;
\r
2885 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2887 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2888 lineGap, &logbrush, 0, NULL);
\r
2889 logbrush.lbColor = highlightSquareColor;
\r
2891 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2892 lineGap, &logbrush, 0, NULL);
\r
2894 logbrush.lbColor = premoveHighlightColor;
\r
2896 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2897 lineGap, &logbrush, 0, NULL);
\r
2899 for (i = 0; i < BOARD_SIZE + 1; i++) {
\r
2900 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2901 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2;
\r
2902 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2903 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2904 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2905 BOARD_SIZE * (squareSize + lineGap);
\r
2906 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x =
\r
2907 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left +
\r
2908 lineGap / 2 + (i * (squareSize + lineGap));
\r
2909 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y =
\r
2910 boardRect.top + BOARD_SIZE * (squareSize + lineGap);
\r
2911 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2915 if (boardSize == oldBoardSize) return;
\r
2916 oldBoardSize = boardSize;
\r
2917 oldTinyLayout = tinyLayout;
\r
2919 /* Load piece bitmaps for this board size */
\r
2920 for (i=0; i<=2; i++) {
\r
2921 for (piece = WhitePawn;
\r
2922 (int) piece <= (int) WhiteKing;
\r
2923 piece = (ChessSquare) ((int) piece + 1)) {
\r
2924 if (pieceBitmap[i][piece] != NULL)
\r
2925 DeleteObject(pieceBitmap[i][piece]);
\r
2929 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2930 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2931 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2932 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2933 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2934 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2935 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2936 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2937 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2938 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2939 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2940 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2941 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2942 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2943 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2944 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2945 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2946 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2951 PieceBitmap(ChessSquare p, int kind)
\r
2953 if ((int) p >= (int) BlackPawn)
\r
2954 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2956 return pieceBitmap[kind][(int) p];
\r
2959 /***************************************************************/
\r
2961 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2962 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2964 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2965 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2969 SquareToPos(int row, int column, int * x, int * y)
\r
2972 *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
2973 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2975 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2976 *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
2981 DrawCoordsOnDC(HDC hdc)
\r
2983 static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'};
\r
2984 static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'};
\r
2985 char str[2] = { NULLCHAR, NULLCHAR };
\r
2986 int oldMode, oldAlign, x, y, start, i;
\r
2990 if (!appData.showCoords)
\r
2993 start = flipView ? 0 : 8;
\r
2995 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2996 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2997 oldAlign = GetTextAlign(hdc);
\r
2998 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3000 y = boardRect.top + lineGap;
\r
3001 x = boardRect.left + lineGap;
\r
3003 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3004 for (i = 0; i < 8; i++) {
\r
3005 str[0] = files[start + i];
\r
3006 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3007 y += squareSize + lineGap;
\r
3010 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3011 for (i = 0; i < 8; i++) {
\r
3012 str[0] = ranks[start + i];
\r
3013 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3014 x += squareSize + lineGap;
\r
3017 SelectObject(hdc, oldBrush);
\r
3018 SetBkMode(hdc, oldMode);
\r
3019 SetTextAlign(hdc, oldAlign);
\r
3020 SelectObject(hdc, oldFont);
\r
3024 DrawGridOnDC(HDC hdc)
\r
3028 if (lineGap != 0) {
\r
3029 oldPen = SelectObject(hdc, gridPen);
\r
3030 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2);
\r
3031 SelectObject(hdc, oldPen);
\r
3035 #define HIGHLIGHT_PEN 0
\r
3036 #define PREMOVE_PEN 1
\r
3039 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3042 HPEN oldPen, hPen;
\r
3043 if (lineGap == 0) return;
\r
3045 x1 = boardRect.left +
\r
3046 lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap);
\r
3047 y1 = boardRect.top +
\r
3048 lineGap/2 + y * (squareSize + lineGap);
\r
3050 x1 = boardRect.left +
\r
3051 lineGap/2 + x * (squareSize + lineGap);
\r
3052 y1 = boardRect.top +
\r
3053 lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap);
\r
3055 hPen = pen ? premovePen : highlightPen;
\r
3056 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3057 MoveToEx(hdc, x1, y1, NULL);
\r
3058 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3059 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3060 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3061 LineTo(hdc, x1, y1);
\r
3062 SelectObject(hdc, oldPen);
\r
3066 DrawHighlightsOnDC(HDC hdc)
\r
3069 for (i=0; i<2; i++) {
\r
3070 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3071 DrawHighlightOnDC(hdc, TRUE,
\r
3072 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3075 for (i=0; i<2; i++) {
\r
3076 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3077 premoveHighlightInfo.sq[i].y >= 0) {
\r
3078 DrawHighlightOnDC(hdc, TRUE,
\r
3079 premoveHighlightInfo.sq[i].x,
\r
3080 premoveHighlightInfo.sq[i].y,
\r
3086 /* Note: sqcolor is used only in monoMode */
\r
3087 /* Note that this code is largely duplicated in woptions.c,
\r
3088 function DrawSampleSquare, so that needs to be updated too */
\r
3090 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3092 HBITMAP oldBitmap;
\r
3095 if (appData.blindfold) return;
\r
3097 /* [AS] Use font-based pieces if needed */
3098 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
3099 /* Create piece bitmaps, or do nothing if piece set is up to date */
3100 CreatePiecesFromFont();
3102 if( fontBitmapSquareSize == squareSize ) {
3103 int index = TranslatePieceToFontPiece( piece );
3105 SelectObject( tmphdc, hPieceMask[ index ] );
3109 squareSize, squareSize,
3114 SelectObject( tmphdc, hPieceFace[ index ] );
3118 squareSize, squareSize,
3127 if (appData.monoMode) {
\r
3128 SelectObject(tmphdc, PieceBitmap(piece,
\r
3129 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3130 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3131 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3134 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3135 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3136 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3138 /* Use black piece color for outline of white pieces */
\r
3139 /* Not sure this looks really good (though xboard does it).
\r
3140 Maybe better to have another selectable color, default black */
\r
3141 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3142 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3143 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3145 /* Use black for outline of white pieces */
\r
3146 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3147 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
3151 /* Use white piece color for details of black pieces */
\r
3152 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3153 WHITE_PIECE ones aren't always the right shape. */
\r
3154 /* Not sure this looks really good (though xboard does it).
\r
3155 Maybe better to have another selectable color, default medium gray? */
\r
3156 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3157 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3158 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3159 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3160 SelectObject(hdc, blackPieceBrush);
\r
3161 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3163 /* Use square color for details of black pieces */
\r
3164 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3165 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3166 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3169 SelectObject(hdc, oldBrush);
\r
3170 SelectObject(tmphdc, oldBitmap);
\r
3174 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
3175 int GetBackTextureMode( int algo )
3177 int result = BACK_TEXTURE_MODE_DISABLED;
3181 case BACK_TEXTURE_MODE_PLAIN:
3182 result = 1; /* Always use identity map */
3184 case BACK_TEXTURE_MODE_FULL_RANDOM:
3185 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
3193 [AS] Compute and save texture drawing info, otherwise we may not be able
3194 to handle redraws cleanly (as random numbers would always be different).
3196 VOID RebuildTextureSquareInfo()
3206 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
3208 if( liteBackTexture != NULL ) {
3209 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
3210 lite_w = bi.bmWidth;
3211 lite_h = bi.bmHeight;
3215 if( darkBackTexture != NULL ) {
3216 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
3217 dark_w = bi.bmWidth;
3218 dark_h = bi.bmHeight;
3222 for( row=0; row<BOARD_SIZE; row++ ) {
3223 for( col=0; col<BOARD_SIZE; col++ ) {
3224 if( (col + row) & 1 ) {
3226 if( lite_w >= squareSize && lite_h >= squareSize ) {
3227 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_SIZE;
3228 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_SIZE;
3229 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
3234 if( dark_w >= squareSize && dark_h >= squareSize ) {
3235 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_SIZE;
3236 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_SIZE;
3237 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
3244 /* [AS] Arrow highlighting support */
3246 static int A_WIDTH = 5; /* Width of arrow body */
3248 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
3249 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
3251 static double Sqr( double x )
3256 static int Round( double x )
3258 return (int) (x + 0.5);
3261 /* Draw an arrow between two points using current settings */
3262 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
3265 double dx, dy, j, k, x, y;
3268 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
3270 arrow[0].x = s_x + A_WIDTH;
3273 arrow[1].x = s_x + A_WIDTH;
3274 arrow[1].y = d_y - h;
3276 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
3277 arrow[2].y = d_y - h;
3282 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
3283 arrow[4].y = d_y - h;
3285 arrow[5].x = s_x - A_WIDTH;
3286 arrow[5].y = d_y - h;
3288 arrow[6].x = s_x - A_WIDTH;
3291 else if( d_y == s_y ) {
3292 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
3295 arrow[0].y = s_y + A_WIDTH;
3297 arrow[1].x = d_x - w;
3298 arrow[1].y = s_y + A_WIDTH;
3300 arrow[2].x = d_x - w;
3301 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
3306 arrow[4].x = d_x - w;
3307 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
3309 arrow[5].x = d_x - w;
3310 arrow[5].y = s_y - A_WIDTH;
3313 arrow[6].y = s_y - A_WIDTH;
3316 /* [AS] Needed a lot of paper for this! :-) */
3317 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
3318 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
3320 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
3322 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
3327 arrow[0].x = Round(x - j);
3328 arrow[0].y = Round(y + j*dx);
3330 arrow[1].x = Round(x + j);
3331 arrow[1].y = Round(y - j*dx);
3334 x = (double) d_x - k;
3335 y = (double) d_y - k*dy;
3338 x = (double) d_x + k;
3339 y = (double) d_y + k*dy;
3342 arrow[2].x = Round(x + j);
3343 arrow[2].y = Round(y - j*dx);
3345 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
3346 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
3351 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
3352 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
3354 arrow[6].x = Round(x - j);
3355 arrow[6].y = Round(y + j*dx);
3358 Polygon( hdc, arrow, 7 );
3361 /* [AS] Draw an arrow between two squares */
3362 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
3364 int s_x, s_y, d_x, d_y;
3371 if( s_col == d_col && s_row == d_row ) {
3375 /* Get source and destination points */
3376 SquareToPos( s_row, s_col, &s_x, &s_y);
3377 SquareToPos( d_row, d_col, &d_x, &d_y);
3380 d_y += squareSize / 4;
3382 else if( d_y < s_y ) {
3383 d_y += 3 * squareSize / 4;
3386 d_y += squareSize / 2;
3390 d_x += squareSize / 4;
3392 else if( d_x < s_x ) {
3393 d_x += 3 * squareSize / 4;
3396 d_x += squareSize / 2;
3399 s_x += squareSize / 2;
3400 s_y += squareSize / 2;
3403 A_WIDTH = squareSize / 14;
3406 stLB.lbStyle = BS_SOLID;
3407 stLB.lbColor = appData.highlightArrowColor;
3410 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
3411 holdpen = SelectObject( hdc, hpen );
3412 hbrush = CreateBrushIndirect( &stLB );
3413 holdbrush = SelectObject( hdc, hbrush );
3415 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
3417 SelectObject( hdc, holdpen );
3418 SelectObject( hdc, holdbrush );
3419 DeleteObject( hpen );
3420 DeleteObject( hbrush );
3423 BOOL HasHighlightInfo()
3425 BOOL result = FALSE;
3427 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
3428 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
3436 BOOL IsDrawArrowEnabled()
3438 BOOL result = FALSE;
3440 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
3447 VOID DrawArrowHighlight( HDC hdc )
3449 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
3450 DrawArrowBetweenSquares( hdc,
3451 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
3452 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
3456 HRGN GetArrowHighlightClipRegion( HDC hdc )
3460 if( HasHighlightInfo() ) {
3464 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
3465 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
3469 dx = MAX( x1, x2 ) + squareSize;
3470 dy = MAX( y1, y2 ) + squareSize;
3472 result = CreateRectRgn( sx, sy, dx, dy );
3479 Warning: this function modifies the behavior of several other functions.
3481 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
3482 needed. Unfortunately, the decision whether or not to perform a full or partial
3483 repaint is scattered all over the place, which is not good for features such as
3484 "arrow highlighting" that require a full repaint of the board.
3486 So, I've tried to patch the code where I thought it made sense (e.g. after or during
3487 user interaction, when speed is not so important) but especially to avoid errors
3488 in the displayed graphics.
3490 In such patched places, I always try refer to this function so there is a single
3491 place to maintain knowledge.
3493 To restore the original behavior, just return FALSE unconditionally.
3495 BOOL IsFullRepaintPreferrable()
3497 BOOL result = FALSE;
3499 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
3500 /* Arrow may appear on the board */
3508 This function is called by DrawPosition to know whether a full repaint must
3511 Only DrawPosition may directly call this function, which makes use of
3512 some state information. Other function should call DrawPosition specifying
3513 the repaint flag, and can use IsFullRepaintPreferrable if needed.
3515 BOOL DrawPositionNeedsFullRepaint()
3517 BOOL result = FALSE;
3520 Probably a slightly better policy would be to trigger a full repaint
3521 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
3522 but animation is fast enough that it's difficult to notice.
3524 if( animInfo.piece == EmptySquare ) {
3525 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
3534 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3536 int row, column, x, y, square_color, piece_color;
\r
3537 ChessSquare piece;
\r
3539 HDC texture_hdc = NULL;
3541 /* [AS] Initialize background textures if needed */
3542 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
3543 if( backTextureSquareSize != squareSize ) {
3544 backTextureSquareSize = squareSize;
3545 RebuildTextureSquareInfo();
3548 texture_hdc = CreateCompatibleDC( hdc );
3551 for (row = 0; row < BOARD_SIZE; row++) {
\r
3552 for (column = 0; column < BOARD_SIZE; column++) {
\r
3554 SquareToPos(row, column, &x, &y);
\r
3556 piece = board[row][column];
\r
3558 square_color = ((column + row) % 2) == 1;
\r
3559 piece_color = (int) piece < (int) BlackPawn;
\r
3561 if (appData.monoMode) {
\r
3562 if (piece == EmptySquare) {
\r
3563 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3564 square_color ? WHITENESS : BLACKNESS);
\r
3566 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3569 else if( backTextureSquareInfo[row][column].mode > 0 ) {
3570 /* [AS] Draw the square using a texture bitmap */
3571 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
3574 squareSize, squareSize,
3577 backTextureSquareInfo[row][column].mode,
3578 backTextureSquareInfo[row][column].x,
3579 backTextureSquareInfo[row][column].y );
3581 SelectObject( texture_hdc, hbm );
3583 if (piece != EmptySquare) {
3584 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
3588 oldBrush = SelectObject(hdc, square_color ?
\r
3589 lightSquareBrush : darkSquareBrush);
\r
3590 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3591 SelectObject(hdc, oldBrush);
\r
3592 if (piece != EmptySquare)
\r
3593 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3598 if( texture_hdc != NULL ) {
3599 DeleteDC( texture_hdc );
3603 #define MAX_CLIPS 200 /* more than enough */
\r
3606 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3608 static Board lastReq, lastDrawn;
\r
3609 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3610 static int lastDrawnFlipView = 0;
\r
3611 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3612 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3615 HBITMAP bufferBitmap;
\r
3616 HBITMAP oldBitmap;
\r
3618 HRGN clips[MAX_CLIPS];
\r
3619 ChessSquare dragged_piece = EmptySquare;
\r
3621 /* I'm undecided on this - this function figures out whether a full
\r
3622 * repaint is necessary on its own, so there's no real reason to have the
\r
3623 * caller tell it that. I think this can safely be set to FALSE - but
\r
3624 * if we trust the callers not to request full repaints unnessesarily, then
\r
3625 * we could skip some clipping work. In other words, only request a full
\r
3626 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3627 * gamestart and similar) --Hawk
\r
3629 Boolean fullrepaint = repaint;
\r
3631 if( DrawPositionNeedsFullRepaint() ) {
3637 static int repaint_count = 0;
3641 sprintf( buf, "FULL repaint: %d\n", repaint_count );
3642 OutputDebugString( buf );
3646 if (board == NULL) {
\r
3647 if (!lastReqValid) {
\r
3652 CopyBoard(lastReq, board);
\r
3656 if (doingSizing) {
\r
3660 if (IsIconic(hwndMain)) {
\r
3664 if (hdc == NULL) {
\r
3665 hdc = GetDC(hwndMain);
\r
3666 if (!appData.monoMode) {
\r
3667 SelectPalette(hdc, hPal, FALSE);
\r
3668 RealizePalette(hdc);
\r
3672 releaseDC = FALSE;
\r
3676 fprintf(debugFP, "*******************************\n"
\r
3678 "dragInfo.from (%d,%d)\n"
\r
3679 "dragInfo.start (%d,%d)\n"
\r
3680 "dragInfo.pos (%d,%d)\n"
\r
3681 "dragInfo.lastpos (%d,%d)\n",
\r
3682 repaint ? "TRUE" : "FALSE",
\r
3683 dragInfo.from.x, dragInfo.from.y,
\r
3684 dragInfo.start.x, dragInfo.start.y,
\r
3685 dragInfo.pos.x, dragInfo.pos.y,
\r
3686 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
3687 fprintf(debugFP, "prev: ");
\r
3688 for (row = 0; row < 8; row++) {
\r
3689 for (column = 0; column < 8; column++) {
\r
3690 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
3693 fprintf(debugFP, "\n");
\r
3694 fprintf(debugFP, "board: ");
\r
3695 for (row = 0; row < 8; row++) {
\r
3696 for (column = 0; column < 8; column++) {
\r
3697 fprintf(debugFP, "%d ", board[row][column]);
\r
3700 fprintf(debugFP, "\n");
\r
3704 /* Create some work-DCs */
\r
3705 hdcmem = CreateCompatibleDC(hdc);
\r
3706 tmphdc = CreateCompatibleDC(hdc);
\r
3708 /* Figure out which squares need updating by comparing the
\r
3709 * newest board with the last drawn board and checking if
\r
3710 * flipping has changed.
\r
3712 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3713 for (row = 0; row < 8; row++) {
\r
3714 for (column = 0; column < 8; column++) {
\r
3715 if (lastDrawn[row][column] != board[row][column]) {
\r
3716 SquareToPos(row, column, &x, &y);
\r
3717 clips[num_clips++] =
\r
3718 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3722 for (i=0; i<2; i++) {
\r
3723 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3724 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3725 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3726 lastDrawnHighlight.sq[i].y >= 0) {
\r
3727 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3728 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3729 clips[num_clips++] =
\r
3730 CreateRectRgn(x - lineGap, y - lineGap,
\r
3731 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3733 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3734 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3735 clips[num_clips++] =
\r
3736 CreateRectRgn(x - lineGap, y - lineGap,
\r
3737 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3741 for (i=0; i<2; i++) {
\r
3742 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3743 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3744 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3745 lastDrawnPremove.sq[i].y >= 0) {
\r
3746 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3747 lastDrawnPremove.sq[i].x, &x, &y);
\r
3748 clips[num_clips++] =
\r
3749 CreateRectRgn(x - lineGap, y - lineGap,
\r
3750 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3752 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3753 premoveHighlightInfo.sq[i].y >= 0) {
\r
3754 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3755 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3756 clips[num_clips++] =
\r
3757 CreateRectRgn(x - lineGap, y - lineGap,
\r
3758 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3763 fullrepaint = TRUE;
\r
3766 /* Create a buffer bitmap - this is the actual bitmap
\r
3767 * being written to. When all the work is done, we can
\r
3768 * copy it to the real DC (the screen). This avoids
\r
3769 * the problems with flickering.
\r
3771 GetClientRect(hwndMain, &Rect);
\r
3772 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3773 Rect.bottom-Rect.top+1);
\r
3774 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3775 if (!appData.monoMode) {
\r
3776 SelectPalette(hdcmem, hPal, FALSE);
\r
3779 /* Create clips for dragging */
\r
3780 if (!fullrepaint) {
\r
3781 if (dragInfo.from.x >= 0) {
\r
3782 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3783 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3785 if (dragInfo.start.x >= 0) {
\r
3786 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3787 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3789 if (dragInfo.pos.x >= 0) {
\r
3790 x = dragInfo.pos.x - squareSize / 2;
\r
3791 y = dragInfo.pos.y - squareSize / 2;
\r
3792 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3794 if (dragInfo.lastpos.x >= 0) {
\r
3795 x = dragInfo.lastpos.x - squareSize / 2;
\r
3796 y = dragInfo.lastpos.y - squareSize / 2;
\r
3797 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3801 /* If dragging is in progress, we temporarely remove the piece */
\r
3802 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3803 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3804 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3807 /* Are we animating a move?
\r
3809 * - remove the piece from the board (temporarely)
\r
3810 * - calculate the clipping region
\r
3812 if (!fullrepaint) {
\r
3813 if (animInfo.piece != EmptySquare) {
\r
3814 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3815 x = boardRect.left + animInfo.lastpos.x;
\r
3816 y = boardRect.top + animInfo.lastpos.y;
\r
3817 x2 = boardRect.left + animInfo.pos.x;
\r
3818 y2 = boardRect.top + animInfo.pos.y;
\r
3819 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3820 /* Slight kludge. The real problem is that after AnimateMove is
\r
3821 done, the position on the screen does not match lastDrawn.
\r
3822 This currently causes trouble only on e.p. captures in
\r
3823 atomic, where the piece moves to an empty square and then
\r
3824 explodes. The old and new positions both had an empty square
\r
3825 at the destination, but animation has drawn a piece there and
\r
3826 we have to remember to erase it. */
\r
3827 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3831 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3832 if (num_clips == 0)
\r
3833 fullrepaint = TRUE;
\r
3835 /* Set clipping on the memory DC */
\r
3836 if (!fullrepaint) {
\r
3837 SelectClipRgn(hdcmem, clips[0]);
\r
3838 for (x = 1; x < num_clips; x++) {
\r
3839 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3840 abort(); // this should never ever happen!
\r
3844 /* Do all the drawing to the memory DC */
\r
3845 DrawGridOnDC(hdcmem);
\r
3846 DrawHighlightsOnDC(hdcmem);
\r
3847 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3849 if( appData.highlightMoveWithArrow ) {
3850 DrawArrowHighlight(hdcmem);
3853 DrawCoordsOnDC(hdcmem);
\r
3855 /* Put the dragged piece back into place and draw it */
\r
3856 if (dragged_piece != EmptySquare) {
\r
3857 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3858 x = dragInfo.pos.x - squareSize / 2;
\r
3859 y = dragInfo.pos.y - squareSize / 2;
\r
3860 DrawPieceOnDC(hdcmem, dragged_piece,
\r
3861 ((int) dragged_piece < (int) BlackPawn),
\r
3862 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3865 /* Put the animated piece back into place and draw it */
\r
3866 if (animInfo.piece != EmptySquare) {
\r
3867 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3868 x = boardRect.left + animInfo.pos.x;
\r
3869 y = boardRect.top + animInfo.pos.y;
\r
3870 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3871 ((int) animInfo.piece < (int) BlackPawn),
\r
3872 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3875 /* Release the bufferBitmap by selecting in the old bitmap
\r
3876 * and delete the memory DC
\r
3878 SelectObject(hdcmem, oldBitmap);
\r
3881 /* Set clipping on the target DC */
\r
3882 if (!fullrepaint) {
\r
3883 SelectClipRgn(hdc, clips[0]);
\r
3884 for (x = 1; x < num_clips; x++) {
\r
3885 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3886 abort(); // this should never ever happen!
\r
3890 /* Copy the new bitmap onto the screen in one go.
\r
3891 * This way we avoid any flickering
\r
3893 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3894 BitBlt(hdc, boardRect.left, boardRect.top,
\r
3895 boardRect.right - boardRect.left,
\r
3896 boardRect.bottom - boardRect.top,
\r
3897 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3898 SelectObject(tmphdc, oldBitmap);
\r
3900 /* Massive cleanup */
\r
3901 for (x = 0; x < num_clips; x++)
\r
3902 DeleteObject(clips[x]);
\r
3905 DeleteObject(bufferBitmap);
\r
3908 ReleaseDC(hwndMain, hdc);
\r
3910 if (lastDrawnFlipView != flipView) {
\r
3912 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
3914 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
3917 CopyBoard(lastDrawn, board);
\r
3918 lastDrawnHighlight = highlightInfo;
\r
3919 lastDrawnPremove = premoveHighlightInfo;
\r
3920 lastDrawnFlipView = flipView;
\r
3921 lastDrawnValid = 1;
\r
3925 /*---------------------------------------------------------------------------*\
\r
3926 | CLIENT PAINT PROCEDURE
\r
3927 | This is the main event-handler for the WM_PAINT message.
\r
3929 \*---------------------------------------------------------------------------*/
\r
3931 PaintProc(HWND hwnd)
\r
3937 if(hdc = BeginPaint(hwnd, &ps)) {
\r
3938 if (IsIconic(hwnd)) {
\r
3939 DrawIcon(hdc, 2, 2, iconCurrent);
\r
3941 if (!appData.monoMode) {
\r
3942 SelectPalette(hdc, hPal, FALSE);
\r
3943 RealizePalette(hdc);
\r
3945 HDCDrawPosition(hdc, 1, NULL);
\r
3947 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3948 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
3949 ETO_CLIPPED|ETO_OPAQUE,
\r
3950 &messageRect, messageText, strlen(messageText), NULL);
\r
3951 SelectObject(hdc, oldFont);
\r
3952 DisplayBothClocks();
\r
3954 EndPaint(hwnd,&ps);
\r
3962 * If the user selects on a border boundary, return -1; if off the board,
\r
3963 * return -2. Otherwise map the event coordinate to the square.
\r
3964 * The offset boardRect.left or boardRect.top must already have been
\r
3965 * subtracted from x.
\r
3968 EventToSquare(int x)
\r
3975 if ((x % (squareSize + lineGap)) >= squareSize)
\r
3977 x /= (squareSize + lineGap);
\r
3978 if (x >= BOARD_SIZE)
\r
3989 DropEnable dropEnables[] = {
\r
3990 { 'P', DP_Pawn, "Pawn" },
\r
3991 { 'N', DP_Knight, "Knight" },
\r
3992 { 'B', DP_Bishop, "Bishop" },
\r
3993 { 'R', DP_Rook, "Rook" },
\r
3994 { 'Q', DP_Queen, "Queen" },
\r
3998 SetupDropMenu(HMENU hmenu)
\r
4000 int i, count, enable;
\r
4002 extern char white_holding[], black_holding[];
\r
4003 char item[MSG_SIZ];
\r
4005 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4006 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4007 dropEnables[i].piece);
\r
4009 while (p && *p++ == dropEnables[i].piece) count++;
\r
4010 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4011 enable = count > 0 || !appData.testLegality
\r
4012 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4013 && !appData.icsActive);
\r
4014 ModifyMenu(hmenu, dropEnables[i].command,
\r
4015 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4016 dropEnables[i].command, item);
\r
4020 static int fromX = -1, fromY = -1, toX, toY;
\r
4022 /* Event handler for mouse messages */
\r
4024 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4028 static int recursive = 0;
\r
4030 BOOLEAN needsRedraw = FALSE;
4031 BOOLEAN saveAnimate;
\r
4032 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
4033 static BOOLEAN sameAgain = FALSE;
\r
4036 if (message == WM_MBUTTONUP) {
\r
4037 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4038 to the middle button: we simulate pressing the left button too!
\r
4040 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4041 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4047 pt.x = LOWORD(lParam);
\r
4048 pt.y = HIWORD(lParam);
\r
4049 x = EventToSquare(pt.x - boardRect.left);
\r
4050 y = EventToSquare(pt.y - boardRect.top);
\r
4051 if (!flipView && y >= 0) {
\r
4052 y = BOARD_SIZE - 1 - y;
\r
4054 if (flipView && x >= 0) {
\r
4055 x = BOARD_SIZE - 1 - x;
\r
4058 switch (message) {
\r
4059 case WM_LBUTTONDOWN:
\r
4061 sameAgain = FALSE;
\r
4063 /* Downclick vertically off board; check if on clock */
\r
4064 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4065 if (gameMode == EditPosition) {
\r
4066 SetWhiteToPlayEvent();
\r
4067 } else if (gameMode == IcsPlayingBlack ||
\r
4068 gameMode == MachinePlaysWhite) {
\r
4071 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4072 if (gameMode == EditPosition) {
\r
4073 SetBlackToPlayEvent();
\r
4074 } else if (gameMode == IcsPlayingWhite ||
\r
4075 gameMode == MachinePlaysBlack) {
\r
4079 if (!appData.highlightLastMove) {
\r
4080 ClearHighlights();
\r
4081 DrawPosition(forceFullRepaint || FALSE, NULL);
4083 fromX = fromY = -1;
\r
4084 dragInfo.start.x = dragInfo.start.y = -1;
\r
4085 dragInfo.from = dragInfo.start;
\r
4087 } else if (x < 0 || y < 0) {
\r
4089 } else if (fromX == x && fromY == y) {
\r
4090 /* Downclick on same square again */
\r
4091 ClearHighlights();
\r
4092 DrawPosition(forceFullRepaint || FALSE, NULL);
4093 sameAgain = TRUE;
\r
4094 } else if (fromX != -1) {
\r
4095 /* Downclick on different square */
\r
4096 ChessSquare pdown, pup;
\r
4097 pdown = boards[currentMove][fromY][fromX];
\r
4098 pup = boards[currentMove][y][x];
\r
4099 if (gameMode == EditPosition ||
\r
4100 !((WhitePawn <= pdown && pdown <= WhiteKing &&
\r
4101 WhitePawn <= pup && pup <= WhiteKing) ||
\r
4102 (BlackPawn <= pdown && pdown <= BlackKing &&
\r
4103 BlackPawn <= pup && pup <= BlackKing))) {
\r
4104 /* EditPosition, empty square, or different color piece;
\r
4105 click-click move is possible */
\r
4108 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
4109 if (appData.alwaysPromoteToQueen) {
\r
4110 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
4111 if (!appData.highlightLastMove) {
\r
4112 ClearHighlights();
\r
4113 DrawPosition(forceFullRepaint || FALSE, NULL);
4116 SetHighlights(fromX, fromY, toX, toY);
\r
4117 DrawPosition(forceFullRepaint || FALSE, NULL);
4118 PromotionPopup(hwnd);
\r
4120 } else { /* not a promotion */
\r
4121 if (appData.animate || appData.highlightLastMove) {
\r
4122 SetHighlights(fromX, fromY, toX, toY);
\r
4124 ClearHighlights();
\r
4126 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
4127 if (appData.animate && !appData.highlightLastMove) {
\r
4128 ClearHighlights();
\r
4129 DrawPosition(forceFullRepaint || FALSE, NULL);
4132 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4133 fromX = fromY = -1;
\r
4136 ClearHighlights();
\r
4137 DrawPosition(forceFullRepaint || FALSE, NULL);
4139 /* First downclick, or restart on a square with same color piece */
\r
4140 if (!frozen && OKToStartUserMove(x, y)) {
\r
4143 dragInfo.lastpos = pt;
\r
4144 dragInfo.from.x = fromX;
\r
4145 dragInfo.from.y = fromY;
\r
4146 dragInfo.start = dragInfo.from;
\r
4147 SetCapture(hwndMain);
\r
4149 fromX = fromY = -1;
\r
4150 dragInfo.start.x = dragInfo.start.y = -1;
\r
4151 dragInfo.from = dragInfo.start;
\r
4152 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
4156 case WM_LBUTTONUP:
\r
4158 if (fromX == -1) break;
\r
4159 if (x == fromX && y == fromY) {
\r
4160 dragInfo.from.x = dragInfo.from.y = -1;
\r
4161 /* Upclick on same square */
\r
4163 /* Clicked same square twice: abort click-click move */
\r
4164 fromX = fromY = -1;
\r
4166 ClearPremoveHighlights();
\r
4168 /* First square clicked: start click-click move */
\r
4169 SetHighlights(fromX, fromY, -1, -1);
\r
4171 DrawPosition(forceFullRepaint || FALSE, NULL);
4172 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4173 /* Errant click; ignore */
\r
4176 /* Finish drag move */
\r
4177 dragInfo.from.x = dragInfo.from.y = -1;
\r
4180 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4181 appData.animate = appData.animate && !appData.animateDragging;
\r
4182 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
4183 if (appData.alwaysPromoteToQueen) {
\r
4184 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
4186 DrawPosition(forceFullRepaint || FALSE, NULL);
4187 PromotionPopup(hwnd);
\r
4190 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
4192 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4193 appData.animate = saveAnimate;
\r
4194 fromX = fromY = -1;
\r
4195 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
4196 ClearHighlights();
\r
4198 if (appData.animate || appData.animateDragging ||
\r
4199 appData.highlightDragging || gotPremove) {
\r
4200 DrawPosition(forceFullRepaint || FALSE, NULL);
4203 dragInfo.start.x = dragInfo.start.y = -1;
\r
4204 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4207 case WM_MOUSEMOVE:
\r
4208 if ((appData.animateDragging || appData.highlightDragging)
\r
4209 && (wParam & MK_LBUTTON)
\r
4210 && dragInfo.from.x >= 0)
4212 BOOL full_repaint = FALSE;
4214 if (appData.animateDragging) {
\r
4215 dragInfo.pos = pt;
\r
4217 if (appData.highlightDragging) {
\r
4218 SetHighlights(fromX, fromY, x, y);
\r
4219 if( IsDrawArrowEnabled() && (x < 0 || x > 7 || y < 0 || y > y) ) {
4220 full_repaint = TRUE;
4224 DrawPosition( full_repaint, NULL);
4226 dragInfo.lastpos = dragInfo.pos;
\r
4230 case WM_MBUTTONDOWN:
\r
4231 case WM_RBUTTONDOWN:
\r
4234 fromX = fromY = -1;
\r
4235 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4236 dragInfo.start.x = dragInfo.start.y = -1;
\r
4237 dragInfo.from = dragInfo.start;
\r
4238 dragInfo.lastpos = dragInfo.pos;
\r
4239 if (appData.highlightDragging) {
\r
4240 ClearHighlights();
\r
4242 DrawPosition(TRUE, NULL);
\r
4244 switch (gameMode) {
\r
4245 case EditPosition:
\r
4246 case IcsExamining:
\r
4247 if (x < 0 || y < 0) break;
\r
4250 if (message == WM_MBUTTONDOWN) {
\r
4251 buttonCount = 3; /* even if system didn't think so */
\r
4252 if (wParam & MK_SHIFT)
\r
4253 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4255 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4256 } else { /* message == WM_RBUTTONDOWN */
\r
4258 if (buttonCount == 3) {
\r
4259 if (wParam & MK_SHIFT)
\r
4260 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4262 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4264 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4267 /* Just have one menu, on the right button. Windows users don't
\r
4268 think to try the middle one, and sometimes other software steals
\r
4269 it, or it doesn't really exist. */
\r
4270 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4274 case IcsPlayingWhite:
\r
4275 case IcsPlayingBlack:
\r
4277 case MachinePlaysWhite:
\r
4278 case MachinePlaysBlack:
\r
4279 if (appData.testLegality &&
\r
4280 gameInfo.variant != VariantBughouse &&
\r
4281 gameInfo.variant != VariantCrazyhouse) break;
\r
4282 if (x < 0 || y < 0) break;
\r
4285 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4286 SetupDropMenu(hmenu);
\r
4287 MenuPopup(hwnd, pt, hmenu, -1);
\r
4298 /* Preprocess messages for buttons in main window */
\r
4300 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4302 int id = GetWindowLong(hwnd, GWL_ID);
\r
4305 for (i=0; i<N_BUTTONS; i++) {
\r
4306 if (buttonDesc[i].id == id) break;
\r
4308 if (i == N_BUTTONS) return 0;
\r
4309 switch (message) {
\r
4314 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4315 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4322 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4325 if (appData.icsActive) {
\r
4326 if (GetKeyState(VK_SHIFT) < 0) {
\r
4328 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4329 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4333 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4334 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4341 if (appData.icsActive) {
\r
4342 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4343 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4345 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4347 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4348 PopUpMoveDialog((char)wParam);
\r
4354 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4357 /* Process messages for Promotion dialog box */
\r
4359 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4363 switch (message) {
\r
4364 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4365 /* Center the dialog over the application window */
\r
4366 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4367 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4368 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4369 gameInfo.variant == VariantGiveaway) ?
\r
4370 SW_SHOW : SW_HIDE);
\r
4373 case WM_COMMAND: /* message: received a command */
\r
4374 switch (LOWORD(wParam)) {
\r
4376 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4377 ClearHighlights();
\r
4378 DrawPosition(FALSE, NULL);
\r
4398 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4399 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4400 if (!appData.highlightLastMove) {
\r
4401 ClearHighlights();
\r
4402 DrawPosition(FALSE, NULL);
\r
4409 /* Pop up promotion dialog */
\r
4411 PromotionPopup(HWND hwnd)
\r
4415 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4416 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4417 hwnd, (DLGPROC)lpProc);
\r
4418 FreeProcInstance(lpProc);
\r
4421 /* Toggle ShowThinking */
\r
4423 ToggleShowThinking()
\r
4425 ShowThinkingEvent(!appData.showThinking);
\r
4429 LoadGameDialog(HWND hwnd, char* title)
\r
4433 char fileTitle[MSG_SIZ];
\r
4434 f = OpenFileDialog(hwnd, FALSE, "",
\r
4435 appData.oldSaveStyle ? "gam" : "pgn",
\r
4437 title, &number, fileTitle, NULL);
\r
4439 cmailMsgLoaded = FALSE;
\r
4440 if (number == 0) {
\r
4441 int error = GameListBuild(f);
\r
4443 DisplayError("Cannot build game list", error);
\r
4444 } else if (!ListEmpty(&gameList) &&
\r
4445 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4446 GameListPopUp(f, fileTitle);
\r
4449 GameListDestroy();
\r
4452 LoadGame(f, number, fileTitle, FALSE);
\r
4457 ChangedConsoleFont()
\r
4460 CHARRANGE tmpsel, sel;
\r
4461 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4462 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4463 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4466 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4467 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4468 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4469 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4470 * size. This was undocumented in the version of MSVC++ that I had
\r
4471 * when I wrote the code, but is apparently documented now.
\r
4473 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4474 cfmt.bCharSet = f->lf.lfCharSet;
\r
4475 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4476 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4477 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4478 /* Why are the following seemingly needed too? */
\r
4479 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4480 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4481 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4483 tmpsel.cpMax = -1; /*999999?*/
\r
4484 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4485 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4486 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4487 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4489 paraf.cbSize = sizeof(paraf);
\r
4490 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4491 paraf.dxStartIndent = 0;
\r
4492 paraf.dxOffset = WRAP_INDENT;
\r
4493 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4494 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4497 /*---------------------------------------------------------------------------*\
\r
4499 * Window Proc for main window
\r
4501 \*---------------------------------------------------------------------------*/
\r
4503 /* Process messages for main window, etc. */
\r
4505 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4508 int wmId, wmEvent;
\r
4512 char fileTitle[MSG_SIZ];
\r
4515 switch (message) {
\r
4517 case WM_PAINT: /* message: repaint portion of window */
\r
4521 case WM_ERASEBKGND:
\r
4522 if (IsIconic(hwnd)) {
\r
4523 /* Cheat; change the message */
\r
4524 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4526 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4530 case WM_LBUTTONDOWN:
\r
4531 case WM_MBUTTONDOWN:
\r
4532 case WM_RBUTTONDOWN:
\r
4533 case WM_LBUTTONUP:
\r
4534 case WM_MBUTTONUP:
\r
4535 case WM_RBUTTONUP:
\r
4536 case WM_MOUSEMOVE:
\r
4537 MouseEvent(hwnd, message, wParam, lParam);
\r
4542 if (appData.icsActive) {
\r
4543 if (wParam == '\t') {
\r
4544 if (GetKeyState(VK_SHIFT) < 0) {
\r
4546 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4547 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4551 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4552 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4556 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4557 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4559 SendMessage(h, message, wParam, lParam);
\r
4561 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4562 PopUpMoveDialog((char)wParam);
\r
4566 case WM_PALETTECHANGED:
\r
4567 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4569 HDC hdc = GetDC(hwndMain);
\r
4570 SelectPalette(hdc, hPal, TRUE);
\r
4571 nnew = RealizePalette(hdc);
\r
4573 paletteChanged = TRUE;
\r
4575 UpdateColors(hdc);
\r
4577 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
4580 ReleaseDC(hwnd, hdc);
\r
4584 case WM_QUERYNEWPALETTE:
\r
4585 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4587 HDC hdc = GetDC(hwndMain);
\r
4588 paletteChanged = FALSE;
\r
4589 SelectPalette(hdc, hPal, FALSE);
\r
4590 nnew = RealizePalette(hdc);
\r
4592 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4594 ReleaseDC(hwnd, hdc);
\r
4599 case WM_COMMAND: /* message: command from application menu */
\r
4600 wmId = LOWORD(wParam);
\r
4601 wmEvent = HIWORD(wParam);
\r
4606 AnalysisPopDown();
\r
4609 case IDM_NewGameFRC:
4610 if( NewGameFRC() == 0 ) {
4616 case IDM_LoadGame:
\r
4617 LoadGameDialog(hwnd, "Load Game from File");
\r
4620 case IDM_LoadNextGame:
\r
4624 case IDM_LoadPrevGame:
\r
4628 case IDM_ReloadGame:
\r
4632 case IDM_LoadPosition:
\r
4633 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4634 Reset(FALSE, TRUE);
\r
4637 f = OpenFileDialog(hwnd, FALSE, "",
\r
4638 appData.oldSaveStyle ? "pos" : "fen",
\r
4640 "Load Position from File", &number, fileTitle, NULL);
\r
4642 LoadPosition(f, number, fileTitle);
\r
4646 case IDM_LoadNextPosition:
\r
4647 ReloadPosition(1);
\r
4650 case IDM_LoadPrevPosition:
\r
4651 ReloadPosition(-1);
\r
4654 case IDM_ReloadPosition:
\r
4655 ReloadPosition(0);
\r
4658 case IDM_SaveGame:
\r
4659 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4660 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4661 appData.oldSaveStyle ? "gam" : "pgn",
\r
4663 "Save Game to File", NULL, fileTitle, NULL);
\r
4665 SaveGame(f, 0, "");
\r
4669 case IDM_SavePosition:
\r
4670 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4671 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4672 appData.oldSaveStyle ? "pos" : "fen",
\r
4674 "Save Position to File", NULL, fileTitle, NULL);
\r
4676 SavePosition(f, 0, "");
\r
4680 case IDM_CopyGame:
\r
4681 CopyGameToClipboard();
\r
4684 case IDM_PasteGame:
\r
4685 PasteGameFromClipboard();
\r
4688 case IDM_CopyGameListToClipboard:
4689 CopyGameListToClipboard();
4692 /* [AS] Autodetect FEN or PGN data */
4694 PasteGameOrFENFromClipboard();
4697 /* [AS] Move history */
4698 case IDM_ShowMoveHistory:
4699 if( MoveHistoryIsUp() ) {
4700 MoveHistoryPopDown();
4707 /* [AS] Eval graph */
4708 case IDM_ShowEvalGraph:
4709 if( EvalGraphIsUp() ) {
4717 /* [AS] Engine output */
4718 case IDM_ShowEngineOutput:
4719 if( EngineOutputIsUp() ) {
4720 EngineOutputPopDown();
4723 EngineOutputPopUp();
4727 /* [AS] User adjudication */
4728 case IDM_UserAdjudication_White:
4729 UserAdjudicationEvent( +1 );
4732 case IDM_UserAdjudication_Black:
4733 UserAdjudicationEvent( -1 );
4736 case IDM_UserAdjudication_Draw:
4737 UserAdjudicationEvent( 0 );
4740 /* [AS] Game list options dialog */
4741 case IDM_GameListOptions:
4745 case IDM_CopyPosition:
\r
4746 CopyFENToClipboard();
\r
4749 case IDM_PastePosition:
\r
4750 PasteFENFromClipboard();
\r
4753 case IDM_MailMove:
\r
4757 case IDM_ReloadCMailMsg:
\r
4758 Reset(TRUE, TRUE);
\r
4759 ReloadCmailMsgEvent(FALSE);
\r
4762 case IDM_Minimize:
\r
4763 ShowWindow(hwnd, SW_MINIMIZE);
\r
4770 case IDM_MachineWhite:
\r
4771 MachineWhiteEvent();
\r
4773 * refresh the tags dialog only if it's visible
\r
4775 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4777 tags = PGNTags(&gameInfo);
\r
4778 TagsPopUp(tags, CmailMsg());
\r
4783 case IDM_MachineBlack:
\r
4784 MachineBlackEvent();
\r
4786 * refresh the tags dialog only if it's visible
\r
4788 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
4790 tags = PGNTags(&gameInfo);
\r
4791 TagsPopUp(tags, CmailMsg());
\r
4796 case IDM_TwoMachines:
\r
4797 TwoMachinesEvent();
\r
4799 * refresh the tags dialog only if it's visible
\r
4801 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
4803 tags = PGNTags(&gameInfo);
\r
4804 TagsPopUp(tags, CmailMsg());
\r
4809 case IDM_AnalysisMode:
\r
4810 if (!first.analysisSupport) {
\r
4811 char buf[MSG_SIZ];
\r
4812 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4813 DisplayError(buf, 0);
\r
4815 if (!appData.showThinking) ToggleShowThinking();
\r
4816 AnalyzeModeEvent();
\r
4820 case IDM_AnalyzeFile:
\r
4821 if (!first.analysisSupport) {
\r
4822 char buf[MSG_SIZ];
\r
4823 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4824 DisplayError(buf, 0);
\r
4826 if (!appData.showThinking) ToggleShowThinking();
\r
4827 AnalyzeFileEvent();
\r
4828 LoadGameDialog(hwnd, "Analyze Game from File");
\r
4829 AnalysisPeriodicEvent(1);
\r
4833 case IDM_IcsClient:
\r
4837 case IDM_EditGame:
\r
4841 case IDM_EditPosition:
\r
4842 EditPositionEvent();
\r
4845 case IDM_Training:
\r
4849 case IDM_ShowGameList:
\r
4850 ShowGameListProc();
\r
4853 case IDM_EditTags:
\r
4857 case IDM_EditComment:
\r
4858 if (commentDialogUp && editComment) {
\r
4861 EditCommentEvent();
\r
4881 case IDM_CallFlag:
\r
4901 case IDM_StopObserving:
\r
4902 StopObservingEvent();
\r
4905 case IDM_StopExamining:
\r
4906 StopExaminingEvent();
\r
4909 case IDM_TypeInMove:
\r
4910 PopUpMoveDialog('\000');
\r
4913 case IDM_Backward:
\r
4915 SetFocus(hwndMain);
\r
4920 SetFocus(hwndMain);
\r
4925 SetFocus(hwndMain);
\r
4930 SetFocus(hwndMain);
\r
4937 case IDM_TruncateGame:
\r
4938 TruncateGameEvent();
\r
4945 case IDM_RetractMove:
\r
4946 RetractMoveEvent();
\r
4949 case IDM_FlipView:
\r
4950 flipView = !flipView;
\r
4951 DrawPosition(FALSE, NULL);
\r
4954 case IDM_GeneralOptions:
\r
4955 GeneralOptionsPopup(hwnd);
\r
4956 DrawPosition(TRUE, NULL);
4959 case IDM_BoardOptions:
\r
4960 BoardOptionsPopup(hwnd);
\r
4963 case IDM_EnginePlayOptions:
4964 EnginePlayOptionsPopup(hwnd);
4967 case IDM_OptionsUCI:
4968 UciOptionsPopup(hwnd);
4971 case IDM_IcsOptions:
\r
4972 IcsOptionsPopup(hwnd);
\r
4976 FontsOptionsPopup(hwnd);
\r
4980 SoundOptionsPopup(hwnd);
\r
4983 case IDM_CommPort:
\r
4984 CommPortOptionsPopup(hwnd);
\r
4987 case IDM_LoadOptions:
\r
4988 LoadOptionsPopup(hwnd);
\r
4991 case IDM_SaveOptions:
\r
4992 SaveOptionsPopup(hwnd);
\r
4995 case IDM_TimeControl:
\r
4996 TimeControlOptionsPopup(hwnd);
\r
4999 case IDM_SaveSettings:
\r
5000 SaveSettings(settingsFileName);
\r
5003 case IDM_SaveSettingsOnExit:
\r
5004 saveSettingsOnExit = !saveSettingsOnExit;
\r
5005 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5006 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5007 MF_CHECKED : MF_UNCHECKED));
\r
5018 case IDM_AboutGame:
\r
5023 appData.debugMode = !appData.debugMode;
\r
5024 if (appData.debugMode) {
\r
5025 char dir[MSG_SIZ];
\r
5026 GetCurrentDirectory(MSG_SIZ, dir);
\r
5027 SetCurrentDirectory(installDir);
\r
5028 debugFP = fopen(appData.nameOfDebugFile, "w");
5029 SetCurrentDirectory(dir);
\r
5030 setbuf(debugFP, NULL);
\r
5037 case IDM_HELPCONTENTS:
\r
5038 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5039 MessageBox (GetFocus(),
\r
5040 "Unable to activate help",
\r
5041 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5045 case IDM_HELPSEARCH:
\r
5046 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5047 MessageBox (GetFocus(),
\r
5048 "Unable to activate help",
\r
5049 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5053 case IDM_HELPHELP:
\r
5054 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5055 MessageBox (GetFocus(),
\r
5056 "Unable to activate help",
\r
5057 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5062 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5064 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5065 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5066 FreeProcInstance(lpProc);
\r
5069 case IDM_DirectCommand1:
\r
5070 AskQuestionEvent("Direct Command",
\r
5071 "Send to chess program:", "", "1");
\r
5073 case IDM_DirectCommand2:
\r
5074 AskQuestionEvent("Direct Command",
\r
5075 "Send to second chess program:", "", "2");
\r
5078 case EP_WhitePawn:
\r
5079 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5080 fromX = fromY = -1;
\r
5083 case EP_WhiteKnight:
\r
5084 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5085 fromX = fromY = -1;
\r
5088 case EP_WhiteBishop:
\r
5089 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5090 fromX = fromY = -1;
\r
5093 case EP_WhiteRook:
\r
5094 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5095 fromX = fromY = -1;
\r
5098 case EP_WhiteQueen:
\r
5099 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5100 fromX = fromY = -1;
\r
5103 case EP_WhiteKing:
\r
5104 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5105 fromX = fromY = -1;
\r
5108 case EP_BlackPawn:
\r
5109 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5110 fromX = fromY = -1;
\r
5113 case EP_BlackKnight:
\r
5114 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5115 fromX = fromY = -1;
\r
5118 case EP_BlackBishop:
\r
5119 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5120 fromX = fromY = -1;
\r
5123 case EP_BlackRook:
\r
5124 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5125 fromX = fromY = -1;
\r
5128 case EP_BlackQueen:
\r
5129 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5130 fromX = fromY = -1;
\r
5133 case EP_BlackKing:
\r
5134 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5135 fromX = fromY = -1;
\r
5138 case EP_EmptySquare:
\r
5139 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5140 fromX = fromY = -1;
\r
5143 case EP_ClearBoard:
\r
5144 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5145 fromX = fromY = -1;
\r
5149 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5150 fromX = fromY = -1;
\r
5154 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5155 fromX = fromY = -1;
\r
5159 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5160 fromX = fromY = -1;
\r
5164 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5165 fromX = fromY = -1;
\r
5169 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5170 fromX = fromY = -1;
\r
5174 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5175 fromX = fromY = -1;
\r
5179 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5180 fromX = fromY = -1;
\r
5184 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5190 case CLOCK_TIMER_ID:
\r
5191 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5192 clockTimerEvent = 0;
\r
5193 DecrementClocks(); /* call into back end */
\r
5195 case LOAD_GAME_TIMER_ID:
\r
5196 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5197 loadGameTimerEvent = 0;
\r
5198 AutoPlayGameLoop(); /* call into back end */
\r
5200 case ANALYSIS_TIMER_ID:
\r
5201 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
5202 appData.periodicUpdates) {
\r
5203 AnalysisPeriodicEvent(0);
\r
5205 KillTimer(hwnd, analysisTimerEvent);
\r
5206 analysisTimerEvent = 0;
\r
5209 case DELAYED_TIMER_ID:
\r
5210 KillTimer(hwnd, delayedTimerEvent);
\r
5211 delayedTimerEvent = 0;
\r
5212 delayedTimerCallback();
\r
5217 case WM_USER_Input:
\r
5218 InputEvent(hwnd, message, wParam, lParam);
\r
5221 /* [AS] Also move "attached" child windows */
5222 case WM_WINDOWPOSCHANGING:
5223 if( hwnd == hwndMain && appData.useStickyWindows ) {
5224 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
5226 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
5227 /* Window is moving */
5230 GetWindowRect( hwnd, &rcMain );
5232 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
5233 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
5234 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
5240 case WM_ENTERSIZEMOVE:
\r
5241 if (hwnd == hwndMain) {
\r
5242 doingSizing = TRUE;
\r
5245 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
5249 if (hwnd == hwndMain) {
\r
5250 lastSizing = wParam;
\r
5255 return OnMoving( &sd, hwnd, wParam, lParam );
5257 case WM_EXITSIZEMOVE:
\r
5258 if (hwnd == hwndMain) {
\r
5260 doingSizing = FALSE;
\r
5261 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5262 GetClientRect(hwnd, &client);
\r
5263 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5266 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
5269 case WM_DESTROY: /* message: window being destroyed */
\r
5270 PostQuitMessage(0);
\r
5274 if (hwnd == hwndMain) {
\r
5279 default: /* Passes it on if unprocessed */
\r
5280 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5285 /*---------------------------------------------------------------------------*\
\r
5287 * Misc utility routines
\r
5289 \*---------------------------------------------------------------------------*/
\r
5292 * Decent random number generator, at least not as bad as Windows
\r
5293 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5295 unsigned int randstate;
\r
5300 randstate = randstate * 1664525 + 1013904223;
\r
5301 return (int) randstate & 0x7fffffff;
\r
5305 mysrandom(unsigned int seed)
\r
5312 * returns TRUE if user selects a different color, FALSE otherwise
\r
5316 ChangeColor(HWND hwnd, COLORREF *which)
\r
5318 static BOOL firstTime = TRUE;
\r
5319 static DWORD customColors[16];
\r
5321 COLORREF newcolor;
\r
5326 /* Make initial colors in use available as custom colors */
\r
5327 /* Should we put the compiled-in defaults here instead? */
\r
5329 customColors[i++] = lightSquareColor & 0xffffff;
\r
5330 customColors[i++] = darkSquareColor & 0xffffff;
\r
5331 customColors[i++] = whitePieceColor & 0xffffff;
\r
5332 customColors[i++] = blackPieceColor & 0xffffff;
\r
5333 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5334 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5336 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5337 customColors[i++] = textAttribs[ccl].color;
\r
5339 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5340 firstTime = FALSE;
\r
5343 cc.lStructSize = sizeof(cc);
\r
5344 cc.hwndOwner = hwnd;
\r
5345 cc.hInstance = NULL;
\r
5346 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5347 cc.lpCustColors = (LPDWORD) customColors;
\r
5348 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5350 if (!ChooseColor(&cc)) return FALSE;
\r
5352 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5353 if (newcolor == *which) return FALSE;
\r
5354 *which = newcolor;
\r
5358 InitDrawingColors();
\r
5359 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5364 MyLoadSound(MySound *ms)
\r
5370 if (ms->data) free(ms->data);
\r
5373 switch (ms->name[0]) {
\r
5379 /* System sound from Control Panel. Don't preload here. */
\r
5383 if (ms->name[1] == NULLCHAR) {
\r
5384 /* "!" alone = silence */
\r
5387 /* Builtin wave resource. Error if not found. */
\r
5388 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5389 if (h == NULL) break;
\r
5390 ms->data = (void *)LoadResource(hInst, h);
\r
5391 if (h == NULL) break;
\r
5396 /* .wav file. Error if not found. */
\r
5397 f = fopen(ms->name, "rb");
\r
5398 if (f == NULL) break;
\r
5399 if (fstat(fileno(f), &st) < 0) break;
\r
5400 ms->data = malloc(st.st_size);
\r
5401 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5407 char buf[MSG_SIZ];
\r
5408 sprintf(buf, "Error loading sound %s", ms->name);
\r
5409 DisplayError(buf, GetLastError());
\r
5415 MyPlaySound(MySound *ms)
\r
5417 BOOLEAN ok = FALSE;
\r
5418 switch (ms->name[0]) {
\r
5424 /* System sound from Control Panel (deprecated feature).
\r
5425 "$" alone or an unset sound name gets default beep (still in use). */
\r
5426 if (ms->name[1]) {
\r
5427 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5429 if (!ok) ok = MessageBeep(MB_OK);
\r
5432 /* Builtin wave resource, or "!" alone for silence */
\r
5433 if (ms->name[1]) {
\r
5434 if (ms->data == NULL) return FALSE;
\r
5435 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5441 /* .wav file. Error if not found. */
\r
5442 if (ms->data == NULL) return FALSE;
\r
5443 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5446 /* Don't print an error: this can happen innocently if the sound driver
\r
5447 is busy; for instance, if another instance of WinBoard is playing
\r
5448 a sound at about the same time. */
\r
5451 char buf[MSG_SIZ];
\r
5452 sprintf(buf, "Error playing sound %s", ms->name);
\r
5453 DisplayError(buf, GetLastError());
\r
5461 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5464 OPENFILENAME *ofn;
\r
5465 static UINT *number; /* gross that this is static */
\r
5467 switch (message) {
\r
5468 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5469 /* Center the dialog over the application window */
\r
5470 ofn = (OPENFILENAME *) lParam;
\r
5471 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5472 number = (UINT *) ofn->lCustData;
\r
5473 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5477 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5478 return FALSE; /* Allow for further processing */
\r
5481 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5482 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5484 return FALSE; /* Allow for further processing */
\r
5490 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5492 static UINT *number;
\r
5493 OPENFILENAME *ofname;
\r
5496 case WM_INITDIALOG:
\r
5497 ofname = (OPENFILENAME *)lParam;
\r
5498 number = (UINT *)(ofname->lCustData);
\r
5501 ofnot = (OFNOTIFY *)lParam;
\r
5502 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5503 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5512 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
5513 char *nameFilt, char *dlgTitle, UINT *number,
\r
5514 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5516 OPENFILENAME openFileName;
\r
5517 char buf1[MSG_SIZ];
\r
5520 if (fileName == NULL) fileName = buf1;
\r
5521 if (defName == NULL) {
\r
5522 strcpy(fileName, "*.");
\r
5523 strcat(fileName, defExt);
\r
5525 strcpy(fileName, defName);
\r
5527 if (fileTitle) strcpy(fileTitle, "");
\r
5528 if (number) *number = 0;
\r
5530 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5531 openFileName.hwndOwner = hwnd;
\r
5532 openFileName.hInstance = (HANDLE) hInst;
\r
5533 openFileName.lpstrFilter = nameFilt;
\r
5534 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5535 openFileName.nMaxCustFilter = 0L;
\r
5536 openFileName.nFilterIndex = 1L;
\r
5537 openFileName.lpstrFile = fileName;
\r
5538 openFileName.nMaxFile = MSG_SIZ;
\r
5539 openFileName.lpstrFileTitle = fileTitle;
\r
5540 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5541 openFileName.lpstrInitialDir = NULL;
\r
5542 openFileName.lpstrTitle = dlgTitle;
\r
5543 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5544 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
5545 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5546 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5547 openFileName.nFileOffset = 0;
\r
5548 openFileName.nFileExtension = 0;
\r
5549 openFileName.lpstrDefExt = defExt;
\r
5550 openFileName.lCustData = (LONG) number;
\r
5551 openFileName.lpfnHook = oldDialog ?
\r
5552 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5553 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5555 if (write ? GetSaveFileName(&openFileName) :
\r
5556 GetOpenFileName(&openFileName)) {
\r
5557 /* open the file */
\r
5558 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
5560 MessageBox(hwnd, "File open failed", NULL,
\r
5561 MB_OK|MB_ICONEXCLAMATION);
\r
5565 int err = CommDlgExtendedError();
\r
5566 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
5575 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5577 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5580 * Get the first pop-up menu in the menu template. This is the
\r
5581 * menu that TrackPopupMenu displays.
\r
5583 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5585 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5588 * TrackPopup uses screen coordinates, so convert the
\r
5589 * coordinates of the mouse click to screen coordinates.
\r
5591 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5593 /* Draw and track the floating pop-up menu. */
\r
5594 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5595 pt.x, pt.y, 0, hwnd, NULL);
\r
5597 /* Destroy the menu.*/
\r
5598 DestroyMenu(hmenu);
\r
5603 int sizeX, sizeY, newSizeX, newSizeY;
\r
5605 } ResizeEditPlusButtonsClosure;
\r
5608 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5610 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5614 if (hChild == cl->hText) return TRUE;
\r
5615 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5616 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5617 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5618 ScreenToClient(cl->hDlg, &pt);
\r
5619 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5620 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5624 /* Resize a dialog that has a (rich) edit field filling most of
\r
5625 the top, with a row of buttons below */
\r
5627 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
5630 int newTextHeight, newTextWidth;
\r
5631 ResizeEditPlusButtonsClosure cl;
\r
5633 /*if (IsIconic(hDlg)) return;*/
\r
5634 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
5636 cl.hdwp = BeginDeferWindowPos(8);
\r
5638 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
5639 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5640 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5641 if (newTextHeight < 0) {
\r
5642 newSizeY += -newTextHeight;
\r
5643 newTextHeight = 0;
\r
5645 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
5646 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5652 cl.newSizeX = newSizeX;
\r
5653 cl.newSizeY = newSizeY;
\r
5654 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
5656 EndDeferWindowPos(cl.hdwp);
\r
5659 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
5661 RECT rChild, rParent;
\r
5662 int wChild, hChild, wParent, hParent;
\r
5663 int wScreen, hScreen, xNew, yNew;
\r
5666 /* Get the Height and Width of the child window */
\r
5667 GetWindowRect (hwndChild, &rChild);
\r
5668 wChild = rChild.right - rChild.left;
\r
5669 hChild = rChild.bottom - rChild.top;
\r
5671 /* Get the Height and Width of the parent window */
\r
5672 GetWindowRect (hwndParent, &rParent);
\r
5673 wParent = rParent.right - rParent.left;
\r
5674 hParent = rParent.bottom - rParent.top;
\r
5676 /* Get the display limits */
\r
5677 hdc = GetDC (hwndChild);
\r
5678 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
5679 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
5680 ReleaseDC(hwndChild, hdc);
\r
5682 /* Calculate new X position, then adjust for screen */
\r
5683 xNew = rParent.left + ((wParent - wChild) /2);
\r
5686 } else if ((xNew+wChild) > wScreen) {
\r
5687 xNew = wScreen - wChild;
\r
5690 /* Calculate new Y position, then adjust for screen */
\r
5692 yNew = rParent.top + ((hParent - hChild) /2);
\r
5695 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
5700 } else if ((yNew+hChild) > hScreen) {
\r
5701 yNew = hScreen - hChild;
\r
5704 /* Set it, and return */
\r
5705 return SetWindowPos (hwndChild, NULL,
\r
5706 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
5709 /* Center one window over another */
5710 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
5712 return CenterWindowEx( hwndChild, hwndParent, 0 );
5715 /*---------------------------------------------------------------------------*\
\r
5717 * Startup Dialog functions
\r
5719 \*---------------------------------------------------------------------------*/
\r
5721 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
5723 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5725 while (*cd != NULL) {
\r
5726 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
5732 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
5734 char buf1[ARG_MAX];
\r
5737 if (str[0] == '@') {
\r
5738 FILE* f = fopen(str + 1, "r");
\r
5740 DisplayFatalError(str + 1, errno, 2);
\r
5743 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
5745 buf1[len] = NULLCHAR;
\r
5749 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5752 char buf[MSG_SIZ];
\r
5753 char *end = strchr(str, '\n');
\r
5754 if (end == NULL) return;
\r
5755 memcpy(buf, str, end - str);
\r
5756 buf[end - str] = NULLCHAR;
\r
5757 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
5763 SetStartupDialogEnables(HWND hDlg)
\r
5765 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5766 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5767 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5768 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5769 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
5770 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
5771 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5772 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
5773 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
5774 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
5775 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5776 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
5777 IsDlgButtonChecked(hDlg, OPT_View));
\r
5781 QuoteForFilename(char *filename)
\r
5783 int dquote, space;
\r
5784 dquote = strchr(filename, '"') != NULL;
\r
5785 space = strchr(filename, ' ') != NULL;
\r
5786 if (dquote || space) {
\r
5798 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
5800 char buf[MSG_SIZ];
\r
5803 InitComboStringsFromOption(hwndCombo, nthnames);
\r
5804 q = QuoteForFilename(nthcp);
\r
5805 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
5806 if (*nthdir != NULLCHAR) {
\r
5807 q = QuoteForFilename(nthdir);
\r
5808 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
5810 if (*nthcp == NULLCHAR) {
\r
5811 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5812 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5813 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5814 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5819 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5821 char buf[MSG_SIZ];
\r
5825 switch (message) {
\r
5826 case WM_INITDIALOG:
\r
5827 /* Center the dialog */
\r
5828 CenterWindow (hDlg, GetDesktopWindow());
\r
5829 /* Initialize the dialog items */
\r
5830 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5831 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
5832 firstChessProgramNames);
\r
5833 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5834 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
5835 secondChessProgramNames);
\r
5836 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
5837 InitComboStringsFromOption(hwndCombo, icsNames);
\r
5838 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
5839 if (*appData.icsHelper != NULLCHAR) {
\r
5840 char *q = QuoteForFilename(appData.icsHelper);
\r
5841 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
5843 if (*appData.icsHost == NULLCHAR) {
\r
5844 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5845 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
5846 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5847 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5848 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5851 if (appData.icsActive) {
5852 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
5854 else if (appData.noChessProgram) {
5855 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
5858 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
5861 SetStartupDialogEnables(hDlg);
\r
5865 switch (LOWORD(wParam)) {
\r
5867 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
5868 strcpy(buf, "/fcp=");
\r
5869 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5871 ParseArgs(StringGet, &p);
\r
5872 strcpy(buf, "/scp=");
\r
5873 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5875 ParseArgs(StringGet, &p);
\r
5876 appData.noChessProgram = FALSE;
\r
5877 appData.icsActive = FALSE;
\r
5878 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
5879 strcpy(buf, "/ics /icshost=");
\r
5880 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5882 ParseArgs(StringGet, &p);
\r
5883 if (appData.zippyPlay) {
\r
5884 strcpy(buf, "/fcp=");
\r
5885 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5887 ParseArgs(StringGet, &p);
\r
5889 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
5890 appData.noChessProgram = TRUE;
\r
5891 appData.icsActive = FALSE;
\r
5893 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
5894 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
5897 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
5898 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
5900 ParseArgs(StringGet, &p);
\r
5902 EndDialog(hDlg, TRUE);
\r
5909 case IDM_HELPCONTENTS:
\r
5910 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5911 MessageBox (GetFocus(),
\r
5912 "Unable to activate help",
\r
5913 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5918 SetStartupDialogEnables(hDlg);
\r
5926 /*---------------------------------------------------------------------------*\
\r
5928 * About box dialog functions
\r
5930 \*---------------------------------------------------------------------------*/
\r
5932 /* Process messages for "About" dialog box */
\r
5934 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5936 switch (message) {
\r
5937 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5938 /* Center the dialog over the application window */
\r
5939 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5940 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
5943 case WM_COMMAND: /* message: received a command */
\r
5944 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
5945 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
5946 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5954 /*---------------------------------------------------------------------------*\
\r
5956 * Comment Dialog functions
\r
5958 \*---------------------------------------------------------------------------*/
\r
5961 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5963 static HANDLE hwndText = NULL;
\r
5964 int len, newSizeX, newSizeY, flags;
\r
5965 static int sizeX, sizeY;
\r
5970 switch (message) {
\r
5971 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5972 /* Initialize the dialog items */
\r
5973 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
5974 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
5975 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
5976 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
5977 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
5978 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
5979 SetWindowText(hDlg, commentTitle);
\r
5980 if (editComment) {
\r
5981 SetFocus(hwndText);
\r
5983 SetFocus(GetDlgItem(hDlg, IDOK));
\r
5985 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
5986 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
5987 MAKELPARAM(FALSE, 0));
\r
5988 /* Size and position the dialog */
\r
5989 if (!commentDialog) {
\r
5990 commentDialog = hDlg;
\r
5991 flags = SWP_NOZORDER;
\r
5992 GetClientRect(hDlg, &rect);
\r
5993 sizeX = rect.right;
\r
5994 sizeY = rect.bottom;
\r
5995 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
5996 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
5997 WINDOWPLACEMENT wp;
\r
5998 EnsureOnScreen(&commentX, &commentY);
\r
5999 wp.length = sizeof(WINDOWPLACEMENT);
\r
6001 wp.showCmd = SW_SHOW;
\r
6002 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6003 wp.rcNormalPosition.left = commentX;
\r
6004 wp.rcNormalPosition.right = commentX + commentW;
\r
6005 wp.rcNormalPosition.top = commentY;
\r
6006 wp.rcNormalPosition.bottom = commentY + commentH;
\r
6007 SetWindowPlacement(hDlg, &wp);
\r
6009 GetClientRect(hDlg, &rect);
\r
6010 newSizeX = rect.right;
\r
6011 newSizeY = rect.bottom;
\r
6012 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6013 newSizeX, newSizeY);
\r
6020 case WM_COMMAND: /* message: received a command */
\r
6021 switch (LOWORD(wParam)) {
\r
6023 if (editComment) {
\r
6025 /* Read changed options from the dialog box */
\r
6026 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6027 len = GetWindowTextLength(hwndText);
\r
6028 str = (char *) malloc(len + 1);
\r
6029 GetWindowText(hwndText, str, len + 1);
\r
6038 ReplaceComment(commentIndex, str);
\r
6045 case OPT_CancelComment:
\r
6049 case OPT_ClearComment:
\r
6050 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6053 case OPT_EditComment:
\r
6054 EditCommentEvent();
\r
6063 newSizeX = LOWORD(lParam);
\r
6064 newSizeY = HIWORD(lParam);
\r
6065 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6070 case WM_GETMINMAXINFO:
\r
6071 /* Prevent resizing window too small */
\r
6072 mmi = (MINMAXINFO *) lParam;
\r
6073 mmi->ptMinTrackSize.x = 100;
\r
6074 mmi->ptMinTrackSize.y = 100;
\r
6081 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6086 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6088 if (str == NULL) str = "";
\r
6089 p = (char *) malloc(2 * strlen(str) + 2);
\r
6092 if (*str == '\n') *q++ = '\r';
\r
6096 if (commentText != NULL) free(commentText);
\r
6098 commentIndex = index;
\r
6099 commentTitle = title;
\r
6101 editComment = edit;
\r
6103 if (commentDialog) {
\r
6104 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6105 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
6107 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6108 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6109 hwndMain, (DLGPROC)lpProc);
\r
6110 FreeProcInstance(lpProc);
\r
6112 commentDialogUp = TRUE;
\r
6116 /*---------------------------------------------------------------------------*\
\r
6118 * Type-in move dialog functions
\r
6120 \*---------------------------------------------------------------------------*/
\r
6123 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6125 char move[MSG_SIZ];
\r
6127 ChessMove moveType;
\r
6128 int fromX, fromY, toX, toY;
\r
6131 switch (message) {
\r
6132 case WM_INITDIALOG:
\r
6133 move[0] = (char) lParam;
\r
6134 move[1] = NULLCHAR;
\r
6135 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
6136 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6137 SetWindowText(hInput, move);
\r
6139 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6143 switch (LOWORD(wParam)) {
\r
6145 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
6146 gameMode != Training) {
\r
6147 DisplayMoveError("Displayed move is not current");
\r
6149 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6150 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6151 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
6152 if (gameMode != Training)
\r
6153 forwardMostMove = currentMove;
\r
6154 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
6156 DisplayMoveError("Could not parse move");
\r
6159 EndDialog(hDlg, TRUE);
\r
6162 EndDialog(hDlg, FALSE);
\r
6173 PopUpMoveDialog(char firstchar)
\r
6177 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
6178 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
6179 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
6180 gameMode == EditPosition || gameMode == IcsExamining ||
\r
6181 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
6182 gameMode == Training) {
\r
6183 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6184 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6185 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6186 FreeProcInstance(lpProc);
\r
6190 /*---------------------------------------------------------------------------*\
\r
6194 \*---------------------------------------------------------------------------*/
\r
6196 /* Nonmodal error box */
\r
6197 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6198 WPARAM wParam, LPARAM lParam);
\r
6201 ErrorPopUp(char *title, char *content)
\r
6205 BOOLEAN modal = hwndMain == NULL;
\r
6223 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6224 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6227 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6229 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6230 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6231 hwndMain, (DLGPROC)lpProc);
\r
6232 FreeProcInstance(lpProc);
\r
6239 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6240 if (errorDialog == NULL) return;
\r
6241 DestroyWindow(errorDialog);
\r
6242 errorDialog = NULL;
\r
6246 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6251 switch (message) {
\r
6252 case WM_INITDIALOG:
\r
6253 GetWindowRect(hDlg, &rChild);
\r
6256 SetWindowPos(hDlg, NULL, rChild.left,
\r
6257 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6258 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6262 [AS] It seems that the above code wants to move the dialog up in the "caption
6263 area" of the main window, but it uses the dialog height as an hard-coded constant,
6264 and it doesn't work when you resize the dialog.
6265 For now, just give it a default position.
6267 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
6269 errorDialog = hDlg;
\r
6270 SetWindowText(hDlg, errorTitle);
\r
6271 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6272 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6276 switch (LOWORD(wParam)) {
\r
6279 if (errorDialog == hDlg) errorDialog = NULL;
\r
6280 DestroyWindow(hDlg);
\r
6291 /*---------------------------------------------------------------------------*\
\r
6293 * Ics Interaction console functions
\r
6295 \*---------------------------------------------------------------------------*/
\r
6297 #define HISTORY_SIZE 64
\r
6298 static char *history[HISTORY_SIZE];
\r
6299 int histIn = 0, histP = 0;
\r
6302 SaveInHistory(char *cmd)
\r
6304 if (history[histIn] != NULL) {
\r
6305 free(history[histIn]);
\r
6306 history[histIn] = NULL;
\r
6308 if (*cmd == NULLCHAR) return;
\r
6309 history[histIn] = StrSave(cmd);
\r
6310 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6311 if (history[histIn] != NULL) {
\r
6312 free(history[histIn]);
\r
6313 history[histIn] = NULL;
\r
6319 PrevInHistory(char *cmd)
\r
6322 if (histP == histIn) {
\r
6323 if (history[histIn] != NULL) free(history[histIn]);
\r
6324 history[histIn] = StrSave(cmd);
\r
6326 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6327 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6329 return history[histP];
\r
6335 if (histP == histIn) return NULL;
\r
6336 histP = (histP + 1) % HISTORY_SIZE;
\r
6337 return history[histP];
\r
6344 BOOLEAN immediate;
\r
6345 } IcsTextMenuEntry;
\r
6346 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
6347 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
6350 ParseIcsTextMenu(char *icsTextMenuString)
\r
6353 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
6354 char *p = icsTextMenuString;
\r
6355 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6358 if (e->command != NULL) {
\r
6360 e->command = NULL;
\r
6364 e = icsTextMenuEntry;
\r
6365 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6366 if (*p == ';' || *p == '\n') {
\r
6367 e->item = strdup("-");
\r
6368 e->command = NULL;
\r
6370 } else if (*p == '-') {
\r
6371 e->item = strdup("-");
\r
6372 e->command = NULL;
\r
6376 char *q, *r, *s, *t;
\r
6378 q = strchr(p, ',');
\r
6379 if (q == NULL) break;
\r
6381 r = strchr(q + 1, ',');
\r
6382 if (r == NULL) break;
\r
6384 s = strchr(r + 1, ',');
\r
6385 if (s == NULL) break;
\r
6388 t = strchr(s + 1, c);
\r
6391 t = strchr(s + 1, c);
\r
6393 if (t != NULL) *t = NULLCHAR;
\r
6394 e->item = strdup(p);
\r
6395 e->command = strdup(q + 1);
\r
6396 e->getname = *(r + 1) != '0';
\r
6397 e->immediate = *(s + 1) != '0';
\r
6401 if (t == NULL) break;
\r
6410 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6414 hmenu = LoadMenu(hInst, "TextMenu");
\r
6415 h = GetSubMenu(hmenu, 0);
\r
6417 if (strcmp(e->item, "-") == 0) {
\r
6418 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6420 if (e->item[0] == '|') {
\r
6421 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6422 IDM_CommandX + i, &e->item[1]);
\r
6424 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
6433 WNDPROC consoleTextWindowProc;
\r
6436 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6438 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6439 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6443 SetWindowText(hInput, command);
\r
6445 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6447 sel.cpMin = 999999;
\r
6448 sel.cpMax = 999999;
\r
6449 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6454 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6455 if (sel.cpMin == sel.cpMax) {
\r
6456 /* Expand to surrounding word */
\r
6459 tr.chrg.cpMax = sel.cpMin;
\r
6460 tr.chrg.cpMin = --sel.cpMin;
\r
6461 if (sel.cpMin < 0) break;
\r
6462 tr.lpstrText = name;
\r
6463 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6464 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6468 tr.chrg.cpMin = sel.cpMax;
\r
6469 tr.chrg.cpMax = ++sel.cpMax;
\r
6470 tr.lpstrText = name;
\r
6471 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6472 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6475 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6476 MessageBeep(MB_ICONEXCLAMATION);
\r
6480 tr.lpstrText = name;
\r
6481 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6483 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6484 MessageBeep(MB_ICONEXCLAMATION);
\r
6487 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6490 sprintf(buf, "%s %s", command, name);
\r
6491 SetWindowText(hInput, buf);
\r
6492 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6494 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
6495 SetWindowText(hInput, buf);
\r
6496 sel.cpMin = 999999;
\r
6497 sel.cpMax = 999999;
\r
6498 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6504 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6509 switch (message) {
\r
6511 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6514 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6517 sel.cpMin = 999999;
\r
6518 sel.cpMax = 999999;
\r
6519 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6520 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6525 if (wParam == '\t') {
\r
6526 if (GetKeyState(VK_SHIFT) < 0) {
\r
6528 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6529 if (buttonDesc[0].hwnd) {
\r
6530 SetFocus(buttonDesc[0].hwnd);
\r
6532 SetFocus(hwndMain);
\r
6536 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
6539 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6541 SendMessage(hInput, message, wParam, lParam);
\r
6545 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6547 return SendMessage(hInput, message, wParam, lParam);
\r
6548 case WM_MBUTTONDOWN:
\r
6549 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6550 case WM_RBUTTONDOWN:
\r
6551 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6552 /* Move selection here if it was empty */
\r
6554 pt.x = LOWORD(lParam);
\r
6555 pt.y = HIWORD(lParam);
\r
6556 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6557 if (sel.cpMin == sel.cpMax) {
\r
6558 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6559 sel.cpMax = sel.cpMin;
\r
6560 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6562 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6565 case WM_RBUTTONUP:
\r
6566 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6567 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6568 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6571 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6572 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6573 if (sel.cpMin == sel.cpMax) {
\r
6574 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6575 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6577 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6578 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6580 pt.x = LOWORD(lParam);
\r
6581 pt.y = HIWORD(lParam);
\r
6582 MenuPopup(hwnd, pt, hmenu, -1);
\r
6586 switch (LOWORD(wParam)) {
\r
6587 case IDM_QuickPaste:
\r
6589 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6590 if (sel.cpMin == sel.cpMax) {
\r
6591 MessageBeep(MB_ICONEXCLAMATION);
\r
6594 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6595 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6596 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6601 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6604 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6607 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6611 int i = LOWORD(wParam) - IDM_CommandX;
\r
6612 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
6613 icsTextMenuEntry[i].command != NULL) {
\r
6614 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
6615 icsTextMenuEntry[i].getname,
\r
6616 icsTextMenuEntry[i].immediate);
\r
6624 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
6627 WNDPROC consoleInputWindowProc;
\r
6630 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6632 char buf[MSG_SIZ];
\r
6634 static BOOL sendNextChar = FALSE;
\r
6635 static BOOL quoteNextChar = FALSE;
\r
6636 InputSource *is = consoleInputSource;
\r
6640 switch (message) {
\r
6642 if (!appData.localLineEditing || sendNextChar) {
\r
6643 is->buf[0] = (CHAR) wParam;
\r
6645 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6646 sendNextChar = FALSE;
\r
6649 if (quoteNextChar) {
\r
6650 buf[0] = (char) wParam;
\r
6651 buf[1] = NULLCHAR;
\r
6652 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
6653 quoteNextChar = FALSE;
\r
6657 case '\r': /* Enter key */
\r
6658 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
6659 if (consoleEcho) SaveInHistory(is->buf);
\r
6660 is->buf[is->count++] = '\n';
\r
6661 is->buf[is->count] = NULLCHAR;
\r
6662 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6663 if (consoleEcho) {
\r
6664 ConsoleOutput(is->buf, is->count, TRUE);
\r
6665 } else if (appData.localLineEditing) {
\r
6666 ConsoleOutput("\n", 1, TRUE);
\r
6669 case '\033': /* Escape key */
\r
6670 SetWindowText(hwnd, "");
\r
6671 cf.cbSize = sizeof(CHARFORMAT);
\r
6672 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6673 if (consoleEcho) {
\r
6674 cf.crTextColor = textAttribs[ColorNormal].color;
\r
6676 cf.crTextColor = COLOR_ECHOOFF;
\r
6678 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
6679 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6681 case '\t': /* Tab key */
\r
6682 if (GetKeyState(VK_SHIFT) < 0) {
\r
6684 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
6687 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6688 if (buttonDesc[0].hwnd) {
\r
6689 SetFocus(buttonDesc[0].hwnd);
\r
6691 SetFocus(hwndMain);
\r
6695 case '\023': /* Ctrl+S */
\r
6696 sendNextChar = TRUE;
\r
6698 case '\021': /* Ctrl+Q */
\r
6699 quoteNextChar = TRUE;
\r
6708 GetWindowText(hwnd, buf, MSG_SIZ);
\r
6709 p = PrevInHistory(buf);
\r
6711 SetWindowText(hwnd, p);
\r
6712 sel.cpMin = 999999;
\r
6713 sel.cpMax = 999999;
\r
6714 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6719 p = NextInHistory();
\r
6721 SetWindowText(hwnd, p);
\r
6722 sel.cpMin = 999999;
\r
6723 sel.cpMax = 999999;
\r
6724 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6730 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6734 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
6738 case WM_MBUTTONDOWN:
\r
6739 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6740 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6742 case WM_RBUTTONUP:
\r
6743 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6744 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6745 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6749 hmenu = LoadMenu(hInst, "InputMenu");
\r
6750 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6751 if (sel.cpMin == sel.cpMax) {
\r
6752 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6753 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
6755 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6756 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6758 pt.x = LOWORD(lParam);
\r
6759 pt.y = HIWORD(lParam);
\r
6760 MenuPopup(hwnd, pt, hmenu, -1);
\r
6764 switch (LOWORD(wParam)) {
\r
6766 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
6768 case IDM_SelectAll:
\r
6770 sel.cpMax = -1; /*999999?*/
\r
6771 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6774 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6777 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6780 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6785 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
6788 #define CO_MAX 100000
\r
6789 #define CO_TRIM 1000
\r
6792 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6795 static HWND hText, hInput, hFocus;
\r
6796 InputSource *is = consoleInputSource;
\r
6798 static int sizeX, sizeY;
\r
6799 int newSizeX, newSizeY;
\r
6802 switch (message) {
\r
6803 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6804 hwndConsole = hDlg;
\r
6805 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
6806 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
6808 consoleTextWindowProc = (WNDPROC)
\r
6809 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
6810 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6811 consoleInputWindowProc = (WNDPROC)
\r
6812 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
6813 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6814 Colorize(ColorNormal, TRUE);
\r
6815 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
6816 ChangedConsoleFont();
\r
6817 GetClientRect(hDlg, &rect);
\r
6818 sizeX = rect.right;
\r
6819 sizeY = rect.bottom;
\r
6820 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
6821 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
6822 WINDOWPLACEMENT wp;
\r
6823 EnsureOnScreen(&consoleX, &consoleY);
\r
6824 wp.length = sizeof(WINDOWPLACEMENT);
\r
6826 wp.showCmd = SW_SHOW;
\r
6827 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6828 wp.rcNormalPosition.left = consoleX;
\r
6829 wp.rcNormalPosition.right = consoleX + consoleW;
\r
6830 wp.rcNormalPosition.top = consoleY;
\r
6831 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
6832 SetWindowPlacement(hDlg, &wp);
\r
6846 if (IsIconic(hDlg)) break;
\r
6847 newSizeX = LOWORD(lParam);
\r
6848 newSizeY = HIWORD(lParam);
\r
6849 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
6850 RECT rectText, rectInput;
\r
6852 int newTextHeight, newTextWidth;
\r
6853 GetWindowRect(hText, &rectText);
\r
6854 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6855 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6856 if (newTextHeight < 0) {
\r
6857 newSizeY += -newTextHeight;
\r
6858 newTextHeight = 0;
\r
6860 SetWindowPos(hText, NULL, 0, 0,
\r
6861 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6862 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
6863 pt.x = rectInput.left;
\r
6864 pt.y = rectInput.top + newSizeY - sizeY;
\r
6865 ScreenToClient(hDlg, &pt);
\r
6866 SetWindowPos(hInput, NULL,
\r
6867 pt.x, pt.y, /* needs client coords */
\r
6868 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
6869 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
6875 case WM_GETMINMAXINFO:
\r
6876 /* Prevent resizing window too small */
\r
6877 mmi = (MINMAXINFO *) lParam;
\r
6878 mmi->ptMinTrackSize.x = 100;
\r
6879 mmi->ptMinTrackSize.y = 100;
\r
6883 case WM_ENTERSIZEMOVE:
6884 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
6887 return OnSizing( &sd, hDlg, wParam, lParam );
6890 return OnMoving( &sd, hDlg, wParam, lParam );
6892 case WM_EXITSIZEMOVE:
6893 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
6896 return DefWindowProc(hDlg, message, wParam, lParam);
\r
6904 if (hwndConsole) return;
\r
6905 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
6906 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
6911 ConsoleOutput(char* data, int length, int forceVisible)
\r
6916 char buf[CO_MAX+1];
\r
6919 static int delayLF = 0;
\r
6920 CHARRANGE savesel, sel;
\r
6922 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
6930 while (length--) {
\r
6938 } else if (*p == '\007') {
\r
6939 MyPlaySound(&sounds[(int)SoundBell]);
\r
6946 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
6947 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6948 /* Save current selection */
\r
6949 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
6950 exlen = GetWindowTextLength(hText);
\r
6951 /* Find out whether current end of text is visible */
\r
6952 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
6953 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
6954 /* Trim existing text if it's too long */
\r
6955 if (exlen + (q - buf) > CO_MAX) {
\r
6956 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
6959 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6960 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
6962 savesel.cpMin -= trim;
\r
6963 savesel.cpMax -= trim;
\r
6964 if (exlen < 0) exlen = 0;
\r
6965 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
6966 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
6968 /* Append the new text */
\r
6969 sel.cpMin = exlen;
\r
6970 sel.cpMax = exlen;
\r
6971 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6972 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
6973 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
6974 if (forceVisible || exlen == 0 ||
\r
6975 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
6976 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
6977 /* Scroll to make new end of text visible if old end of text
\r
6978 was visible or new text is an echo of user typein */
\r
6979 sel.cpMin = 9999999;
\r
6980 sel.cpMax = 9999999;
\r
6981 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6982 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6983 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
6984 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6986 if (savesel.cpMax == exlen || forceVisible) {
\r
6987 /* Move insert point to new end of text if it was at the old
\r
6988 end of text or if the new text is an echo of user typein */
\r
6989 sel.cpMin = 9999999;
\r
6990 sel.cpMax = 9999999;
\r
6991 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6993 /* Restore previous selection */
\r
6994 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
6996 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7003 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7004 RECT *rect, char *color)
\r
7008 COLORREF oldFg, oldBg;
\r
7011 if (appData.clockMode) {
\r
7013 sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));
\r
7015 sprintf(buf, "%s: %s", color, TimeString(timeRemaining));
\r
7022 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7023 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7025 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7026 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7028 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7030 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7031 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7032 rect, str, strlen(str), NULL);
\r
7034 (void) SetTextColor(hdc, oldFg);
\r
7035 (void) SetBkColor(hdc, oldBg);
\r
7036 (void) SelectObject(hdc, oldFont);
\r
7041 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7048 if (appData.debugMode) {
7049 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
7052 return ERROR_INVALID_USER_BUFFER;
7055 ResetEvent(ovl->hEvent);
\r
7056 ovl->Offset = ovl->OffsetHigh = 0;
\r
7057 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7061 err = GetLastError();
\r
7062 if (err == ERROR_IO_PENDING) {
\r
7063 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7067 err = GetLastError();
\r
7074 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7079 ResetEvent(ovl->hEvent);
\r
7080 ovl->Offset = ovl->OffsetHigh = 0;
\r
7081 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7085 err = GetLastError();
\r
7086 if (err == ERROR_IO_PENDING) {
\r
7087 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7091 err = GetLastError();
\r
7097 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
7098 void CheckForInputBufferFull( InputSource * is )
7100 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
7101 /* Look for end of line */
7104 while( p < is->next && *p != '\n' ) {
7108 if( p >= is->next ) {
7109 if (appData.debugMode) {
7110 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
7113 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
7114 is->count = (DWORD) -1;
7121 InputThread(LPVOID arg)
\r
7126 is = (InputSource *) arg;
\r
7127 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7128 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7129 while (is->hThread != NULL) {
\r
7130 is->error = DoReadFile(is->hFile, is->next,
\r
7131 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7132 &is->count, &ovl);
\r
7133 if (is->error == NO_ERROR) {
\r
7134 is->next += is->count;
\r
7136 if (is->error == ERROR_BROKEN_PIPE) {
\r
7137 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7140 is->count = (DWORD) -1;
\r
7141 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
7146 CheckForInputBufferFull( is );
7148 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7150 if( is->count == ((DWORD) -1) ) break; /* [AS] */
7152 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7155 CloseHandle(ovl.hEvent);
\r
7156 CloseHandle(is->hFile);
\r
7158 if (appData.debugMode) {
7159 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
7166 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7168 NonOvlInputThread(LPVOID arg)
\r
7175 is = (InputSource *) arg;
\r
7176 while (is->hThread != NULL) {
\r
7177 is->error = ReadFile(is->hFile, is->next,
\r
7178 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7179 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7180 if (is->error == NO_ERROR) {
\r
7181 /* Change CRLF to LF */
\r
7182 if (is->next > is->buf) {
\r
7184 i = is->count + 1;
\r
7192 if (prev == '\r' && *p == '\n') {
\r
7204 if (is->error == ERROR_BROKEN_PIPE) {
\r
7205 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7208 is->count = (DWORD) -1;
\r
7212 CheckForInputBufferFull( is );
7214 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7216 if( is->count == ((DWORD) -1) ) break; /* [AS] */
7218 if (is->count < 0) break; /* Quit on error */
\r
7220 CloseHandle(is->hFile);
\r
7225 SocketInputThread(LPVOID arg)
\r
7229 is = (InputSource *) arg;
\r
7230 while (is->hThread != NULL) {
\r
7231 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7232 if ((int)is->count == SOCKET_ERROR) {
\r
7233 is->count = (DWORD) -1;
\r
7234 is->error = WSAGetLastError();
\r
7236 is->error = NO_ERROR;
\r
7237 is->next += is->count;
\r
7238 if (is->count == 0 && is->second == is) {
\r
7239 /* End of file on stderr; quit with no message */
\r
7243 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7245 if( is->count == ((DWORD) -1) ) break; /* [AS] */
7247 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7253 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7257 is = (InputSource *) lParam;
\r
7258 if (is->lineByLine) {
\r
7259 /* Feed in lines one by one */
\r
7260 char *p = is->buf;
\r
7262 while (q < is->next) {
\r
7263 if (*q++ == '\n') {
\r
7264 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7269 /* Move any partial line to the start of the buffer */
\r
7271 while (p < is->next) {
\r
7276 if (is->error != NO_ERROR || is->count == 0) {
\r
7277 /* Notify backend of the error. Note: If there was a partial
\r
7278 line at the end, it is not flushed through. */
\r
7279 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7282 /* Feed in the whole chunk of input at once */
\r
7283 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7284 is->next = is->buf;
\r
7288 /*---------------------------------------------------------------------------*\
\r
7290 * Menu enables. Used when setting various modes.
\r
7292 \*---------------------------------------------------------------------------*/
\r
7300 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7302 while (enab->item > 0) {
\r
7303 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7308 Enables gnuEnables[] = {
\r
7309 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7310 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7311 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7312 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7313 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7314 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7315 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7316 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7317 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7318 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7322 Enables icsEnables[] = {
\r
7323 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7324 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7325 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7326 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7327 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7328 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7329 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7330 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7331 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7332 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7333 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7334 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7339 Enables zippyEnables[] = {
\r
7340 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7341 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7342 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7347 Enables ncpEnables[] = {
\r
7348 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7349 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7350 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7351 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7352 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7353 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7354 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7355 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7356 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7357 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7358 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7359 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7360 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7361 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7362 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7366 Enables trainingOnEnables[] = {
\r
7367 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7368 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7369 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7370 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7371 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7372 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7373 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7374 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7378 Enables trainingOffEnables[] = {
\r
7379 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7380 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7381 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7382 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7383 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7384 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7385 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7386 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7390 /* These modify either ncpEnables or gnuEnables */
\r
7391 Enables cmailEnables[] = {
\r
7392 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7393 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7394 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7395 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7396 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7397 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7398 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7402 Enables machineThinkingEnables[] = {
\r
7403 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7404 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7405 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7406 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7407 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7408 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7409 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7410 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7411 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7412 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7413 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7414 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7415 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7416 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7417 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7421 Enables userThinkingEnables[] = {
\r
7422 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7423 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7424 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7425 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7426 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7427 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7428 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7429 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7430 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7431 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7432 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7433 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7434 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7435 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7436 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7440 /*---------------------------------------------------------------------------*\
\r
7442 * Front-end interface functions exported by XBoard.
\r
7443 * Functions appear in same order as prototypes in frontend.h.
\r
7445 \*---------------------------------------------------------------------------*/
\r
7449 static UINT prevChecked = 0;
\r
7450 static int prevPausing = 0;
\r
7453 if (pausing != prevPausing) {
\r
7454 prevPausing = pausing;
\r
7455 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7456 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
7457 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
7460 switch (gameMode) {
\r
7461 case BeginningOfGame:
\r
7462 if (appData.icsActive)
\r
7463 nowChecked = IDM_IcsClient;
\r
7464 else if (appData.noChessProgram)
\r
7465 nowChecked = IDM_EditGame;
\r
7467 nowChecked = IDM_MachineBlack;
\r
7469 case MachinePlaysBlack:
\r
7470 nowChecked = IDM_MachineBlack;
\r
7472 case MachinePlaysWhite:
\r
7473 nowChecked = IDM_MachineWhite;
\r
7475 case TwoMachinesPlay:
\r
7476 nowChecked = IDM_TwoMachines;
\r
7479 nowChecked = IDM_AnalysisMode;
\r
7482 nowChecked = IDM_AnalyzeFile;
\r
7485 nowChecked = IDM_EditGame;
\r
7487 case PlayFromGameFile:
\r
7488 nowChecked = IDM_LoadGame;
\r
7490 case EditPosition:
\r
7491 nowChecked = IDM_EditPosition;
\r
7494 nowChecked = IDM_Training;
\r
7496 case IcsPlayingWhite:
\r
7497 case IcsPlayingBlack:
\r
7498 case IcsObserving:
\r
7500 nowChecked = IDM_IcsClient;
\r
7507 if (prevChecked != 0)
\r
7508 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7509 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
7510 if (nowChecked != 0)
\r
7511 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7512 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
7514 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
7515 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
7516 MF_BYCOMMAND|MF_ENABLED);
\r
7518 (void) EnableMenuItem(GetMenu(hwndMain),
\r
7519 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
7522 prevChecked = nowChecked;
\r
7528 HMENU hmenu = GetMenu(hwndMain);
\r
7529 SetMenuEnables(hmenu, icsEnables);
\r
7530 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
7531 MF_BYPOSITION|MF_ENABLED);
\r
7533 if (appData.zippyPlay) {
\r
7534 SetMenuEnables(hmenu, zippyEnables);
\r
7542 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
7548 HMENU hmenu = GetMenu(hwndMain);
\r
7549 SetMenuEnables(hmenu, ncpEnables);
\r
7550 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
7551 MF_BYPOSITION|MF_GRAYED);
\r
7552 DrawMenuBar(hwndMain);
\r
7558 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
7562 SetTrainingModeOn()
\r
7565 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
7566 for (i = 0; i < N_BUTTONS; i++) {
\r
7567 if (buttonDesc[i].hwnd != NULL)
\r
7568 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
7573 VOID SetTrainingModeOff()
\r
7576 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
7577 for (i = 0; i < N_BUTTONS; i++) {
\r
7578 if (buttonDesc[i].hwnd != NULL)
\r
7579 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
7585 SetUserThinkingEnables()
\r
7587 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
7591 SetMachineThinkingEnables()
\r
7593 HMENU hMenu = GetMenu(hwndMain);
\r
7594 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
7596 SetMenuEnables(hMenu, machineThinkingEnables);
\r
7598 if (gameMode == MachinePlaysBlack) {
\r
7599 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
7600 } else if (gameMode == MachinePlaysWhite) {
\r
7601 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
7602 } else if (gameMode == TwoMachinesPlay) {
\r
7603 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
7609 DisplayTitle(char *str)
\r
7611 char title[MSG_SIZ], *host;
\r
7612 if (str[0] != NULLCHAR) {
\r
7613 strcpy(title, str);
\r
7614 } else if (appData.icsActive) {
\r
7615 if (appData.icsCommPort[0] != NULLCHAR)
\r
7618 host = appData.icsHost;
\r
7619 sprintf(title, "%s: %s", szTitle, host);
\r
7620 } else if (appData.noChessProgram) {
\r
7621 strcpy(title, szTitle);
\r
7623 strcpy(title, szTitle);
\r
7624 strcat(title, ": ");
\r
7625 strcat(title, first.tidy);
\r
7627 SetWindowText(hwndMain, title);
\r
7632 DisplayMessage(char *str1, char *str2)
\r
7636 int remain = MESSAGE_TEXT_MAX - 1;
\r
7639 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
7640 messageText[0] = NULLCHAR;
\r
7642 len = strlen(str1);
\r
7643 if (len > remain) len = remain;
\r
7644 strncpy(messageText, str1, len);
\r
7645 messageText[len] = NULLCHAR;
\r
7648 if (*str2 && remain >= 2) {
\r
7650 strcat(messageText, " ");
\r
7653 len = strlen(str2);
\r
7654 if (len > remain) len = remain;
\r
7655 strncat(messageText, str2, len);
\r
7657 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
7659 if (IsIconic(hwndMain)) return;
\r
7660 hdc = GetDC(hwndMain);
\r
7661 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
7662 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7663 &messageRect, messageText, strlen(messageText), NULL);
\r
7664 (void) SelectObject(hdc, oldFont);
\r
7665 (void) ReleaseDC(hwndMain, hdc);
\r
7669 DisplayError(char *str, int error)
\r
7671 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
7677 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7678 NULL, error, LANG_NEUTRAL,
\r
7679 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7681 sprintf(buf, "%s:\n%s", str, buf2);
\r
7683 ErrorMap *em = errmap;
\r
7684 while (em->err != 0 && em->err != error) em++;
\r
7685 if (em->err != 0) {
\r
7686 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7688 sprintf(buf, "%s:\nError code %d", str, error);
\r
7693 ErrorPopUp("Error", buf);
\r
7698 DisplayMoveError(char *str)
\r
7700 fromX = fromY = -1;
\r
7701 ClearHighlights();
\r
7702 DrawPosition(FALSE, NULL);
\r
7703 if (appData.popupMoveErrors) {
\r
7704 ErrorPopUp("Error", str);
\r
7706 DisplayMessage(str, "");
\r
7707 moveErrorMessageUp = TRUE;
\r
7712 DisplayFatalError(char *str, int error, int exitStatus)
\r
7714 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
7716 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
7719 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7720 NULL, error, LANG_NEUTRAL,
\r
7721 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7723 sprintf(buf, "%s:\n%s", str, buf2);
\r
7725 ErrorMap *em = errmap;
\r
7726 while (em->err != 0 && em->err != error) em++;
\r
7727 if (em->err != 0) {
\r
7728 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7730 sprintf(buf, "%s:\nError code %d", str, error);
\r
7735 if (appData.debugMode) {
\r
7736 fprintf(debugFP, "%s: %s\n", label, str);
\r
7738 if (appData.popupExitMessage) {
\r
7739 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
7740 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
7742 ExitEvent(exitStatus);
\r
7747 DisplayInformation(char *str)
\r
7749 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
7754 DisplayNote(char *str)
\r
7756 ErrorPopUp("Note", str);
\r
7761 char *title, *question, *replyPrefix;
\r
7766 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7768 static QuestionParams *qp;
\r
7769 char reply[MSG_SIZ];
\r
7772 switch (message) {
\r
7773 case WM_INITDIALOG:
\r
7774 qp = (QuestionParams *) lParam;
\r
7775 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7776 SetWindowText(hDlg, qp->title);
\r
7777 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
7778 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
7782 switch (LOWORD(wParam)) {
\r
7784 strcpy(reply, qp->replyPrefix);
\r
7785 if (*reply) strcat(reply, " ");
\r
7786 len = strlen(reply);
\r
7787 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
7788 strcat(reply, "\n");
\r
7789 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
7790 EndDialog(hDlg, TRUE);
\r
7791 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
7794 EndDialog(hDlg, FALSE);
\r
7805 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
7807 QuestionParams qp;
\r
7811 qp.question = question;
\r
7812 qp.replyPrefix = replyPrefix;
\r
7814 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
7815 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
7816 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
7817 FreeProcInstance(lpProc);
\r
7820 /* [AS] Pick FRC position */
7821 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
7823 static int * lpIndexFRC;
7830 lpIndexFRC = (int *) lParam;
7832 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
7834 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
7835 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
7836 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
7837 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
7842 switch( LOWORD(wParam) ) {
7844 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
7845 EndDialog( hDlg, 0 );
7848 EndDialog( hDlg, 1 );
7851 if( HIWORD(wParam) == EN_CHANGE ) {
7852 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
7854 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
7857 case IDC_NFG_Random:
7858 sprintf( buf, "%d", myrandom() % 960 );
7859 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
7872 int index = appData.defaultFrcPosition;
7873 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
7875 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
7878 appData.defaultFrcPosition = index;
7884 /* [AS] Game list options */
7890 static GLT_Item GLT_ItemInfo[] = {
7891 { GLT_EVENT, "Event" },
7892 { GLT_SITE, "Site" },
7893 { GLT_DATE, "Date" },
7894 { GLT_ROUND, "Round" },
7895 { GLT_PLAYERS, "Players" },
7896 { GLT_RESULT, "Result" },
7897 { GLT_WHITE_ELO, "White Rating" },
7898 { GLT_BLACK_ELO, "Black Rating" },
7899 { GLT_TIME_CONTROL,"Time Control" },
7900 { GLT_VARIANT, "Variant" },
7901 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
7905 const char * GLT_FindItem( char id )
7907 const char * result = 0;
7909 GLT_Item * list = GLT_ItemInfo;
7911 while( list->id != 0 ) {
7912 if( list->id == id ) {
7913 result = list->name;
7923 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
7925 const char * name = GLT_FindItem( id );
7929 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
7932 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
7937 void GLT_TagsToList( HWND hDlg, char * tags )
7941 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
7944 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
7948 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
7953 if( strchr( tags, *pc ) == 0 ) {
7954 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
7959 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
7962 char GLT_ListItemToTag( HWND hDlg, int index )
7967 GLT_Item * list = GLT_ItemInfo;
7969 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
7970 while( list->id != 0 ) {
7971 if( strcmp( list->name, name ) == 0 ) {
7983 void GLT_MoveSelection( HWND hDlg, int delta )
7985 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
7986 int idx2 = idx1 + delta;
7987 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
7989 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
7992 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
7993 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
7994 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
7995 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
7999 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
8001 static char glt[64];
8002 static char * lpUserGLT;
8007 lpUserGLT = (char *) lParam;
8009 strcpy( glt, lpUserGLT );
8011 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
8013 /* Initialize list */
8014 GLT_TagsToList( hDlg, glt );
8016 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
8021 switch( LOWORD(wParam) ) {
8024 char * pc = lpUserGLT;
8026 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
8030 id = GLT_ListItemToTag( hDlg, idx );
8034 } while( id != '\0' );
8036 EndDialog( hDlg, 0 );
8039 EndDialog( hDlg, 1 );
8042 case IDC_GLT_Default:
8043 strcpy( glt, GLT_DEFAULT_TAGS );
8044 GLT_TagsToList( hDlg, glt );
8047 case IDC_GLT_Restore:
8048 strcpy( glt, lpUserGLT );
8049 GLT_TagsToList( hDlg, glt );
8053 GLT_MoveSelection( hDlg, -1 );
8057 GLT_MoveSelection( hDlg, +1 );
8067 int GameListOptions()
8071 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
8073 strcpy( glt, appData.gameListTags );
8075 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
8078 /* [AS] Memory leak here! */
8079 appData.gameListTags = strdup( glt );
8087 DisplayIcsInteractionTitle(char *str)
\r
8089 char consoleTitle[MSG_SIZ];
\r
8091 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8092 SetWindowText(hwndConsole, consoleTitle);
\r
8096 DrawPosition(int fullRedraw, Board board)
\r
8098 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8105 fromX = fromY = -1;
\r
8106 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8107 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8108 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8109 dragInfo.lastpos = dragInfo.pos;
\r
8110 dragInfo.start.x = dragInfo.start.y = -1;
\r
8111 dragInfo.from = dragInfo.start;
\r
8113 DrawPosition(TRUE, NULL);
\r
8119 CommentPopUp(char *title, char *str)
\r
8121 HWND hwnd = GetActiveWindow();
\r
8122 EitherCommentPopUp(0, title, str, FALSE);
\r
8123 SetActiveWindow(hwnd);
\r
8127 CommentPopDown(void)
\r
8129 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8130 if (commentDialog) {
\r
8131 ShowWindow(commentDialog, SW_HIDE);
\r
8133 commentDialogUp = FALSE;
\r
8137 EditCommentPopUp(int index, char *title, char *str)
\r
8139 EitherCommentPopUp(index, title, str, TRUE);
\r
8146 MyPlaySound(&sounds[(int)SoundMove]);
\r
8149 VOID PlayIcsWinSound()
\r
8151 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8154 VOID PlayIcsLossSound()
\r
8156 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8159 VOID PlayIcsDrawSound()
\r
8161 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8164 VOID PlayIcsUnfinishedSound()
\r
8166 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8172 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8180 consoleEcho = TRUE;
\r
8181 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8182 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8183 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8192 consoleEcho = FALSE;
\r
8193 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8194 /* This works OK: set text and background both to the same color */
\r
8196 cf.crTextColor = COLOR_ECHOOFF;
\r
8197 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8198 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8201 /* No Raw()...? */
\r
8203 void Colorize(ColorClass cc, int continuation)
\r
8205 currentColorClass = cc;
\r
8206 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8207 consoleCF.crTextColor = textAttribs[cc].color;
\r
8208 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8209 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8215 static char buf[MSG_SIZ];
\r
8216 DWORD bufsiz = MSG_SIZ;
\r
8218 if (!GetUserName(buf, &bufsiz)) {
\r
8219 /*DisplayError("Error getting user name", GetLastError());*/
\r
8220 strcpy(buf, "User");
\r
8228 static char buf[MSG_SIZ];
\r
8229 DWORD bufsiz = MSG_SIZ;
\r
8231 if (!GetComputerName(buf, &bufsiz)) {
\r
8232 /*DisplayError("Error getting host name", GetLastError());*/
\r
8233 strcpy(buf, "Unknown");
\r
8240 ClockTimerRunning()
\r
8242 return clockTimerEvent != 0;
\r
8248 if (clockTimerEvent == 0) return FALSE;
\r
8249 KillTimer(hwndMain, clockTimerEvent);
\r
8250 clockTimerEvent = 0;
\r
8255 StartClockTimer(long millisec)
\r
8257 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8258 (UINT) millisec, NULL);
\r
8262 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8265 hdc = GetDC(hwndMain);
\r
8266 if (!IsIconic(hwndMain)) {
\r
8267 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");
\r
8269 if (highlight && iconCurrent == iconBlack) {
\r
8270 iconCurrent = iconWhite;
\r
8271 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8272 if (IsIconic(hwndMain)) {
\r
8273 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8276 (void) ReleaseDC(hwndMain, hdc);
\r
8278 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8282 DisplayBlackClock(long timeRemaining, int highlight)
\r
8285 hdc = GetDC(hwndMain);
\r
8286 if (!IsIconic(hwndMain)) {
\r
8287 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");
\r
8289 if (highlight && iconCurrent == iconWhite) {
\r
8290 iconCurrent = iconBlack;
\r
8291 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8292 if (IsIconic(hwndMain)) {
\r
8293 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8296 (void) ReleaseDC(hwndMain, hdc);
\r
8298 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8303 LoadGameTimerRunning()
\r
8305 return loadGameTimerEvent != 0;
\r
8309 StopLoadGameTimer()
\r
8311 if (loadGameTimerEvent == 0) return FALSE;
\r
8312 KillTimer(hwndMain, loadGameTimerEvent);
\r
8313 loadGameTimerEvent = 0;
\r
8318 StartLoadGameTimer(long millisec)
\r
8320 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8321 (UINT) millisec, NULL);
\r
8329 char fileTitle[MSG_SIZ];
\r
8331 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8332 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
8333 appData.oldSaveStyle ? "gam" : "pgn",
\r
8335 "Save Game to File", NULL, fileTitle, NULL);
\r
8337 SaveGame(f, 0, "");
\r
8344 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8346 if (delayedTimerEvent != 0) {
\r
8347 if (appData.debugMode) {
\r
8348 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8350 KillTimer(hwndMain, delayedTimerEvent);
\r
8351 delayedTimerEvent = 0;
\r
8352 delayedTimerCallback();
\r
8354 delayedTimerCallback = cb;
\r
8355 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8356 (UINT) millisec, NULL);
\r
8359 DelayedEventCallback
\r
8362 if (delayedTimerEvent) {
\r
8363 return delayedTimerCallback;
\r
8370 CancelDelayedEvent()
\r
8372 if (delayedTimerEvent) {
\r
8373 KillTimer(hwndMain, delayedTimerEvent);
\r
8374 delayedTimerEvent = 0;
\r
8378 /* Start a child process running the given program.
\r
8379 The process's standard output can be read from "from", and its
\r
8380 standard input can be written to "to".
\r
8381 Exit with fatal error if anything goes wrong.
\r
8382 Returns an opaque pointer that can be used to destroy the process
\r
8386 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8388 #define BUFSIZE 4096
\r
8390 HANDLE hChildStdinRd, hChildStdinWr,
\r
8391 hChildStdoutRd, hChildStdoutWr;
\r
8392 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8393 SECURITY_ATTRIBUTES saAttr;
\r
8395 PROCESS_INFORMATION piProcInfo;
\r
8396 STARTUPINFO siStartInfo;
\r
8398 char buf[MSG_SIZ];
\r
8401 if (appData.debugMode) {
\r
8402 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8407 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8408 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8409 saAttr.bInheritHandle = TRUE;
\r
8410 saAttr.lpSecurityDescriptor = NULL;
\r
8413 * The steps for redirecting child's STDOUT:
\r
8414 * 1. Create anonymous pipe to be STDOUT for child.
\r
8415 * 2. Create a noninheritable duplicate of read handle,
\r
8416 * and close the inheritable read handle.
\r
8419 /* Create a pipe for the child's STDOUT. */
\r
8420 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8421 return GetLastError();
\r
8424 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8425 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8426 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8427 FALSE, /* not inherited */
\r
8428 DUPLICATE_SAME_ACCESS);
\r
8430 return GetLastError();
\r
8432 CloseHandle(hChildStdoutRd);
\r
8435 * The steps for redirecting child's STDIN:
\r
8436 * 1. Create anonymous pipe to be STDIN for child.
\r
8437 * 2. Create a noninheritable duplicate of write handle,
\r
8438 * and close the inheritable write handle.
\r
8441 /* Create a pipe for the child's STDIN. */
\r
8442 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8443 return GetLastError();
\r
8446 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8447 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8448 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8449 FALSE, /* not inherited */
\r
8450 DUPLICATE_SAME_ACCESS);
\r
8452 return GetLastError();
\r
8454 CloseHandle(hChildStdinWr);
\r
8456 /* Arrange to (1) look in dir for the child .exe file, and
\r
8457 * (2) have dir be the child's working directory. Interpret
\r
8458 * dir relative to the directory WinBoard loaded from. */
\r
8459 GetCurrentDirectory(MSG_SIZ, buf);
\r
8460 SetCurrentDirectory(installDir);
\r
8461 SetCurrentDirectory(dir);
\r
8463 /* Now create the child process. */
\r
8465 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8466 siStartInfo.lpReserved = NULL;
\r
8467 siStartInfo.lpDesktop = NULL;
\r
8468 siStartInfo.lpTitle = NULL;
\r
8469 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8470 siStartInfo.cbReserved2 = 0;
\r
8471 siStartInfo.lpReserved2 = NULL;
\r
8472 siStartInfo.hStdInput = hChildStdinRd;
\r
8473 siStartInfo.hStdOutput = hChildStdoutWr;
\r
8474 siStartInfo.hStdError = hChildStdoutWr;
\r
8476 fSuccess = CreateProcess(NULL,
\r
8477 cmdLine, /* command line */
\r
8478 NULL, /* process security attributes */
\r
8479 NULL, /* primary thread security attrs */
\r
8480 TRUE, /* handles are inherited */
\r
8481 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
8482 NULL, /* use parent's environment */
\r
8484 &siStartInfo, /* STARTUPINFO pointer */
\r
8485 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
8487 err = GetLastError();
\r
8488 SetCurrentDirectory(buf); /* return to prev directory */
\r
8493 /* Close the handles we don't need in the parent */
\r
8494 CloseHandle(piProcInfo.hThread);
\r
8495 CloseHandle(hChildStdinRd);
\r
8496 CloseHandle(hChildStdoutWr);
\r
8498 /* Prepare return value */
\r
8499 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8500 cp->kind = CPReal;
\r
8501 cp->hProcess = piProcInfo.hProcess;
\r
8502 cp->pid = piProcInfo.dwProcessId;
\r
8503 cp->hFrom = hChildStdoutRdDup;
\r
8504 cp->hTo = hChildStdinWrDup;
\r
8506 *pr = (void *) cp;
\r
8508 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
8509 2000 where engines sometimes don't see the initial command(s)
\r
8510 from WinBoard and hang. I don't understand how that can happen,
\r
8511 but the Sleep is harmless, so I've put it in. Others have also
\r
8512 reported what may be the same problem, so hopefully this will fix
\r
8513 it for them too. */
\r
8521 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
8525 cp = (ChildProc *) pr;
\r
8526 if (cp == NULL) return;
\r
8528 switch (cp->kind) {
\r
8530 /* TerminateProcess is considered harmful, so... */
\r
8531 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
8532 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
8533 /* The following doesn't work because the chess program
\r
8534 doesn't "have the same console" as WinBoard. Maybe
\r
8535 we could arrange for this even though neither WinBoard
\r
8536 nor the chess program uses a console for stdio? */
\r
8537 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
8539 /* [AS] Special termination modes for misbehaving programs... */
8541 if ( appData.debugMode) {
8542 fprintf( debugFP, "Terminating process %u\n", cp->pid );
8545 TerminateProcess( cp->hProcess, 0 );
8547 else if( signal == 10 ) {
8548 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
8550 if( dw != WAIT_OBJECT_0 ) {
8551 if ( appData.debugMode) {
8552 fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
8555 TerminateProcess( cp->hProcess, 0 );
8559 CloseHandle(cp->hProcess);
\r
8563 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
8567 closesocket(cp->sock);
\r
8572 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
8573 closesocket(cp->sock);
\r
8574 closesocket(cp->sock2);
\r
8582 InterruptChildProcess(ProcRef pr)
\r
8586 cp = (ChildProc *) pr;
\r
8587 if (cp == NULL) return;
\r
8588 switch (cp->kind) {
\r
8590 /* The following doesn't work because the chess program
\r
8591 doesn't "have the same console" as WinBoard. Maybe
\r
8592 we could arrange for this even though neither WinBoard
\r
8593 nor the chess program uses a console for stdio */
\r
8594 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
8599 /* Can't interrupt */
\r
8603 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
8610 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
8612 char cmdLine[MSG_SIZ];
\r
8614 if (port[0] == NULLCHAR) {
\r
8615 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
8617 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
8619 return StartChildProcess(cmdLine, "", pr);
\r
8623 /* Code to open TCP sockets */
\r
8626 OpenTCP(char *host, char *port, ProcRef *pr)
\r
8631 struct sockaddr_in sa, mysa;
\r
8632 struct hostent FAR *hp;
\r
8633 unsigned short uport;
\r
8634 WORD wVersionRequested;
\r
8637 /* Initialize socket DLL */
\r
8638 wVersionRequested = MAKEWORD(1, 1);
\r
8639 err = WSAStartup(wVersionRequested, &wsaData);
\r
8640 if (err != 0) return err;
\r
8643 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8644 err = WSAGetLastError();
\r
8649 /* Bind local address using (mostly) don't-care values.
\r
8651 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8652 mysa.sin_family = AF_INET;
\r
8653 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8654 uport = (unsigned short) 0;
\r
8655 mysa.sin_port = htons(uport);
\r
8656 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8657 == SOCKET_ERROR) {
\r
8658 err = WSAGetLastError();
\r
8663 /* Resolve remote host name */
\r
8664 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8665 if (!(hp = gethostbyname(host))) {
\r
8666 unsigned int b0, b1, b2, b3;
\r
8668 err = WSAGetLastError();
\r
8670 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8671 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8672 hp->h_addrtype = AF_INET;
\r
8674 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8675 hp->h_addr_list[0] = (char *) malloc(4);
\r
8676 hp->h_addr_list[0][0] = (char) b0;
\r
8677 hp->h_addr_list[0][1] = (char) b1;
\r
8678 hp->h_addr_list[0][2] = (char) b2;
\r
8679 hp->h_addr_list[0][3] = (char) b3;
\r
8685 sa.sin_family = hp->h_addrtype;
\r
8686 uport = (unsigned short) atoi(port);
\r
8687 sa.sin_port = htons(uport);
\r
8688 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8690 /* Make connection */
\r
8691 if (connect(s, (struct sockaddr *) &sa,
\r
8692 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8693 err = WSAGetLastError();
\r
8698 /* Prepare return value */
\r
8699 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8700 cp->kind = CPSock;
\r
8702 *pr = (ProcRef *) cp;
\r
8708 OpenCommPort(char *name, ProcRef *pr)
\r
8713 char fullname[MSG_SIZ];
\r
8715 if (*name != '\\')
\r
8716 sprintf(fullname, "\\\\.\\%s", name);
\r
8718 strcpy(fullname, name);
\r
8720 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
8721 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
8722 if (h == (HANDLE) -1) {
\r
8723 return GetLastError();
\r
8727 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
8729 /* Accumulate characters until a 100ms pause, then parse */
\r
8730 ct.ReadIntervalTimeout = 100;
\r
8731 ct.ReadTotalTimeoutMultiplier = 0;
\r
8732 ct.ReadTotalTimeoutConstant = 0;
\r
8733 ct.WriteTotalTimeoutMultiplier = 0;
\r
8734 ct.WriteTotalTimeoutConstant = 0;
\r
8735 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
8737 /* Prepare return value */
\r
8738 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8739 cp->kind = CPComm;
\r
8742 *pr = (ProcRef *) cp;
\r
8748 OpenLoopback(ProcRef *pr)
\r
8750 DisplayFatalError("Not implemented", 0, 1);
\r
8756 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
8761 struct sockaddr_in sa, mysa;
\r
8762 struct hostent FAR *hp;
\r
8763 unsigned short uport;
\r
8764 WORD wVersionRequested;
\r
8767 char stderrPortStr[MSG_SIZ];
\r
8769 /* Initialize socket DLL */
\r
8770 wVersionRequested = MAKEWORD(1, 1);
\r
8771 err = WSAStartup(wVersionRequested, &wsaData);
\r
8772 if (err != 0) return err;
\r
8774 /* Resolve remote host name */
\r
8775 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8776 if (!(hp = gethostbyname(host))) {
\r
8777 unsigned int b0, b1, b2, b3;
\r
8779 err = WSAGetLastError();
\r
8781 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8782 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8783 hp->h_addrtype = AF_INET;
\r
8785 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8786 hp->h_addr_list[0] = (char *) malloc(4);
\r
8787 hp->h_addr_list[0][0] = (char) b0;
\r
8788 hp->h_addr_list[0][1] = (char) b1;
\r
8789 hp->h_addr_list[0][2] = (char) b2;
\r
8790 hp->h_addr_list[0][3] = (char) b3;
\r
8796 sa.sin_family = hp->h_addrtype;
\r
8797 uport = (unsigned short) 514;
\r
8798 sa.sin_port = htons(uport);
\r
8799 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8801 /* Bind local socket to unused "privileged" port address
\r
8803 s = INVALID_SOCKET;
\r
8804 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8805 mysa.sin_family = AF_INET;
\r
8806 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8807 for (fromPort = 1023;; fromPort--) {
\r
8808 if (fromPort < 0) {
\r
8810 return WSAEADDRINUSE;
\r
8812 if (s == INVALID_SOCKET) {
\r
8813 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8814 err = WSAGetLastError();
\r
8819 uport = (unsigned short) fromPort;
\r
8820 mysa.sin_port = htons(uport);
\r
8821 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8822 == SOCKET_ERROR) {
\r
8823 err = WSAGetLastError();
\r
8824 if (err == WSAEADDRINUSE) continue;
\r
8828 if (connect(s, (struct sockaddr *) &sa,
\r
8829 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8830 err = WSAGetLastError();
\r
8831 if (err == WSAEADDRINUSE) {
\r
8842 /* Bind stderr local socket to unused "privileged" port address
\r
8844 s2 = INVALID_SOCKET;
\r
8845 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8846 mysa.sin_family = AF_INET;
\r
8847 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8848 for (fromPort = 1023;; fromPort--) {
\r
8849 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
8850 if (fromPort < 0) {
\r
8851 (void) closesocket(s);
\r
8853 return WSAEADDRINUSE;
\r
8855 if (s2 == INVALID_SOCKET) {
\r
8856 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8857 err = WSAGetLastError();
\r
8863 uport = (unsigned short) fromPort;
\r
8864 mysa.sin_port = htons(uport);
\r
8865 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8866 == SOCKET_ERROR) {
\r
8867 err = WSAGetLastError();
\r
8868 if (err == WSAEADDRINUSE) continue;
\r
8869 (void) closesocket(s);
\r
8873 if (listen(s2, 1) == SOCKET_ERROR) {
\r
8874 err = WSAGetLastError();
\r
8875 if (err == WSAEADDRINUSE) {
\r
8877 s2 = INVALID_SOCKET;
\r
8880 (void) closesocket(s);
\r
8881 (void) closesocket(s2);
\r
8887 prevStderrPort = fromPort; // remember port used
\r
8888 sprintf(stderrPortStr, "%d", fromPort);
\r
8890 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
8891 err = WSAGetLastError();
\r
8892 (void) closesocket(s);
\r
8893 (void) closesocket(s2);
\r
8898 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
8899 err = WSAGetLastError();
\r
8900 (void) closesocket(s);
\r
8901 (void) closesocket(s2);
\r
8905 if (*user == NULLCHAR) user = UserName();
\r
8906 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
8907 err = WSAGetLastError();
\r
8908 (void) closesocket(s);
\r
8909 (void) closesocket(s2);
\r
8913 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
8914 err = WSAGetLastError();
\r
8915 (void) closesocket(s);
\r
8916 (void) closesocket(s2);
\r
8921 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
8922 err = WSAGetLastError();
\r
8923 (void) closesocket(s);
\r
8924 (void) closesocket(s2);
\r
8928 (void) closesocket(s2); /* Stop listening */
\r
8930 /* Prepare return value */
\r
8931 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8932 cp->kind = CPRcmd;
\r
8935 *pr = (ProcRef *) cp;
\r
8942 AddInputSource(ProcRef pr, int lineByLine,
\r
8943 InputCallback func, VOIDSTAR closure)
\r
8945 InputSource *is, *is2 = NULL;
8946 ChildProc *cp = (ChildProc *) pr;
\r
8948 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
8949 is->lineByLine = lineByLine;
\r
8951 is->closure = closure;
\r
8952 is->second = NULL;
\r
8953 is->next = is->buf;
\r
8954 if (pr == NoProc) {
\r
8955 is->kind = CPReal;
\r
8956 consoleInputSource = is;
\r
8958 is->kind = cp->kind;
\r
8960 [AS] Try to avoid a race condition if the thread is given control too early:
8961 we create all threads suspended so that the is->hThread variable can be
8962 safely assigned, then let the threads start with ResumeThread.
8964 switch (cp->kind) {
\r
8966 is->hFile = cp->hFrom;
\r
8967 cp->hFrom = NULL; /* now owned by InputThread */
\r
8969 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
8970 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8974 is->hFile = cp->hFrom;
\r
8975 cp->hFrom = NULL; /* now owned by InputThread */
\r
8977 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
8978 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8982 is->sock = cp->sock;
\r
8984 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8985 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8989 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
8991 is->sock = cp->sock;
\r
8993 is2->sock = cp->sock2;
\r
8994 is2->second = is2;
\r
8996 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8997 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8999 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9000 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
9004 if( is->hThread != NULL ) {
9005 ResumeThread( is->hThread );
9008 if( is2 != NULL && is2->hThread != NULL ) {
9009 ResumeThread( is2->hThread );
9013 return (InputSourceRef) is;
\r
9017 RemoveInputSource(InputSourceRef isr)
\r
9021 is = (InputSource *) isr;
\r
9022 is->hThread = NULL; /* tell thread to stop */
\r
9023 CloseHandle(is->hThread);
\r
9024 if (is->second != NULL) {
\r
9025 is->second->hThread = NULL;
\r
9026 CloseHandle(is->second->hThread);
\r
9032 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9035 int outCount = SOCKET_ERROR;
\r
9036 ChildProc *cp = (ChildProc *) pr;
\r
9037 static OVERLAPPED ovl;
\r
9039 if (pr == NoProc) {
\r
9040 ConsoleOutput(message, count, FALSE);
\r
9044 if (ovl.hEvent == NULL) {
\r
9045 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9047 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9049 switch (cp->kind) {
\r
9052 outCount = send(cp->sock, message, count, 0);
\r
9053 if (outCount == SOCKET_ERROR) {
\r
9054 *outError = WSAGetLastError();
\r
9056 *outError = NO_ERROR;
\r
9061 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9062 &dOutCount, NULL)) {
\r
9063 *outError = NO_ERROR;
\r
9064 outCount = (int) dOutCount;
\r
9066 *outError = GetLastError();
\r
9071 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9072 &dOutCount, &ovl);
\r
9073 if (*outError == NO_ERROR) {
\r
9074 outCount = (int) dOutCount;
\r
9082 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9085 /* Ignore delay, not implemented for WinBoard */
\r
9086 return OutputToProcess(pr, message, count, outError);
\r
9091 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9092 char *buf, int count, int error)
\r
9094 DisplayFatalError("Not implemented", 0, 1);
\r
9097 /* see wgamelist.c for Game List functions */
\r
9098 /* see wedittags.c for Edit Tags functions */
\r
9105 char buf[MSG_SIZ];
\r
9108 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9109 f = fopen(buf, "r");
\r
9111 ProcessICSInitScript(f);
\r
9119 StartAnalysisClock()
\r
9121 if (analysisTimerEvent) return;
\r
9122 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9123 (UINT) 2000, NULL);
\r
9127 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9129 static HANDLE hwndText;
\r
9131 static int sizeX, sizeY;
\r
9132 int newSizeX, newSizeY, flags;
\r
9135 switch (message) {
\r
9136 case WM_INITDIALOG: /* message: initialize dialog box */
\r
9137 /* Initialize the dialog items */
\r
9138 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
9139 SetWindowText(hDlg, analysisTitle);
\r
9140 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
9141 /* Size and position the dialog */
\r
9142 if (!analysisDialog) {
\r
9143 analysisDialog = hDlg;
\r
9144 flags = SWP_NOZORDER;
\r
9145 GetClientRect(hDlg, &rect);
\r
9146 sizeX = rect.right;
\r
9147 sizeY = rect.bottom;
\r
9148 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
9149 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
9150 WINDOWPLACEMENT wp;
\r
9151 EnsureOnScreen(&analysisX, &analysisY);
\r
9152 wp.length = sizeof(WINDOWPLACEMENT);
\r
9154 wp.showCmd = SW_SHOW;
\r
9155 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
9156 wp.rcNormalPosition.left = analysisX;
\r
9157 wp.rcNormalPosition.right = analysisX + analysisW;
\r
9158 wp.rcNormalPosition.top = analysisY;
\r
9159 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
9160 SetWindowPlacement(hDlg, &wp);
\r
9162 GetClientRect(hDlg, &rect);
\r
9163 newSizeX = rect.right;
\r
9164 newSizeY = rect.bottom;
\r
9165 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
9166 newSizeX, newSizeY);
\r
9173 case WM_COMMAND: /* message: received a command */
\r
9174 switch (LOWORD(wParam)) {
\r
9184 newSizeX = LOWORD(lParam);
\r
9185 newSizeY = HIWORD(lParam);
\r
9186 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
9191 case WM_GETMINMAXINFO:
\r
9192 /* Prevent resizing window too small */
\r
9193 mmi = (MINMAXINFO *) lParam;
\r
9194 mmi->ptMinTrackSize.x = 100;
\r
9195 mmi->ptMinTrackSize.y = 100;
\r
9202 AnalysisPopUp(char* title, char* str)
\r
9208 EngineOutputPopUp();
9211 if (str == NULL) str = "";
\r
9212 p = (char *) malloc(2 * strlen(str) + 2);
\r
9215 if (*str == '\n') *q++ = '\r';
\r
9219 if (analysisText != NULL) free(analysisText);
\r
9222 if (analysisDialog) {
\r
9223 SetWindowText(analysisDialog, title);
\r
9224 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
9225 ShowWindow(analysisDialog, SW_SHOW);
\r
9227 analysisTitle = title;
\r
9228 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
9229 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
9230 hwndMain, (DLGPROC)lpProc);
\r
9231 FreeProcInstance(lpProc);
\r
9233 analysisDialogUp = TRUE;
\r
9239 if (analysisDialog) {
\r
9240 ShowWindow(analysisDialog, SW_HIDE);
\r
9242 analysisDialogUp = FALSE;
\r
9247 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9249 highlightInfo.sq[0].x = fromX;
\r
9250 highlightInfo.sq[0].y = fromY;
\r
9251 highlightInfo.sq[1].x = toX;
\r
9252 highlightInfo.sq[1].y = toY;
\r
9258 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9259 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9263 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9265 premoveHighlightInfo.sq[0].x = fromX;
\r
9266 premoveHighlightInfo.sq[0].y = fromY;
\r
9267 premoveHighlightInfo.sq[1].x = toX;
\r
9268 premoveHighlightInfo.sq[1].y = toY;
\r
9272 ClearPremoveHighlights()
\r
9274 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9275 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9279 ShutDownFrontEnd()
\r
9281 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9282 DeleteClipboardTempFiles();
\r
9288 if (IsIconic(hwndMain))
\r
9289 ShowWindow(hwndMain, SW_RESTORE);
\r
9291 SetActiveWindow(hwndMain);
\r
9295 * Prototypes for animation support routines
\r
9297 static void ScreenSquare(int column, int row, POINT * pt);
\r
9298 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9299 POINT frames[], int * nFrames);
\r
9305 AnimateMove(board, fromX, fromY, toX, toY)
\r
9312 ChessSquare piece;
\r
9313 POINT start, finish, mid;
\r
9314 POINT frames[kFactor * 2 + 1];
\r
9317 if (!appData.animate) return;
\r
9318 if (doingSizing) return;
\r
9319 if (fromY < 0 || fromX < 0) return;
\r
9320 piece = board[fromY][fromX];
\r
9321 if (piece >= EmptySquare) return;
\r
9323 ScreenSquare(fromX, fromY, &start);
\r
9324 ScreenSquare(toX, toY, &finish);
\r
9326 /* All pieces except knights move in straight line */
\r
9327 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9328 mid.x = start.x + (finish.x - start.x) / 2;
\r
9329 mid.y = start.y + (finish.y - start.y) / 2;
\r
9331 /* Knight: make diagonal movement then straight */
\r
9332 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9333 mid.x = start.x + (finish.x - start.x) / 2;
\r
9337 mid.y = start.y + (finish.y - start.y) / 2;
\r
9341 /* Don't use as many frames for very short moves */
\r
9342 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9343 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9345 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9347 animInfo.from.x = fromX;
\r
9348 animInfo.from.y = fromY;
\r
9349 animInfo.to.x = toX;
\r
9350 animInfo.to.y = toY;
\r
9351 animInfo.lastpos = start;
\r
9352 animInfo.piece = piece;
\r
9353 for (n = 0; n < nFrames; n++) {
\r
9354 animInfo.pos = frames[n];
\r
9355 DrawPosition(FALSE, NULL);
\r
9356 animInfo.lastpos = animInfo.pos;
\r
9357 Sleep(appData.animSpeed);
\r
9359 animInfo.pos = finish;
\r
9360 DrawPosition(FALSE, NULL);
\r
9361 animInfo.piece = EmptySquare;
\r
9364 /* Convert board position to corner of screen rect and color */
\r
9367 ScreenSquare(column, row, pt)
\r
9368 int column; int row; POINT * pt;
\r
9371 pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
9372 pt->y = lineGap + row * (squareSize + lineGap);
\r
9374 pt->x = lineGap + column * (squareSize + lineGap);
\r
9375 pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
9379 /* Generate a series of frame coords from start->mid->finish.
\r
9380 The movement rate doubles until the half way point is
\r
9381 reached, then halves back down to the final destination,
\r
9382 which gives a nice slow in/out effect. The algorithmn
\r
9383 may seem to generate too many intermediates for short
\r
9384 moves, but remember that the purpose is to attract the
\r
9385 viewers attention to the piece about to be moved and
\r
9386 then to where it ends up. Too few frames would be less
\r
9390 Tween(start, mid, finish, factor, frames, nFrames)
\r
9391 POINT * start; POINT * mid;
\r
9392 POINT * finish; int factor;
\r
9393 POINT frames[]; int * nFrames;
\r
9395 int n, fraction = 1, count = 0;
\r
9397 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9398 for (n = 0; n < factor; n++)
\r
9400 for (n = 0; n < factor; n++) {
\r
9401 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9402 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9404 fraction = fraction / 2;
\r
9408 frames[count] = *mid;
\r
9411 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9413 for (n = 0; n < factor; n++) {
\r
9414 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9415 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9417 fraction = fraction * 2;
\r
9423 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
9428 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
9429 first, last, current, current >= 0 ? movelist[current] : "n/a" );
9431 OutputDebugString( buf );
9434 MoveHistorySet( movelist, first, last, current, pvInfoList );
9436 EvalGraphSet( first, last, current, pvInfoList );
9439 void SetProgramStats( FrontEndProgramStats * stats )
9444 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
9445 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
9447 OutputDebugString( buf );
9450 EngineOutputUpdate( stats );