2 * WinBoard.c -- Windows NT front end to XBoard
\r
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
61 #include <sys/stat.h>
\r
64 #include <commdlg.h>
\r
66 #include <richedit.h>
\r
74 #include "winboard.h"
\r
75 #include "frontend.h"
\r
76 #include "backend.h"
\r
78 #include "wclipbrd.h"
\r
79 #include "wgamelist.h"
\r
80 #include "wedittags.h"
\r
81 #include "woptions.h"
\r
82 #include "wsockerr.h"
\r
83 #include "defaults.h"
\r
87 POINT pos; /* window coordinates of current pos */
\r
88 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
89 POINT from; /* board coordinates of the piece's orig pos */
\r
90 POINT to; /* board coordinates of the piece's new pos */
\r
93 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
96 POINT start; /* window coordinates of start pos */
\r
97 POINT pos; /* window coordinates of current pos */
\r
98 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
99 POINT from; /* board coordinates of the piece's orig pos */
\r
102 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
105 POINT sq[2]; /* board coordinates of from, to squares */
\r
108 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
109 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
111 /* Window class names */
\r
112 char szAppName[] = "WinBoard";
\r
113 char szConsoleName[] = "WBConsole";
\r
115 /* Title bar text */
\r
116 char szTitle[] = "WinBoard";
\r
117 char szConsoleTitle[] = "ICS Interaction";
\r
120 char *settingsFileName;
\r
121 BOOLEAN saveSettingsOnExit;
\r
122 char installDir[MSG_SIZ];
\r
124 BoardSize boardSize;
\r
125 BOOLEAN chessProgram;
\r
126 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
127 static int squareSize, lineGap;
\r
128 static int winWidth, winHeight;
\r
129 static RECT messageRect, whiteRect, blackRect;
\r
130 static char messageText[MESSAGE_TEXT_MAX];
\r
131 static int clockTimerEvent = 0;
\r
132 static int loadGameTimerEvent = 0;
\r
133 static int analysisTimerEvent = 0;
\r
134 static DelayedEventCallback delayedTimerCallback;
\r
135 static int delayedTimerEvent = 0;
\r
136 static int buttonCount = 2;
\r
137 char *icsTextMenuString;
\r
139 char *firstChessProgramNames;
\r
140 char *secondChessProgramNames;
\r
142 #define ARG_MAX 20000
\r
144 #define PALETTESIZE 256
\r
146 HINSTANCE hInst; /* current instance */
\r
147 HWND hwndMain = NULL; /* root window*/
\r
148 HWND hwndConsole = NULL;
\r
149 BOOLEAN alwaysOnTop = FALSE;
\r
151 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
152 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
154 ColorClass currentColorClass;
\r
156 HWND hCommPort = NULL; /* currently open comm port */
\r
157 static HWND hwndPause; /* pause button */
\r
158 static HBITMAP pieceBitmap[3][(int) WhiteKing + 1];
\r
159 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
160 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
161 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
162 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
163 static HPEN gridPen = NULL;
\r
164 static HPEN highlightPen = NULL;
\r
165 static HPEN premovePen = NULL;
\r
166 static NPLOGPALETTE pLogPal;
\r
167 static BOOL paletteChanged = FALSE;
\r
168 static HICON iconWhite, iconBlack, iconCurrent;
\r
169 static int doingSizing = FALSE;
\r
170 static int lastSizing = 0;
\r
172 #if __GNUC__ && !defined(_winmajor)
\r
173 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
175 #define oldDialog (_winmajor < 4)
\r
178 char *defaultTextAttribs[] =
\r
180 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
181 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
191 int cliWidth, cliHeight;
\r
194 SizeInfo sizeInfo[] =
\r
196 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
197 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
198 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
199 { "petite", 33, 1, 1, 1, 0, 0 },
\r
200 { "slim", 37, 2, 1, 0, 0, 0 },
\r
201 { "small", 40, 2, 1, 0, 0, 0 },
\r
202 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
203 { "middling", 49, 2, 0, 0, 0, 0 },
\r
204 { "average", 54, 2, 0, 0, 0, 0 },
\r
205 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
206 { "medium", 64, 3, 0, 0, 0, 0 },
\r
207 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
208 { "large", 80, 3, 0, 0, 0, 0 },
\r
209 { "big", 87, 3, 0, 0, 0, 0 },
\r
210 { "huge", 95, 3, 0, 0, 0, 0 },
\r
211 { "giant", 108, 3, 0, 0, 0, 0 },
\r
212 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
213 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
214 { NULL, 0, 0, 0, 0, 0, 0 }
\r
217 #define MF(x) {x, {0, }, {0, }, 0}
\r
218 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
220 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY),
\r
221 MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY),
\r
222 MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY) },
\r
223 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY),
\r
224 MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY),
\r
225 MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY) },
\r
226 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY),
\r
227 MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY),
\r
228 MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY) },
\r
229 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE),
\r
230 MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE),
\r
231 MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE) },
\r
232 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM),
\r
233 MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM),
\r
234 MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM) },
\r
235 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL),
\r
236 MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL),
\r
237 MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL) },
\r
238 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE),
\r
239 MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE),
\r
240 MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE) },
\r
241 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING),
\r
242 MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING),
\r
243 MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING) },
\r
244 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE),
\r
245 MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE),
\r
246 MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE) },
\r
247 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE),
\r
248 MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE),
\r
249 MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE) },
\r
250 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM),
\r
251 MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM),
\r
252 MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM) },
\r
253 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY),
\r
254 MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY),
\r
255 MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY) },
\r
256 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE),
\r
257 MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE),
\r
258 MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE) },
\r
259 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG),
\r
260 MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG),
\r
261 MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG) },
\r
262 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE),
\r
263 MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE),
\r
264 MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE) },
\r
265 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT),
\r
266 MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT),
\r
267 MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT) },
\r
268 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL),
\r
269 MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL),
\r
270 MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL) },
\r
271 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC),
\r
272 MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC),
\r
273 MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC) },
\r
276 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
285 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
286 #define N_BUTTONS 5
\r
288 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
290 {"<<", IDM_ToStart, NULL, NULL},
\r
291 {"<", IDM_Backward, NULL, NULL},
\r
292 {"P", IDM_Pause, NULL, NULL},
\r
293 {">", IDM_Forward, NULL, NULL},
\r
294 {">>", IDM_ToEnd, NULL, NULL},
\r
297 int tinyLayout = 0, smallLayout = 0;
\r
298 #define MENU_BAR_ITEMS 6
\r
299 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
300 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
301 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
305 MySound sounds[(int)NSoundClasses];
\r
306 MyTextAttribs textAttribs[(int)NColorClasses];
\r
308 MyColorizeAttribs colorizeAttribs[] = {
\r
309 { (COLORREF)0, 0, "Shout Text" },
\r
310 { (COLORREF)0, 0, "SShout/CShout" },
\r
311 { (COLORREF)0, 0, "Channel 1 Text" },
\r
312 { (COLORREF)0, 0, "Channel Text" },
\r
313 { (COLORREF)0, 0, "Kibitz Text" },
\r
314 { (COLORREF)0, 0, "Tell Text" },
\r
315 { (COLORREF)0, 0, "Challenge Text" },
\r
316 { (COLORREF)0, 0, "Request Text" },
\r
317 { (COLORREF)0, 0, "Seek Text" },
\r
318 { (COLORREF)0, 0, "Normal Text" },
\r
319 { (COLORREF)0, 0, "None" }
\r
324 static char *commentTitle;
\r
325 static char *commentText;
\r
326 static int commentIndex;
\r
327 static Boolean editComment = FALSE;
\r
328 HWND commentDialog = NULL;
\r
329 BOOLEAN commentDialogUp = FALSE;
\r
330 static int commentX, commentY, commentH, commentW;
\r
332 static char *analysisTitle;
\r
333 static char *analysisText;
\r
334 HWND analysisDialog = NULL;
\r
335 BOOLEAN analysisDialogUp = FALSE;
\r
336 static int analysisX, analysisY, analysisH, analysisW;
\r
338 char errorMessage[2*MSG_SIZ];
\r
339 HWND errorDialog = NULL;
\r
340 BOOLEAN moveErrorMessageUp = FALSE;
\r
341 BOOLEAN consoleEcho = TRUE;
\r
342 CHARFORMAT consoleCF;
\r
343 COLORREF consoleBackgroundColor;
\r
345 char *programVersion;
\r
347 #include <winsock.h>
\r
353 typedef int CPKind;
\r
362 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
365 #define INPUT_SOURCE_BUF_SIZE 4096
\r
367 typedef struct _InputSource {
\r
374 char buf[INPUT_SOURCE_BUF_SIZE];
\r
378 InputCallback func;
\r
379 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
383 InputSource *consoleInputSource;
\r
388 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
389 VOID ConsoleCreate();
\r
391 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
392 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
393 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
394 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
396 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
397 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
398 void ParseIcsTextMenu(char *icsTextMenuString);
\r
399 VOID PopUpMoveDialog(char firstchar);
\r
400 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
403 * Setting "frozen" should disable all user input other than deleting
\r
404 * the window. We do this while engines are initializing themselves.
\r
406 static int frozen = 0;
\r
407 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
413 if (frozen) return;
\r
415 hmenu = GetMenu(hwndMain);
\r
416 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
417 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
419 DrawMenuBar(hwndMain);
\r
422 /* Undo a FreezeUI */
\r
428 if (!frozen) return;
\r
430 hmenu = GetMenu(hwndMain);
\r
431 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
432 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
434 DrawMenuBar(hwndMain);
\r
437 /*---------------------------------------------------------------------------*\
\r
441 \*---------------------------------------------------------------------------*/
\r
444 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
445 LPSTR lpCmdLine, int nCmdShow)
\r
448 HANDLE hAccelMain, hAccelNoAlt;
\r
452 LoadLibrary("RICHED32.DLL");
\r
453 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
455 if (!InitApplication(hInstance)) {
\r
458 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
462 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
463 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
465 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
467 while (GetMessage(&msg, /* message structure */
\r
468 NULL, /* handle of window receiving the message */
\r
469 0, /* lowest message to examine */
\r
470 0)) /* highest message to examine */
\r
472 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
473 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
474 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
475 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
476 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
477 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
478 TranslateMessage(&msg); /* Translates virtual key codes */
\r
479 DispatchMessage(&msg); /* Dispatches message to window */
\r
484 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
487 /*---------------------------------------------------------------------------*\
\r
489 * Initialization functions
\r
491 \*---------------------------------------------------------------------------*/
\r
494 InitApplication(HINSTANCE hInstance)
\r
498 /* Fill in window class structure with parameters that describe the */
\r
501 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
502 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
503 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
504 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
505 wc.hInstance = hInstance; /* Owner of this class */
\r
506 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
507 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
508 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
509 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
510 wc.lpszClassName = szAppName; /* Name to register as */
\r
512 /* Register the window class and return success/failure code. */
\r
513 if (!RegisterClass(&wc)) return FALSE;
\r
515 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
516 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
518 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
519 wc.hInstance = hInstance;
\r
520 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
521 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
522 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
523 wc.lpszMenuName = NULL;
\r
524 wc.lpszClassName = szConsoleName;
\r
526 if (!RegisterClass(&wc)) return FALSE;
\r
531 /* Set by InitInstance, used by EnsureOnScreen */
\r
532 int screenHeight, screenWidth;
\r
535 EnsureOnScreen(int *x, int *y)
\r
537 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
538 if (*x > screenWidth - 32) *x = 0;
\r
539 if (*y > screenHeight - 32) *y = 0;
\r
543 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
545 HWND hwnd; /* Main window handle. */
\r
547 WINDOWPLACEMENT wp;
\r
550 hInst = hInstance; /* Store instance handle in our global variable */
\r
552 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
553 *filepart = NULLCHAR;
\r
555 GetCurrentDirectory(MSG_SIZ, installDir);
\r
557 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
558 if (appData.debugMode) {
\r
559 debugFP = fopen("winboard.debug", "w");
\r
560 setbuf(debugFP, NULL);
\r
565 /* Create a main window for this application instance. */
\r
566 hwnd = CreateWindow(szAppName, szTitle,
\r
567 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
568 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
569 NULL, NULL, hInstance, NULL);
\r
572 /* If window could not be created, return "failure" */
\r
577 iconWhite = LoadIcon(hInstance, "icon_white");
\r
578 iconBlack = LoadIcon(hInstance, "icon_black");
\r
579 iconCurrent = iconWhite;
\r
580 InitDrawingColors();
\r
581 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
582 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
583 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
584 /* Compute window size for each board size, and use the largest
\r
585 size that fits on this screen as the default. */
\r
586 InitDrawingSizes((BoardSize)ibs, 0);
\r
587 if (boardSize == (BoardSize)-1 &&
\r
588 winHeight <= screenHeight && winWidth <= screenWidth) {
\r
589 boardSize = (BoardSize)ibs;
\r
592 InitDrawingSizes(boardSize, 0);
\r
594 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
596 /* Make a console window if needed */
\r
597 if (appData.icsActive) {
\r
603 /* Make the window visible; update its client area; and return "success" */
\r
604 EnsureOnScreen(&boardX, &boardY);
\r
605 wp.length = sizeof(WINDOWPLACEMENT);
\r
607 wp.showCmd = nCmdShow;
\r
608 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
609 wp.rcNormalPosition.left = boardX;
\r
610 wp.rcNormalPosition.right = boardX + winWidth;
\r
611 wp.rcNormalPosition.top = boardY;
\r
612 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
613 SetWindowPlacement(hwndMain, &wp);
\r
615 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
616 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
619 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
620 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
622 ShowWindow(hwndConsole, nCmdShow);
\r
624 UpdateWindow(hwnd);
\r
632 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
633 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
634 ArgSettingsFilename
\r
642 String *pString; // ArgString
\r
643 int *pInt; // ArgInt
\r
644 float *pFloat; // ArgFloat
\r
645 Boolean *pBoolean; // ArgBoolean
\r
646 COLORREF *pColor; // ArgColor
\r
647 ColorClass cc; // ArgAttribs
\r
648 String *pFilename; // ArgFilename
\r
649 BoardSize *pBoardSize; // ArgBoardSize
\r
650 int whichFont; // ArgFont
\r
651 DCB *pDCB; // ArgCommSettings
\r
652 String *pFilename; // ArgSettingsFilename
\r
660 ArgDescriptor argDescriptors[] = {
\r
661 /* positional arguments */
\r
662 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
663 { "", ArgNone, NULL },
\r
664 /* keyword arguments */
\r
665 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
666 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
667 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
668 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
669 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
670 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
671 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
672 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
673 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
674 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
675 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
676 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
677 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
678 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
679 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
680 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
681 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
682 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
684 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
686 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
688 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
689 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
691 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
692 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
693 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
694 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
695 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
696 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
697 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
698 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
699 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
700 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
701 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
702 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
703 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
704 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
705 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
706 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
707 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
708 /*!!bitmapDirectory?*/
\r
709 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
710 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
711 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
712 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
713 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
714 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
715 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
716 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
717 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
718 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
719 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
720 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
721 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
722 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
723 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
724 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
725 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
726 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
727 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
728 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
729 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
730 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
731 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
732 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
733 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
734 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
735 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
736 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
737 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
738 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
739 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
740 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
741 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
742 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
743 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
744 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
745 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
746 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
747 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
748 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
749 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
750 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
751 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
752 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
753 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
754 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
755 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
756 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
757 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
758 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
759 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
760 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
761 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
762 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
763 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
764 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
765 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
766 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
767 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
768 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
769 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
770 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
771 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
772 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
773 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
774 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
775 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
776 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
777 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
778 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
779 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
780 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
781 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
782 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
783 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
784 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
785 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
786 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
787 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
788 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
789 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
790 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
791 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
792 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
793 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
794 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
795 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
796 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
797 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
798 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
799 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
800 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
801 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
802 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
803 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
804 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
805 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
806 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
807 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
808 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
809 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
810 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
811 TRUE }, /* must come after all fonts */
\r
812 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
813 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
814 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
815 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
816 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
817 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
818 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
819 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
820 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
821 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
822 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
823 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
824 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
825 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
826 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
827 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
828 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
829 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
830 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
831 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
832 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
833 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
834 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
835 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
836 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
837 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
838 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
839 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
840 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
841 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
842 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
844 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
845 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
847 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
848 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
849 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
850 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
851 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
852 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
853 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
854 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
855 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
856 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
857 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
858 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
859 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
860 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
861 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
862 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
863 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
864 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
865 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
866 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
867 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
868 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
869 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
870 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
871 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
872 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
873 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
874 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
875 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
876 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
877 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
878 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
879 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
880 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
881 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
882 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
883 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
884 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
885 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
886 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
887 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
888 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
889 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
890 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
891 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
892 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
893 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
894 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
895 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
896 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
897 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
898 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
899 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
900 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
901 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
902 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
903 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
904 { "highlightLastMove", ArgBoolean,
\r
905 (LPVOID) &appData.highlightLastMove, TRUE },
\r
906 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
907 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
908 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
909 { "highlightDragging", ArgBoolean,
\r
910 (LPVOID) &appData.highlightDragging, TRUE },
\r
911 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
912 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
913 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
914 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
915 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
916 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
917 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
918 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
919 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
920 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
921 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
922 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
923 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
924 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
925 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
926 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
927 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
928 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
929 { "soundShout", ArgFilename,
\r
930 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
931 { "soundSShout", ArgFilename,
\r
932 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
933 { "soundChannel1", ArgFilename,
\r
934 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
935 { "soundChannel", ArgFilename,
\r
936 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
937 { "soundKibitz", ArgFilename,
\r
938 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
939 { "soundTell", ArgFilename,
\r
940 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
941 { "soundChallenge", ArgFilename,
\r
942 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
943 { "soundRequest", ArgFilename,
\r
944 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
945 { "soundSeek", ArgFilename,
\r
946 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
947 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
948 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
949 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
950 { "soundIcsLoss", ArgFilename,
\r
951 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
952 { "soundIcsDraw", ArgFilename,
\r
953 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
954 { "soundIcsUnfinished", ArgFilename,
\r
955 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
956 { "soundIcsAlarm", ArgFilename,
\r
957 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
958 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
959 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
960 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
961 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
962 { "reuseChessPrograms", ArgBoolean,
\r
963 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
964 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
965 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
966 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
967 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
968 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
969 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
970 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
971 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
972 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
973 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
974 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
975 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
976 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
977 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
978 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
979 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
980 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
981 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
982 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
983 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
984 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
985 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
986 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
987 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
988 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
989 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
990 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
991 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
992 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
993 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
994 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
995 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
996 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
997 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
998 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
999 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1000 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1002 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1004 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1005 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1006 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1007 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion,
\r
1009 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,
\r
1011 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1012 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1013 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1014 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1016 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1017 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1018 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1019 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1020 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1021 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1022 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1023 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1024 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1025 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1026 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1027 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1028 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1030 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1031 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1032 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1033 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1034 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1035 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1036 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1038 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1039 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1040 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1041 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1042 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1043 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1044 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1045 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1046 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1047 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1048 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1049 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1050 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1051 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1052 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1053 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1054 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1055 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1057 { NULL, ArgNone, NULL, FALSE }
\r
1061 /* Kludge for indirection files on command line */
\r
1062 char* lastIndirectionFilename;
\r
1063 ArgDescriptor argDescriptorIndirection =
\r
1064 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1068 ExitArgError(char *msg, char *badArg)
\r
1070 char buf[MSG_SIZ];
\r
1072 sprintf(buf, "%s %s", msg, badArg);
\r
1073 DisplayFatalError(buf, 0, 2);
\r
1077 /* Command line font name parser. NULL name means do nothing.
\r
1078 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1079 For backward compatibility, syntax without the colon is also
\r
1080 accepted, but font names with digits in them won't work in that case.
\r
1083 ParseFontName(char *name, MyFontParams *mfp)
\r
1086 if (name == NULL) return;
\r
1088 q = strchr(p, ':');
\r
1090 if (q - p >= sizeof(mfp->faceName))
\r
1091 ExitArgError("Font name too long:", name);
\r
1092 memcpy(mfp->faceName, p, q - p);
\r
1093 mfp->faceName[q - p] = NULLCHAR;
\r
1096 q = mfp->faceName;
\r
1097 while (*p && !isdigit(*p)) {
\r
1099 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1100 ExitArgError("Font name too long:", name);
\r
1102 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1105 if (!*p) ExitArgError("Font point size missing:", name);
\r
1106 mfp->pointSize = (float) atof(p);
\r
1107 mfp->bold = (strchr(p, 'b') != NULL);
\r
1108 mfp->italic = (strchr(p, 'i') != NULL);
\r
1109 mfp->underline = (strchr(p, 'u') != NULL);
\r
1110 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1113 /* Color name parser.
\r
1114 X version accepts X color names, but this one
\r
1115 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1117 ParseColorName(char *name)
\r
1119 int red, green, blue, count;
\r
1120 char buf[MSG_SIZ];
\r
1122 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1124 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1125 &red, &green, &blue);
\r
1128 sprintf(buf, "Can't parse color name %s", name);
\r
1129 DisplayError(buf, 0);
\r
1130 return RGB(0, 0, 0);
\r
1132 return PALETTERGB(red, green, blue);
\r
1136 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1138 char *e = argValue;
\r
1142 if (*e == 'b') eff |= CFE_BOLD;
\r
1143 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1144 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1145 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1146 else if (*e == '#' || isdigit(*e)) break;
\r
1150 *color = ParseColorName(e);
\r
1155 ParseBoardSize(char *name)
\r
1157 BoardSize bs = SizeTiny;
\r
1158 while (sizeInfo[bs].name != NULL) {
\r
1159 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1162 ExitArgError("Unrecognized board size value", name);
\r
1163 return bs; /* not reached */
\r
1168 StringGet(void *getClosure)
\r
1170 char **p = (char **) getClosure;
\r
1175 FileGet(void *getClosure)
\r
1178 FILE* f = (FILE*) getClosure;
\r
1187 /* Parse settings file named "name". If file found, return the
\r
1188 full name in fullname and return TRUE; else return FALSE */
\r
1190 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1195 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1196 f = fopen(fullname, "r");
\r
1198 ParseArgs(FileGet, f);
\r
1207 ParseArgs(GetFunc get, void *cl)
\r
1209 char argName[ARG_MAX];
\r
1210 char argValue[ARG_MAX];
\r
1211 ArgDescriptor *ad;
\r
1220 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1221 if (ch == NULLCHAR) break;
\r
1223 /* Comment to end of line */
\r
1225 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1227 } else if (ch == '/' || ch == '-') {
\r
1230 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1231 ch != '\n' && ch != '\t') {
\r
1237 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1238 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1240 if (ad->argName == NULL)
\r
1241 ExitArgError("Unrecognized argument", argName);
\r
1243 } else if (ch == '@') {
\r
1244 /* Indirection file */
\r
1245 ad = &argDescriptorIndirection;
\r
1248 /* Positional argument */
\r
1249 ad = &argDescriptors[posarg++];
\r
1250 strcpy(argName, ad->argName);
\r
1253 if (ad->argType == ArgTrue) {
\r
1254 *(Boolean *) ad->argLoc = TRUE;
\r
1257 if (ad->argType == ArgFalse) {
\r
1258 *(Boolean *) ad->argLoc = FALSE;
\r
1262 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1263 if (ch == NULLCHAR || ch == '\n') {
\r
1264 ExitArgError("No value provided for argument", argName);
\r
1268 // Quoting with { }. No characters have to (or can) be escaped.
\r
1269 // Thus the string cannot contain a '}' character.
\r
1289 } else if (ch == '\'' || ch == '"') {
\r
1290 // Quoting with ' ' or " ", with \ as escape character.
\r
1291 // Inconvenient for long strings that may contain Windows filenames.
\r
1308 if (ch == start) {
\r
1317 if (ad->argType == ArgFilename
\r
1318 || ad->argType == ArgSettingsFilename) {
\r
1324 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1348 for (i = 0; i < 3; i++) {
\r
1349 if (ch >= '0' && ch <= '7') {
\r
1350 octval = octval*8 + (ch - '0');
\r
1357 *q++ = (char) octval;
\r
1368 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1375 switch (ad->argType) {
\r
1377 *(int *) ad->argLoc = atoi(argValue);
\r
1381 *(float *) ad->argLoc = (float) atof(argValue);
\r
1386 *(char **) ad->argLoc = strdup(argValue);
\r
1389 case ArgSettingsFilename:
\r
1391 char fullname[MSG_SIZ];
\r
1392 if (ParseSettingsFile(argValue, fullname)) {
\r
1393 if (ad->argLoc != NULL) {
\r
1394 *(char **) ad->argLoc = strdup(fullname);
\r
1397 if (ad->argLoc != NULL) {
\r
1399 ExitArgError("Failed to open indirection file", argValue);
\r
1406 switch (argValue[0]) {
\r
1409 *(Boolean *) ad->argLoc = TRUE;
\r
1413 *(Boolean *) ad->argLoc = FALSE;
\r
1416 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1422 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1425 case ArgAttribs: {
\r
1426 ColorClass cc = (ColorClass)ad->argLoc;
\r
1427 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1431 case ArgBoardSize:
\r
1432 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1436 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1439 case ArgCommSettings:
\r
1440 ParseCommSettings(argValue, &dcb);
\r
1444 ExitArgError("Unrecognized argument", argValue);
\r
1451 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1453 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1454 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1457 lf->lfEscapement = 0;
\r
1458 lf->lfOrientation = 0;
\r
1459 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1460 lf->lfItalic = mfp->italic;
\r
1461 lf->lfUnderline = mfp->underline;
\r
1462 lf->lfStrikeOut = mfp->strikeout;
\r
1463 lf->lfCharSet = DEFAULT_CHARSET;
\r
1464 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1465 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1466 lf->lfQuality = DEFAULT_QUALITY;
\r
1467 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1468 strcpy(lf->lfFaceName, mfp->faceName);
\r
1472 CreateFontInMF(MyFont *mf)
\r
1474 LFfromMFP(&mf->lf, &mf->mfp);
\r
1475 if (mf->hf) DeleteObject(mf->hf);
\r
1476 mf->hf = CreateFontIndirect(&mf->lf);
\r
1480 SetDefaultTextAttribs()
\r
1483 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1484 ParseAttribs(&textAttribs[cc].color,
\r
1485 &textAttribs[cc].effects,
\r
1486 defaultTextAttribs[cc]);
\r
1491 SetDefaultSounds()
\r
1495 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1496 textAttribs[cc].sound.name = strdup("");
\r
1497 textAttribs[cc].sound.data = NULL;
\r
1499 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1500 sounds[sc].name = strdup("");
\r
1501 sounds[sc].data = NULL;
\r
1503 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1511 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1512 MyLoadSound(&textAttribs[cc].sound);
\r
1514 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1515 MyLoadSound(&sounds[sc]);
\r
1520 InitAppData(LPSTR lpCmdLine)
\r
1523 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1526 programName = szAppName;
\r
1528 /* Initialize to defaults */
\r
1529 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1530 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1531 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1532 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1533 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1534 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1535 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1536 SetDefaultTextAttribs();
\r
1537 SetDefaultSounds();
\r
1538 appData.movesPerSession = MOVES_PER_SESSION;
\r
1539 appData.initString = INIT_STRING;
\r
1540 appData.secondInitString = INIT_STRING;
\r
1541 appData.firstComputerString = COMPUTER_STRING;
\r
1542 appData.secondComputerString = COMPUTER_STRING;
\r
1543 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1544 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1545 appData.firstPlaysBlack = FALSE;
\r
1546 appData.noChessProgram = FALSE;
\r
1547 chessProgram = FALSE;
\r
1548 appData.firstHost = FIRST_HOST;
\r
1549 appData.secondHost = SECOND_HOST;
\r
1550 appData.firstDirectory = FIRST_DIRECTORY;
\r
1551 appData.secondDirectory = SECOND_DIRECTORY;
\r
1552 appData.bitmapDirectory = "";
\r
1553 appData.remoteShell = REMOTE_SHELL;
\r
1554 appData.remoteUser = "";
\r
1555 appData.timeDelay = TIME_DELAY;
\r
1556 appData.timeControl = TIME_CONTROL;
\r
1557 appData.timeIncrement = TIME_INCREMENT;
\r
1558 appData.icsActive = FALSE;
\r
1559 appData.icsHost = "";
\r
1560 appData.icsPort = ICS_PORT;
\r
1561 appData.icsCommPort = ICS_COMM_PORT;
\r
1562 appData.icsLogon = ICS_LOGON;
\r
1563 appData.icsHelper = "";
\r
1564 appData.useTelnet = FALSE;
\r
1565 appData.telnetProgram = TELNET_PROGRAM;
\r
1566 appData.gateway = "";
\r
1567 appData.loadGameFile = "";
\r
1568 appData.loadGameIndex = 0;
\r
1569 appData.saveGameFile = "";
\r
1570 appData.autoSaveGames = FALSE;
\r
1571 appData.loadPositionFile = "";
\r
1572 appData.loadPositionIndex = 1;
\r
1573 appData.savePositionFile = "";
\r
1574 appData.matchMode = FALSE;
\r
1575 appData.matchGames = 0;
\r
1576 appData.monoMode = FALSE;
\r
1577 appData.debugMode = FALSE;
\r
1578 appData.clockMode = TRUE;
\r
1579 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1580 appData.Iconic = FALSE; /*unused*/
\r
1581 appData.searchTime = "";
\r
1582 appData.searchDepth = 0;
\r
1583 appData.showCoords = FALSE;
\r
1584 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1585 appData.autoCallFlag = FALSE;
\r
1586 appData.flipView = FALSE;
\r
1587 appData.autoFlipView = TRUE;
\r
1588 appData.cmailGameName = "";
\r
1589 appData.alwaysPromoteToQueen = FALSE;
\r
1590 appData.oldSaveStyle = FALSE;
\r
1591 appData.quietPlay = FALSE;
\r
1592 appData.showThinking = FALSE;
\r
1593 appData.ponderNextMove = TRUE;
\r
1594 appData.periodicUpdates = TRUE;
\r
1595 appData.popupExitMessage = TRUE;
\r
1596 appData.popupMoveErrors = FALSE;
\r
1597 appData.autoObserve = FALSE;
\r
1598 appData.autoComment = FALSE;
\r
1599 appData.animate = TRUE;
\r
1600 appData.animSpeed = 10;
\r
1601 appData.animateDragging = TRUE;
\r
1602 appData.highlightLastMove = TRUE;
\r
1603 appData.getMoveList = TRUE;
\r
1604 appData.testLegality = TRUE;
\r
1605 appData.premove = TRUE;
\r
1606 appData.premoveWhite = FALSE;
\r
1607 appData.premoveWhiteText = "";
\r
1608 appData.premoveBlack = FALSE;
\r
1609 appData.premoveBlackText = "";
\r
1610 appData.icsAlarm = TRUE;
\r
1611 appData.icsAlarmTime = 5000;
\r
1612 appData.autoRaiseBoard = TRUE;
\r
1613 appData.localLineEditing = TRUE;
\r
1614 appData.colorize = TRUE;
\r
1615 appData.reuseFirst = TRUE;
\r
1616 appData.reuseSecond = TRUE;
\r
1617 appData.blindfold = FALSE;
\r
1618 dcb.DCBlength = sizeof(DCB);
\r
1619 dcb.BaudRate = 9600;
\r
1620 dcb.fBinary = TRUE;
\r
1621 dcb.fParity = FALSE;
\r
1622 dcb.fOutxCtsFlow = FALSE;
\r
1623 dcb.fOutxDsrFlow = FALSE;
\r
1624 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1625 dcb.fDsrSensitivity = FALSE;
\r
1626 dcb.fTXContinueOnXoff = TRUE;
\r
1627 dcb.fOutX = FALSE;
\r
1629 dcb.fNull = FALSE;
\r
1630 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1631 dcb.fAbortOnError = FALSE;
\r
1632 dcb.wReserved = 0;
\r
1634 dcb.Parity = SPACEPARITY;
\r
1635 dcb.StopBits = ONESTOPBIT;
\r
1636 settingsFileName = SETTINGS_FILE;
\r
1637 saveSettingsOnExit = TRUE;
\r
1638 boardX = CW_USEDEFAULT;
\r
1639 boardY = CW_USEDEFAULT;
\r
1640 consoleX = CW_USEDEFAULT;
\r
1641 consoleY = CW_USEDEFAULT;
\r
1642 consoleW = CW_USEDEFAULT;
\r
1643 consoleH = CW_USEDEFAULT;
\r
1644 analysisX = CW_USEDEFAULT;
\r
1645 analysisY = CW_USEDEFAULT;
\r
1646 analysisW = CW_USEDEFAULT;
\r
1647 analysisH = CW_USEDEFAULT;
\r
1648 commentX = CW_USEDEFAULT;
\r
1649 commentY = CW_USEDEFAULT;
\r
1650 commentW = CW_USEDEFAULT;
\r
1651 commentH = CW_USEDEFAULT;
\r
1652 editTagsX = CW_USEDEFAULT;
\r
1653 editTagsY = CW_USEDEFAULT;
\r
1654 editTagsW = CW_USEDEFAULT;
\r
1655 editTagsH = CW_USEDEFAULT;
\r
1656 gameListX = CW_USEDEFAULT;
\r
1657 gameListY = CW_USEDEFAULT;
\r
1658 gameListW = CW_USEDEFAULT;
\r
1659 gameListH = CW_USEDEFAULT;
\r
1660 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1661 icsNames = ICS_NAMES;
\r
1662 firstChessProgramNames = FCP_NAMES;
\r
1663 secondChessProgramNames = SCP_NAMES;
\r
1664 appData.initialMode = "";
\r
1665 appData.variant = "normal";
\r
1666 appData.firstProtocolVersion = PROTOVER;
\r
1667 appData.secondProtocolVersion = PROTOVER;
\r
1668 appData.showButtonBar = TRUE;
\r
1670 appData.zippyTalk = ZIPPY_TALK;
\r
1671 appData.zippyPlay = ZIPPY_PLAY;
\r
1672 appData.zippyLines = ZIPPY_LINES;
\r
1673 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1674 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1675 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1676 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1677 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1678 appData.zippyUseI = ZIPPY_USE_I;
\r
1679 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1680 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1681 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1682 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1683 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1684 appData.zippyAbort = ZIPPY_ABORT;
\r
1685 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1686 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1687 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1690 /* Point font array elements to structures and
\r
1691 parse default font names */
\r
1692 for (i=0; i<NUM_FONTS; i++) {
\r
1693 for (j=0; j<NUM_SIZES; j++) {
\r
1694 font[j][i] = &fontRec[j][i];
\r
1695 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1699 /* Parse default settings file if any */
\r
1700 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1701 settingsFileName = strdup(buf);
\r
1704 /* Parse command line */
\r
1705 ParseArgs(StringGet, &lpCmdLine);
\r
1707 /* Propagate options that affect others */
\r
1708 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1709 if (appData.icsActive || appData.noChessProgram) {
\r
1710 chessProgram = FALSE; /* not local chess program mode */
\r
1713 /* Open startup dialog if needed */
\r
1714 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1715 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1716 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1717 *appData.secondChessProgram == NULLCHAR))) {
\r
1720 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1721 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1722 FreeProcInstance(lpProc);
\r
1725 /* Make sure save files land in the right (?) directory */
\r
1726 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1727 appData.saveGameFile = strdup(buf);
\r
1729 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1730 appData.savePositionFile = strdup(buf);
\r
1733 /* Finish initialization for fonts and sounds */
\r
1734 for (i=0; i<NUM_FONTS; i++) {
\r
1735 for (j=0; j<NUM_SIZES; j++) {
\r
1736 CreateFontInMF(font[j][i]);
\r
1739 /* xboard, and older WinBoards, controlled the move sound with the
\r
1740 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1741 always turn the option on (so that the backend will call us),
\r
1742 then let the user turn the sound off by setting it to silence if
\r
1743 desired. To accommodate old winboard.ini files saved by old
\r
1744 versions of WinBoard, we also turn off the sound if the option
\r
1745 was initially set to false. */
\r
1746 if (!appData.ringBellAfterMoves) {
\r
1747 sounds[(int)SoundMove].name = strdup("");
\r
1748 appData.ringBellAfterMoves = TRUE;
\r
1750 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1751 SetCurrentDirectory(installDir);
\r
1753 SetCurrentDirectory(currDir);
\r
1755 p = icsTextMenuString;
\r
1756 if (p[0] == '@') {
\r
1757 FILE* f = fopen(p + 1, "r");
\r
1759 DisplayFatalError(p + 1, errno, 2);
\r
1762 i = fread(buf, 1, sizeof(buf)-1, f);
\r
1764 buf[i] = NULLCHAR;
\r
1767 ParseIcsTextMenu(strdup(p));
\r
1774 HMENU hmenu = GetMenu(hwndMain);
\r
1776 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1777 MF_BYCOMMAND|((appData.icsActive &&
\r
1778 *appData.icsCommPort != NULLCHAR) ?
\r
1779 MF_ENABLED : MF_GRAYED));
\r
1780 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1781 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1782 MF_CHECKED : MF_UNCHECKED));
\r
1787 SaveSettings(char* name)
\r
1790 ArgDescriptor *ad;
\r
1791 WINDOWPLACEMENT wp;
\r
1792 char dir[MSG_SIZ];
\r
1794 if (!hwndMain) return;
\r
1796 GetCurrentDirectory(MSG_SIZ, dir);
\r
1797 SetCurrentDirectory(installDir);
\r
1798 f = fopen(name, "w");
\r
1799 SetCurrentDirectory(dir);
\r
1801 DisplayError(name, errno);
\r
1804 fprintf(f, ";\n");
\r
1805 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
1806 fprintf(f, ";\n");
\r
1807 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
1808 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
1809 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
1810 fprintf(f, ";\n");
\r
1812 wp.length = sizeof(WINDOWPLACEMENT);
\r
1813 GetWindowPlacement(hwndMain, &wp);
\r
1814 boardX = wp.rcNormalPosition.left;
\r
1815 boardY = wp.rcNormalPosition.top;
\r
1817 if (hwndConsole) {
\r
1818 GetWindowPlacement(hwndConsole, &wp);
\r
1819 consoleX = wp.rcNormalPosition.left;
\r
1820 consoleY = wp.rcNormalPosition.top;
\r
1821 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1822 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1825 if (analysisDialog) {
\r
1826 GetWindowPlacement(analysisDialog, &wp);
\r
1827 analysisX = wp.rcNormalPosition.left;
\r
1828 analysisY = wp.rcNormalPosition.top;
\r
1829 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1830 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1833 if (commentDialog) {
\r
1834 GetWindowPlacement(commentDialog, &wp);
\r
1835 commentX = wp.rcNormalPosition.left;
\r
1836 commentY = wp.rcNormalPosition.top;
\r
1837 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1838 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1841 if (editTagsDialog) {
\r
1842 GetWindowPlacement(editTagsDialog, &wp);
\r
1843 editTagsX = wp.rcNormalPosition.left;
\r
1844 editTagsY = wp.rcNormalPosition.top;
\r
1845 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1846 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1849 if (gameListDialog) {
\r
1850 GetWindowPlacement(gameListDialog, &wp);
\r
1851 gameListX = wp.rcNormalPosition.left;
\r
1852 gameListY = wp.rcNormalPosition.top;
\r
1853 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1854 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1857 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
1858 if (!ad->save) continue;
\r
1859 switch (ad->argType) {
\r
1862 char *p = *(char **)ad->argLoc;
\r
1863 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
1864 /* Quote multiline values or \-containing values
\r
1865 with { } if possible */
\r
1866 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
1868 /* Else quote with " " */
\r
1869 fprintf(f, "/%s=\"", ad->argName);
\r
1871 if (*p == '\n') fprintf(f, "\n");
\r
1872 else if (*p == '\r') fprintf(f, "\\r");
\r
1873 else if (*p == '\t') fprintf(f, "\\t");
\r
1874 else if (*p == '\b') fprintf(f, "\\b");
\r
1875 else if (*p == '\f') fprintf(f, "\\f");
\r
1876 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
1877 else if (*p == '\"') fprintf(f, "\\\"");
\r
1878 else if (*p == '\\') fprintf(f, "\\\\");
\r
1882 fprintf(f, "\"\n");
\r
1887 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
1890 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
1893 fprintf(f, "/%s=%s\n", ad->argName,
\r
1894 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
1897 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1900 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1904 COLORREF color = *(COLORREF *)ad->argLoc;
\r
1905 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
1906 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1911 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1912 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
1913 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1914 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1915 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1916 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1917 (ta->effects) ? " " : "",
\r
1918 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1922 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
1923 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
1925 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
1928 case ArgBoardSize:
\r
1929 fprintf(f, "/%s=%s\n", ad->argName,
\r
1930 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
1935 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1936 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1937 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1938 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
1939 ad->argName, mfp->faceName, mfp->pointSize,
\r
1940 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1941 mfp->bold ? "b" : "",
\r
1942 mfp->italic ? "i" : "",
\r
1943 mfp->underline ? "u" : "",
\r
1944 mfp->strikeout ? "s" : "");
\r
1948 case ArgCommSettings:
\r
1949 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
1957 /*---------------------------------------------------------------------------*\
\r
1959 * GDI board drawing routines
\r
1961 \*---------------------------------------------------------------------------*/
\r
1964 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
1968 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
1969 if (gameInfo.event &&
\r
1970 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
1971 strcmp(name, "k80s") == 0) {
\r
1972 strcpy(name, "tim");
\r
1974 return LoadBitmap(hinst, name);
\r
1978 /* Insert a color into the program's logical palette
\r
1979 structure. This code assumes the given color is
\r
1980 the result of the RGB or PALETTERGB macro, and it
\r
1981 knows how those macros work (which is documented).
\r
1984 InsertInPalette(COLORREF color)
\r
1986 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
1988 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
1989 DisplayFatalError("Too many colors", 0, 1);
\r
1990 pLogPal->palNumEntries--;
\r
1994 pe->peFlags = (char) 0;
\r
1995 pe->peRed = (char) (0xFF & color);
\r
1996 pe->peGreen = (char) (0xFF & (color >> 8));
\r
1997 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2003 InitDrawingColors()
\r
2005 if (pLogPal == NULL) {
\r
2006 /* Allocate enough memory for a logical palette with
\r
2007 * PALETTESIZE entries and set the size and version fields
\r
2008 * of the logical palette structure.
\r
2010 pLogPal = (NPLOGPALETTE)
\r
2011 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2012 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2013 pLogPal->palVersion = 0x300;
\r
2015 pLogPal->palNumEntries = 0;
\r
2017 InsertInPalette(lightSquareColor);
\r
2018 InsertInPalette(darkSquareColor);
\r
2019 InsertInPalette(whitePieceColor);
\r
2020 InsertInPalette(blackPieceColor);
\r
2021 InsertInPalette(highlightSquareColor);
\r
2022 InsertInPalette(premoveHighlightColor);
\r
2024 /* create a logical color palette according the information
\r
2025 * in the LOGPALETTE structure.
\r
2027 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2029 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2030 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2031 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2032 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2033 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2038 BoardWidth(int boardSize)
\r
2040 return (BOARD_SIZE + 1) * sizeInfo[boardSize].lineGap +
\r
2041 BOARD_SIZE * sizeInfo[boardSize].squareSize;
\r
2044 /* Respond to board resize by dragging edge */
\r
2046 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2048 BoardSize newSize = NUM_SIZES - 1;
\r
2049 static int recurse = 0;
\r
2050 if (IsIconic(hwndMain)) return;
\r
2051 if (recurse > 0) return;
\r
2053 while (newSize > 0 &&
\r
2054 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2055 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2058 boardSize = newSize;
\r
2059 InitDrawingSizes(boardSize, flags);
\r
2066 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2068 int i, boardWidth;
\r
2069 ChessSquare piece;
\r
2070 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2072 SIZE clockSize, messageSize;
\r
2074 char buf[MSG_SIZ];
\r
2076 HMENU hmenu = GetMenu(hwndMain);
\r
2077 RECT crect, wrect;
\r
2079 LOGBRUSH logbrush;
\r
2081 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2082 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2083 squareSize = sizeInfo[boardSize].squareSize;
\r
2084 lineGap = sizeInfo[boardSize].lineGap;
\r
2086 if (tinyLayout != oldTinyLayout) {
\r
2087 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2089 style &= ~WS_SYSMENU;
\r
2090 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2091 "&Minimize\tCtrl+F4");
\r
2093 style |= WS_SYSMENU;
\r
2094 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2096 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2098 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2099 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2100 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2102 DrawMenuBar(hwndMain);
\r
2105 boardWidth = BoardWidth(boardSize);
\r
2107 /* Get text area sizes */
\r
2108 hdc = GetDC(hwndMain);
\r
2109 if (appData.clockMode) {
\r
2110 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2112 sprintf(buf, "White");
\r
2114 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2115 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2116 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2117 str = "We only care about the height here";
\r
2118 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2119 SelectObject(hdc, oldFont);
\r
2120 ReleaseDC(hwndMain, hdc);
\r
2122 /* Compute where everything goes */
\r
2123 whiteRect.left = OUTER_MARGIN;
\r
2124 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2125 whiteRect.top = OUTER_MARGIN;
\r
2126 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2128 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2129 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2130 blackRect.top = whiteRect.top;
\r
2131 blackRect.bottom = whiteRect.bottom;
\r
2133 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2134 if (appData.showButtonBar) {
\r
2135 messageRect.right = blackRect.right
\r
2136 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2138 messageRect.right = blackRect.right;
\r
2140 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2141 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2143 boardRect.left = whiteRect.left;
\r
2144 boardRect.right = boardRect.left + boardWidth;
\r
2145 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2146 boardRect.bottom = boardRect.top + boardWidth;
\r
2148 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2149 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2150 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2151 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2152 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2153 GetWindowRect(hwndMain, &wrect);
\r
2154 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2155 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2156 /* compensate if menu bar wrapped */
\r
2157 GetClientRect(hwndMain, &crect);
\r
2158 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2159 winHeight += offby;
\r
2161 case WMSZ_TOPLEFT:
\r
2162 SetWindowPos(hwndMain, NULL,
\r
2163 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2164 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2167 case WMSZ_TOPRIGHT:
\r
2169 SetWindowPos(hwndMain, NULL,
\r
2170 wrect.left, wrect.bottom - winHeight,
\r
2171 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2174 case WMSZ_BOTTOMLEFT:
\r
2176 SetWindowPos(hwndMain, NULL,
\r
2177 wrect.right - winWidth, wrect.top,
\r
2178 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2181 case WMSZ_BOTTOMRIGHT:
\r
2185 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2186 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2191 for (i = 0; i < N_BUTTONS; i++) {
\r
2192 if (buttonDesc[i].hwnd != NULL) {
\r
2193 DestroyWindow(buttonDesc[i].hwnd);
\r
2194 buttonDesc[i].hwnd = NULL;
\r
2196 if (appData.showButtonBar) {
\r
2197 buttonDesc[i].hwnd =
\r
2198 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2199 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2200 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2201 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2202 (HMENU) buttonDesc[i].id,
\r
2203 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2205 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2206 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2207 MAKELPARAM(FALSE, 0));
\r
2209 if (buttonDesc[i].id == IDM_Pause)
\r
2210 hwndPause = buttonDesc[i].hwnd;
\r
2211 buttonDesc[i].wndproc = (WNDPROC)
\r
2212 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2215 if (gridPen != NULL) DeleteObject(gridPen);
\r
2216 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2217 if (premovePen != NULL) DeleteObject(premovePen);
\r
2218 if (lineGap != 0) {
\r
2219 logbrush.lbStyle = BS_SOLID;
\r
2220 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2222 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2223 lineGap, &logbrush, 0, NULL);
\r
2224 logbrush.lbColor = highlightSquareColor;
\r
2226 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2227 lineGap, &logbrush, 0, NULL);
\r
2229 logbrush.lbColor = premoveHighlightColor;
\r
2231 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2232 lineGap, &logbrush, 0, NULL);
\r
2234 for (i = 0; i < BOARD_SIZE + 1; i++) {
\r
2235 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2236 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2;
\r
2237 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2238 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2239 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2240 BOARD_SIZE * (squareSize + lineGap);
\r
2241 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x =
\r
2242 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left +
\r
2243 lineGap / 2 + (i * (squareSize + lineGap));
\r
2244 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y =
\r
2245 boardRect.top + BOARD_SIZE * (squareSize + lineGap);
\r
2246 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2250 if (boardSize == oldBoardSize) return;
\r
2251 oldBoardSize = boardSize;
\r
2252 oldTinyLayout = tinyLayout;
\r
2254 /* Load piece bitmaps for this board size */
\r
2255 for (i=0; i<=2; i++) {
\r
2256 for (piece = WhitePawn;
\r
2257 (int) piece <= (int) WhiteKing;
\r
2258 piece = (ChessSquare) ((int) piece + 1)) {
\r
2259 if (pieceBitmap[i][piece] != NULL)
\r
2260 DeleteObject(pieceBitmap[i][piece]);
\r
2264 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2265 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2266 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2267 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2268 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2269 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2270 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2271 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2272 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2273 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2274 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2275 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2276 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2277 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2278 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2279 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2280 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2281 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2286 PieceBitmap(ChessSquare p, int kind)
\r
2288 if ((int) p >= (int) BlackPawn)
\r
2289 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2291 return pieceBitmap[kind][(int) p];
\r
2294 /***************************************************************/
\r
2296 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2297 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2299 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2300 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2304 SquareToPos(int row, int column, int * x, int * y)
\r
2307 *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
2308 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2310 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2311 *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
2316 DrawCoordsOnDC(HDC hdc)
\r
2318 static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'};
\r
2319 static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'};
\r
2320 char str[2] = { NULLCHAR, NULLCHAR };
\r
2321 int oldMode, oldAlign, x, y, start, i;
\r
2325 if (!appData.showCoords)
\r
2328 start = flipView ? 0 : 8;
\r
2330 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2331 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2332 oldAlign = GetTextAlign(hdc);
\r
2333 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2335 y = boardRect.top + lineGap;
\r
2336 x = boardRect.left + lineGap;
\r
2338 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2339 for (i = 0; i < 8; i++) {
\r
2340 str[0] = files[start + i];
\r
2341 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2342 y += squareSize + lineGap;
\r
2345 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2346 for (i = 0; i < 8; i++) {
\r
2347 str[0] = ranks[start + i];
\r
2348 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2349 x += squareSize + lineGap;
\r
2352 SelectObject(hdc, oldBrush);
\r
2353 SetBkMode(hdc, oldMode);
\r
2354 SetTextAlign(hdc, oldAlign);
\r
2355 SelectObject(hdc, oldFont);
\r
2359 DrawGridOnDC(HDC hdc)
\r
2363 if (lineGap != 0) {
\r
2364 oldPen = SelectObject(hdc, gridPen);
\r
2365 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2);
\r
2366 SelectObject(hdc, oldPen);
\r
2370 #define HIGHLIGHT_PEN 0
\r
2371 #define PREMOVE_PEN 1
\r
2374 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2377 HPEN oldPen, hPen;
\r
2378 if (lineGap == 0) return;
\r
2380 x1 = boardRect.left +
\r
2381 lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap);
\r
2382 y1 = boardRect.top +
\r
2383 lineGap/2 + y * (squareSize + lineGap);
\r
2385 x1 = boardRect.left +
\r
2386 lineGap/2 + x * (squareSize + lineGap);
\r
2387 y1 = boardRect.top +
\r
2388 lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap);
\r
2390 hPen = pen ? premovePen : highlightPen;
\r
2391 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2392 MoveToEx(hdc, x1, y1, NULL);
\r
2393 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2394 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2395 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2396 LineTo(hdc, x1, y1);
\r
2397 SelectObject(hdc, oldPen);
\r
2401 DrawHighlightsOnDC(HDC hdc)
\r
2404 for (i=0; i<2; i++) {
\r
2405 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
2406 DrawHighlightOnDC(hdc, TRUE,
\r
2407 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
2410 for (i=0; i<2; i++) {
\r
2411 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2412 premoveHighlightInfo.sq[i].y >= 0) {
\r
2413 DrawHighlightOnDC(hdc, TRUE,
\r
2414 premoveHighlightInfo.sq[i].x,
\r
2415 premoveHighlightInfo.sq[i].y,
\r
2421 /* Note: sqcolor is used only in monoMode */
\r
2422 /* Note that this code is largely duplicated in woptions.c,
\r
2423 function DrawSampleSquare, so that needs to be updated too */
\r
2425 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2427 HBITMAP oldBitmap;
\r
2430 if (appData.blindfold) return;
\r
2432 if (appData.monoMode) {
\r
2433 SelectObject(tmphdc, PieceBitmap(piece,
\r
2434 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2435 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2436 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2439 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2440 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2441 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2443 /* Use black piece color for outline of white pieces */
\r
2444 /* Not sure this looks really good (though xboard does it).
\r
2445 Maybe better to have another selectable color, default black */
\r
2446 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
2447 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2448 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2450 /* Use black for outline of white pieces */
\r
2451 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2452 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
2456 /* Use white piece color for details of black pieces */
\r
2457 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
2458 WHITE_PIECE ones aren't always the right shape. */
\r
2459 /* Not sure this looks really good (though xboard does it).
\r
2460 Maybe better to have another selectable color, default medium gray? */
\r
2461 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
2462 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
2463 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2464 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2465 SelectObject(hdc, blackPieceBrush);
\r
2466 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2468 /* Use square color for details of black pieces */
\r
2469 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2470 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2471 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2474 SelectObject(hdc, oldBrush);
\r
2475 SelectObject(tmphdc, oldBitmap);
\r
2480 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
2482 int row, column, x, y, square_color, piece_color;
\r
2483 ChessSquare piece;
\r
2486 for (row = 0; row < BOARD_SIZE; row++) {
\r
2487 for (column = 0; column < BOARD_SIZE; column++) {
\r
2489 SquareToPos(row, column, &x, &y);
\r
2491 piece = board[row][column];
\r
2493 square_color = ((column + row) % 2) == 1;
\r
2494 piece_color = (int) piece < (int) BlackPawn;
\r
2496 if (appData.monoMode) {
\r
2497 if (piece == EmptySquare) {
\r
2498 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
2499 square_color ? WHITENESS : BLACKNESS);
\r
2501 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
2504 oldBrush = SelectObject(hdc, square_color ?
\r
2505 lightSquareBrush : darkSquareBrush);
\r
2506 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
2507 SelectObject(hdc, oldBrush);
\r
2508 if (piece != EmptySquare)
\r
2509 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
2515 #define MAX_CLIPS 200 /* more than enough */
\r
2518 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
2520 static Board lastReq, lastDrawn;
\r
2521 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
2522 static int lastDrawnFlipView = 0;
\r
2523 static int lastReqValid = 0, lastDrawnValid = 0;
\r
2524 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
2527 HBITMAP bufferBitmap;
\r
2528 HBITMAP oldBitmap;
\r
2530 HRGN clips[MAX_CLIPS];
\r
2531 ChessSquare dragged_piece = EmptySquare;
\r
2533 /* I'm undecided on this - this function figures out whether a full
\r
2534 * repaint is necessary on its own, so there's no real reason to have the
\r
2535 * caller tell it that. I think this can safely be set to FALSE - but
\r
2536 * if we trust the callers not to request full repaints unnessesarily, then
\r
2537 * we could skip some clipping work. In other words, only request a full
\r
2538 * redraw when the majority of pieces have changed positions (ie. flip,
\r
2539 * gamestart and similar) --Hawk
\r
2541 Boolean fullrepaint = repaint;
\r
2543 if (board == NULL) {
\r
2544 if (!lastReqValid) {
\r
2549 CopyBoard(lastReq, board);
\r
2553 if (doingSizing) {
\r
2557 if (IsIconic(hwndMain)) {
\r
2561 if (hdc == NULL) {
\r
2562 hdc = GetDC(hwndMain);
\r
2563 if (!appData.monoMode) {
\r
2564 SelectPalette(hdc, hPal, FALSE);
\r
2565 RealizePalette(hdc);
\r
2569 releaseDC = FALSE;
\r
2573 fprintf(debugFP, "*******************************\n"
\r
2575 "dragInfo.from (%d,%d)\n"
\r
2576 "dragInfo.start (%d,%d)\n"
\r
2577 "dragInfo.pos (%d,%d)\n"
\r
2578 "dragInfo.lastpos (%d,%d)\n",
\r
2579 repaint ? "TRUE" : "FALSE",
\r
2580 dragInfo.from.x, dragInfo.from.y,
\r
2581 dragInfo.start.x, dragInfo.start.y,
\r
2582 dragInfo.pos.x, dragInfo.pos.y,
\r
2583 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
2584 fprintf(debugFP, "prev: ");
\r
2585 for (row = 0; row < 8; row++) {
\r
2586 for (column = 0; column < 8; column++) {
\r
2587 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
2590 fprintf(debugFP, "\n");
\r
2591 fprintf(debugFP, "board: ");
\r
2592 for (row = 0; row < 8; row++) {
\r
2593 for (column = 0; column < 8; column++) {
\r
2594 fprintf(debugFP, "%d ", board[row][column]);
\r
2597 fprintf(debugFP, "\n");
\r
2601 /* Create some work-DCs */
\r
2602 hdcmem = CreateCompatibleDC(hdc);
\r
2603 tmphdc = CreateCompatibleDC(hdc);
\r
2605 /* Figure out which squares need updating by comparing the
\r
2606 * newest board with the last drawn board and checking if
\r
2607 * flipping has changed.
\r
2609 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
2610 for (row = 0; row < 8; row++) {
\r
2611 for (column = 0; column < 8; column++) {
\r
2612 if (lastDrawn[row][column] != board[row][column]) {
\r
2613 SquareToPos(row, column, &x, &y);
\r
2614 clips[num_clips++] =
\r
2615 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
2619 for (i=0; i<2; i++) {
\r
2620 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
2621 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
2622 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
2623 lastDrawnHighlight.sq[i].y >= 0) {
\r
2624 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
2625 lastDrawnHighlight.sq[i].x, &x, &y);
\r
2626 clips[num_clips++] =
\r
2627 CreateRectRgn(x - lineGap, y - lineGap,
\r
2628 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2630 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
2631 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
2632 clips[num_clips++] =
\r
2633 CreateRectRgn(x - lineGap, y - lineGap,
\r
2634 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2638 for (i=0; i<2; i++) {
\r
2639 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
2640 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
2641 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
2642 lastDrawnPremove.sq[i].y >= 0) {
\r
2643 SquareToPos(lastDrawnPremove.sq[i].y,
\r
2644 lastDrawnPremove.sq[i].x, &x, &y);
\r
2645 clips[num_clips++] =
\r
2646 CreateRectRgn(x - lineGap, y - lineGap,
\r
2647 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2649 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2650 premoveHighlightInfo.sq[i].y >= 0) {
\r
2651 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
2652 premoveHighlightInfo.sq[i].x, &x, &y);
\r
2653 clips[num_clips++] =
\r
2654 CreateRectRgn(x - lineGap, y - lineGap,
\r
2655 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2660 fullrepaint = TRUE;
\r
2663 /* Create a buffer bitmap - this is the actual bitmap
\r
2664 * being written to. When all the work is done, we can
\r
2665 * copy it to the real DC (the screen). This avoids
\r
2666 * the problems with flickering.
\r
2668 GetClientRect(hwndMain, &Rect);
\r
2669 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
2670 Rect.bottom-Rect.top+1);
\r
2671 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
2672 if (!appData.monoMode) {
\r
2673 SelectPalette(hdcmem, hPal, FALSE);
\r
2676 /* Create clips for dragging */
\r
2677 if (!fullrepaint) {
\r
2678 if (dragInfo.from.x >= 0) {
\r
2679 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
2680 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2682 if (dragInfo.start.x >= 0) {
\r
2683 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
2684 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2686 if (dragInfo.pos.x >= 0) {
\r
2687 x = dragInfo.pos.x - squareSize / 2;
\r
2688 y = dragInfo.pos.y - squareSize / 2;
\r
2689 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2691 if (dragInfo.lastpos.x >= 0) {
\r
2692 x = dragInfo.lastpos.x - squareSize / 2;
\r
2693 y = dragInfo.lastpos.y - squareSize / 2;
\r
2694 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2698 /* If dragging is in progress, we temporarely remove the piece */
\r
2699 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
2700 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
2701 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
2704 /* Are we animating a move?
\r
2706 * - remove the piece from the board (temporarely)
\r
2707 * - calculate the clipping region
\r
2709 if (!fullrepaint) {
\r
2710 if (animInfo.piece != EmptySquare) {
\r
2711 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
2712 x = boardRect.left + animInfo.lastpos.x;
\r
2713 y = boardRect.top + animInfo.lastpos.y;
\r
2714 x2 = boardRect.left + animInfo.pos.x;
\r
2715 y2 = boardRect.top + animInfo.pos.y;
\r
2716 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
2717 /* Slight kludge. The real problem is that after AnimateMove is
\r
2718 done, the position on the screen does not match lastDrawn.
\r
2719 This currently causes trouble only on e.p. captures in
\r
2720 atomic, where the piece moves to an empty square and then
\r
2721 explodes. The old and new positions both had an empty square
\r
2722 at the destination, but animation has drawn a piece there and
\r
2723 we have to remember to erase it. */
\r
2724 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
2728 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
2729 if (num_clips == 0)
\r
2730 fullrepaint = TRUE;
\r
2732 /* Set clipping on the memory DC */
\r
2733 if (!fullrepaint) {
\r
2734 SelectClipRgn(hdcmem, clips[0]);
\r
2735 for (x = 1; x < num_clips; x++) {
\r
2736 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
2737 abort(); // this should never ever happen!
\r
2741 /* Do all the drawing to the memory DC */
\r
2742 DrawGridOnDC(hdcmem);
\r
2743 DrawHighlightsOnDC(hdcmem);
\r
2744 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
2745 DrawCoordsOnDC(hdcmem);
\r
2747 /* Put the dragged piece back into place and draw it */
\r
2748 if (dragged_piece != EmptySquare) {
\r
2749 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
2750 x = dragInfo.pos.x - squareSize / 2;
\r
2751 y = dragInfo.pos.y - squareSize / 2;
\r
2752 DrawPieceOnDC(hdcmem, dragged_piece,
\r
2753 ((int) dragged_piece < (int) BlackPawn),
\r
2754 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
2757 /* Put the animated piece back into place and draw it */
\r
2758 if (animInfo.piece != EmptySquare) {
\r
2759 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
2760 x = boardRect.left + animInfo.pos.x;
\r
2761 y = boardRect.top + animInfo.pos.y;
\r
2762 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
2763 ((int) animInfo.piece < (int) BlackPawn),
\r
2764 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
2767 /* Release the bufferBitmap by selecting in the old bitmap
\r
2768 * and delete the memory DC
\r
2770 SelectObject(hdcmem, oldBitmap);
\r
2773 /* Set clipping on the target DC */
\r
2774 if (!fullrepaint) {
\r
2775 SelectClipRgn(hdc, clips[0]);
\r
2776 for (x = 1; x < num_clips; x++) {
\r
2777 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
2778 abort(); // this should never ever happen!
\r
2782 /* Copy the new bitmap onto the screen in one go.
\r
2783 * This way we avoid any flickering
\r
2785 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
2786 BitBlt(hdc, boardRect.left, boardRect.top,
\r
2787 boardRect.right - boardRect.left,
\r
2788 boardRect.bottom - boardRect.top,
\r
2789 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
2790 SelectObject(tmphdc, oldBitmap);
\r
2792 /* Massive cleanup */
\r
2793 for (x = 0; x < num_clips; x++)
\r
2794 DeleteObject(clips[x]);
\r
2797 DeleteObject(bufferBitmap);
\r
2800 ReleaseDC(hwndMain, hdc);
\r
2802 if (lastDrawnFlipView != flipView) {
\r
2804 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
2806 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
2809 CopyBoard(lastDrawn, board);
\r
2810 lastDrawnHighlight = highlightInfo;
\r
2811 lastDrawnPremove = premoveHighlightInfo;
\r
2812 lastDrawnFlipView = flipView;
\r
2813 lastDrawnValid = 1;
\r
2817 /*---------------------------------------------------------------------------*\
\r
2818 | CLIENT PAINT PROCEDURE
\r
2819 | This is the main event-handler for the WM_PAINT message.
\r
2821 \*---------------------------------------------------------------------------*/
\r
2823 PaintProc(HWND hwnd)
\r
2829 if(hdc = BeginPaint(hwnd, &ps)) {
\r
2830 if (IsIconic(hwnd)) {
\r
2831 DrawIcon(hdc, 2, 2, iconCurrent);
\r
2833 if (!appData.monoMode) {
\r
2834 SelectPalette(hdc, hPal, FALSE);
\r
2835 RealizePalette(hdc);
\r
2837 HDCDrawPosition(hdc, 1, NULL);
\r
2839 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2840 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
2841 ETO_CLIPPED|ETO_OPAQUE,
\r
2842 &messageRect, messageText, strlen(messageText), NULL);
\r
2843 SelectObject(hdc, oldFont);
\r
2844 DisplayBothClocks();
\r
2846 EndPaint(hwnd,&ps);
\r
2854 * If the user selects on a border boundary, return -1; if off the board,
\r
2855 * return -2. Otherwise map the event coordinate to the square.
\r
2856 * The offset boardRect.left or boardRect.top must already have been
\r
2857 * subtracted from x.
\r
2860 EventToSquare(int x)
\r
2867 if ((x % (squareSize + lineGap)) >= squareSize)
\r
2869 x /= (squareSize + lineGap);
\r
2870 if (x >= BOARD_SIZE)
\r
2881 DropEnable dropEnables[] = {
\r
2882 { 'P', DP_Pawn, "Pawn" },
\r
2883 { 'N', DP_Knight, "Knight" },
\r
2884 { 'B', DP_Bishop, "Bishop" },
\r
2885 { 'R', DP_Rook, "Rook" },
\r
2886 { 'Q', DP_Queen, "Queen" },
\r
2890 SetupDropMenu(HMENU hmenu)
\r
2892 int i, count, enable;
\r
2894 extern char white_holding[], black_holding[];
\r
2895 char item[MSG_SIZ];
\r
2897 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
2898 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
2899 dropEnables[i].piece);
\r
2901 while (p && *p++ == dropEnables[i].piece) count++;
\r
2902 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
2903 enable = count > 0 || !appData.testLegality
\r
2904 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
2905 && !appData.icsActive);
\r
2906 ModifyMenu(hmenu, dropEnables[i].command,
\r
2907 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
2908 dropEnables[i].command, item);
\r
2912 static int fromX = -1, fromY = -1, toX, toY;
\r
2914 /* Event handler for mouse messages */
\r
2916 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
2920 static int recursive = 0;
\r
2922 BOOLEAN saveAnimate;
\r
2923 static BOOLEAN sameAgain = FALSE;
\r
2926 if (message == WM_MBUTTONUP) {
\r
2927 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
2928 to the middle button: we simulate pressing the left button too!
\r
2930 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
2931 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
2937 pt.x = LOWORD(lParam);
\r
2938 pt.y = HIWORD(lParam);
\r
2939 x = EventToSquare(pt.x - boardRect.left);
\r
2940 y = EventToSquare(pt.y - boardRect.top);
\r
2941 if (!flipView && y >= 0) {
\r
2942 y = BOARD_SIZE - 1 - y;
\r
2944 if (flipView && x >= 0) {
\r
2945 x = BOARD_SIZE - 1 - x;
\r
2948 switch (message) {
\r
2949 case WM_LBUTTONDOWN:
\r
2951 sameAgain = FALSE;
\r
2953 /* Downclick vertically off board; check if on clock */
\r
2954 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
2955 if (gameMode == EditPosition) {
\r
2956 SetWhiteToPlayEvent();
\r
2957 } else if (gameMode == IcsPlayingBlack ||
\r
2958 gameMode == MachinePlaysWhite) {
\r
2961 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
2962 if (gameMode == EditPosition) {
\r
2963 SetBlackToPlayEvent();
\r
2964 } else if (gameMode == IcsPlayingWhite ||
\r
2965 gameMode == MachinePlaysBlack) {
\r
2969 if (!appData.highlightLastMove) {
\r
2970 ClearHighlights();
\r
2971 DrawPosition(FALSE, NULL);
\r
2973 fromX = fromY = -1;
\r
2974 dragInfo.start.x = dragInfo.start.y = -1;
\r
2975 dragInfo.from = dragInfo.start;
\r
2977 } else if (x < 0 || y < 0) {
\r
2979 } else if (fromX == x && fromY == y) {
\r
2980 /* Downclick on same square again */
\r
2981 ClearHighlights();
\r
2982 DrawPosition(FALSE, NULL);
\r
2983 sameAgain = TRUE;
\r
2984 } else if (fromX != -1) {
\r
2985 /* Downclick on different square */
\r
2986 ChessSquare pdown, pup;
\r
2987 pdown = boards[currentMove][fromY][fromX];
\r
2988 pup = boards[currentMove][y][x];
\r
2989 if (gameMode == EditPosition ||
\r
2990 !((WhitePawn <= pdown && pdown <= WhiteKing &&
\r
2991 WhitePawn <= pup && pup <= WhiteKing) ||
\r
2992 (BlackPawn <= pdown && pdown <= BlackKing &&
\r
2993 BlackPawn <= pup && pup <= BlackKing))) {
\r
2994 /* EditPosition, empty square, or different color piece;
\r
2995 click-click move is possible */
\r
2998 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
2999 if (appData.alwaysPromoteToQueen) {
\r
3000 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3001 if (!appData.highlightLastMove) {
\r
3002 ClearHighlights();
\r
3003 DrawPosition(FALSE, NULL);
\r
3006 SetHighlights(fromX, fromY, toX, toY);
\r
3007 DrawPosition(FALSE, NULL);
\r
3008 PromotionPopup(hwnd);
\r
3010 } else { /* not a promotion */
\r
3011 if (appData.animate || appData.highlightLastMove) {
\r
3012 SetHighlights(fromX, fromY, toX, toY);
\r
3014 ClearHighlights();
\r
3016 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3017 if (appData.animate && !appData.highlightLastMove) {
\r
3018 ClearHighlights();
\r
3019 DrawPosition(FALSE, NULL);
\r
3022 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3023 fromX = fromY = -1;
\r
3026 ClearHighlights();
\r
3027 DrawPosition(FALSE, NULL);
\r
3029 /* First downclick, or restart on a square with same color piece */
\r
3030 if (!frozen && OKToStartUserMove(x, y)) {
\r
3033 dragInfo.lastpos = pt;
\r
3034 dragInfo.from.x = fromX;
\r
3035 dragInfo.from.y = fromY;
\r
3036 dragInfo.start = dragInfo.from;
\r
3037 SetCapture(hwndMain);
\r
3039 fromX = fromY = -1;
\r
3040 dragInfo.start.x = dragInfo.start.y = -1;
\r
3041 dragInfo.from = dragInfo.start;
\r
3045 case WM_LBUTTONUP:
\r
3047 if (fromX == -1) break;
\r
3048 if (x == fromX && y == fromY) {
\r
3049 dragInfo.from.x = dragInfo.from.y = -1;
\r
3050 /* Upclick on same square */
\r
3052 /* Clicked same square twice: abort click-click move */
\r
3053 fromX = fromY = -1;
\r
3055 ClearPremoveHighlights();
\r
3057 /* First square clicked: start click-click move */
\r
3058 SetHighlights(fromX, fromY, -1, -1);
\r
3060 DrawPosition(FALSE, NULL);
\r
3061 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
3062 /* Errant click; ignore */
\r
3065 /* Finish drag move */
\r
3066 dragInfo.from.x = dragInfo.from.y = -1;
\r
3069 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
3070 appData.animate = appData.animate && !appData.animateDragging;
\r
3071 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
3072 if (appData.alwaysPromoteToQueen) {
\r
3073 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3075 DrawPosition(FALSE, NULL);
\r
3076 PromotionPopup(hwnd);
\r
3079 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3081 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3082 appData.animate = saveAnimate;
\r
3083 fromX = fromY = -1;
\r
3084 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
3085 ClearHighlights();
\r
3087 if (appData.animate || appData.animateDragging ||
\r
3088 appData.highlightDragging || gotPremove) {
\r
3089 DrawPosition(FALSE, NULL);
\r
3092 dragInfo.start.x = dragInfo.start.y = -1;
\r
3093 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
3096 case WM_MOUSEMOVE:
\r
3097 if ((appData.animateDragging || appData.highlightDragging)
\r
3098 && (wParam & MK_LBUTTON)
\r
3099 && dragInfo.from.x >= 0) {
\r
3100 if (appData.animateDragging) {
\r
3101 dragInfo.pos = pt;
\r
3103 if (appData.highlightDragging) {
\r
3104 SetHighlights(fromX, fromY, x, y);
\r
3106 DrawPosition(FALSE, NULL);
\r
3107 dragInfo.lastpos = dragInfo.pos;
\r
3111 case WM_MBUTTONDOWN:
\r
3112 case WM_RBUTTONDOWN:
\r
3115 fromX = fromY = -1;
\r
3116 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
3117 dragInfo.start.x = dragInfo.start.y = -1;
\r
3118 dragInfo.from = dragInfo.start;
\r
3119 dragInfo.lastpos = dragInfo.pos;
\r
3120 if (appData.highlightDragging) {
\r
3121 ClearHighlights();
\r
3123 DrawPosition(TRUE, NULL);
\r
3125 switch (gameMode) {
\r
3126 case EditPosition:
\r
3127 case IcsExamining:
\r
3128 if (x < 0 || y < 0) break;
\r
3131 if (message == WM_MBUTTONDOWN) {
\r
3132 buttonCount = 3; /* even if system didn't think so */
\r
3133 if (wParam & MK_SHIFT)
\r
3134 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3136 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3137 } else { /* message == WM_RBUTTONDOWN */
\r
3139 if (buttonCount == 3) {
\r
3140 if (wParam & MK_SHIFT)
\r
3141 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3143 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3145 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3148 /* Just have one menu, on the right button. Windows users don't
\r
3149 think to try the middle one, and sometimes other software steals
\r
3150 it, or it doesn't really exist. */
\r
3151 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3155 case IcsPlayingWhite:
\r
3156 case IcsPlayingBlack:
\r
3158 case MachinePlaysWhite:
\r
3159 case MachinePlaysBlack:
\r
3160 if (appData.testLegality &&
\r
3161 gameInfo.variant != VariantBughouse &&
\r
3162 gameInfo.variant != VariantCrazyhouse) break;
\r
3163 if (x < 0 || y < 0) break;
\r
3166 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
3167 SetupDropMenu(hmenu);
\r
3168 MenuPopup(hwnd, pt, hmenu, -1);
\r
3179 /* Preprocess messages for buttons in main window */
\r
3181 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3183 int id = GetWindowLong(hwnd, GWL_ID);
\r
3186 for (i=0; i<N_BUTTONS; i++) {
\r
3187 if (buttonDesc[i].id == id) break;
\r
3189 if (i == N_BUTTONS) return 0;
\r
3190 switch (message) {
\r
3195 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
3196 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
3203 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
3206 if (appData.icsActive) {
\r
3207 if (GetKeyState(VK_SHIFT) < 0) {
\r
3209 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3210 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3214 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3215 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3222 if (appData.icsActive) {
\r
3223 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3224 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3226 SendMessage(h, WM_CHAR, wParam, lParam);
\r
3228 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
3229 PopUpMoveDialog((char)wParam);
\r
3235 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
3238 /* Process messages for Promotion dialog box */
\r
3240 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
3244 switch (message) {
\r
3245 case WM_INITDIALOG: /* message: initialize dialog box */
\r
3246 /* Center the dialog over the application window */
\r
3247 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
3248 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
3249 (!appData.testLegality || gameInfo.variant == VariantSuicide) ?
\r
3250 SW_SHOW : SW_HIDE);
\r
3253 case WM_COMMAND: /* message: received a command */
\r
3254 switch (LOWORD(wParam)) {
\r
3256 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3257 ClearHighlights();
\r
3258 DrawPosition(FALSE, NULL);
\r
3278 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3279 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
3280 if (!appData.highlightLastMove) {
\r
3281 ClearHighlights();
\r
3282 DrawPosition(FALSE, NULL);
\r
3289 /* Pop up promotion dialog */
\r
3291 PromotionPopup(HWND hwnd)
\r
3295 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
3296 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
3297 hwnd, (DLGPROC)lpProc);
\r
3298 FreeProcInstance(lpProc);
\r
3301 /* Toggle ShowThinking */
\r
3303 ToggleShowThinking()
\r
3305 ShowThinkingEvent(!appData.showThinking);
\r
3309 LoadGameDialog(HWND hwnd, char* title)
\r
3313 char fileTitle[MSG_SIZ];
\r
3314 f = OpenFileDialog(hwnd, FALSE, "",
\r
3315 appData.oldSaveStyle ? "gam" : "pgn",
\r
3317 title, &number, fileTitle, NULL);
\r
3319 cmailMsgLoaded = FALSE;
\r
3320 if (number == 0) {
\r
3321 int error = GameListBuild(f);
\r
3323 DisplayError("Cannot build game list", error);
\r
3324 } else if (!ListEmpty(&gameList) &&
\r
3325 ((ListGame *) gameList.tailPred)->number > 1) {
\r
3326 GameListPopUp(f, fileTitle);
\r
3329 GameListDestroy();
\r
3332 LoadGame(f, number, fileTitle, FALSE);
\r
3337 ChangedConsoleFont()
\r
3340 CHARRANGE tmpsel, sel;
\r
3341 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
3342 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3343 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3346 cfmt.cbSize = sizeof(CHARFORMAT);
\r
3347 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
3348 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
3349 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
3350 * size. This was undocumented in the version of MSVC++ that I had
\r
3351 * when I wrote the code, but is apparently documented now.
\r
3353 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
3354 cfmt.bCharSet = f->lf.lfCharSet;
\r
3355 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
3356 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
3357 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
3358 /* Why are the following seemingly needed too? */
\r
3359 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
3360 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
3361 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
3363 tmpsel.cpMax = -1; /*999999?*/
\r
3364 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
3365 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
3366 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
3367 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
3369 paraf.cbSize = sizeof(paraf);
\r
3370 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
3371 paraf.dxStartIndent = 0;
\r
3372 paraf.dxOffset = WRAP_INDENT;
\r
3373 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
3374 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
3377 /*---------------------------------------------------------------------------*\
\r
3379 * Window Proc for main window
\r
3381 \*---------------------------------------------------------------------------*/
\r
3383 /* Process messages for main window, etc. */
\r
3385 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3388 int wmId, wmEvent;
\r
3392 char fileTitle[MSG_SIZ];
\r
3394 switch (message) {
\r
3396 case WM_PAINT: /* message: repaint portion of window */
\r
3400 case WM_ERASEBKGND:
\r
3401 if (IsIconic(hwnd)) {
\r
3402 /* Cheat; change the message */
\r
3403 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
3405 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
3409 case WM_LBUTTONDOWN:
\r
3410 case WM_MBUTTONDOWN:
\r
3411 case WM_RBUTTONDOWN:
\r
3412 case WM_LBUTTONUP:
\r
3413 case WM_MBUTTONUP:
\r
3414 case WM_RBUTTONUP:
\r
3415 case WM_MOUSEMOVE:
\r
3416 MouseEvent(hwnd, message, wParam, lParam);
\r
3421 if (appData.icsActive) {
\r
3422 if (wParam == '\t') {
\r
3423 if (GetKeyState(VK_SHIFT) < 0) {
\r
3425 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3426 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3430 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3431 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3435 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3436 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3438 SendMessage(h, message, wParam, lParam);
\r
3440 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
3441 PopUpMoveDialog((char)wParam);
\r
3445 case WM_PALETTECHANGED:
\r
3446 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
3448 HDC hdc = GetDC(hwndMain);
\r
3449 SelectPalette(hdc, hPal, TRUE);
\r
3450 nnew = RealizePalette(hdc);
\r
3452 paletteChanged = TRUE;
\r
3454 UpdateColors(hdc);
\r
3456 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
3459 ReleaseDC(hwnd, hdc);
\r
3463 case WM_QUERYNEWPALETTE:
\r
3464 if (!appData.monoMode /*&& paletteChanged*/) {
\r
3466 HDC hdc = GetDC(hwndMain);
\r
3467 paletteChanged = FALSE;
\r
3468 SelectPalette(hdc, hPal, FALSE);
\r
3469 nnew = RealizePalette(hdc);
\r
3471 InvalidateRect(hwnd, &boardRect, FALSE);
\r
3473 ReleaseDC(hwnd, hdc);
\r
3478 case WM_COMMAND: /* message: command from application menu */
\r
3479 wmId = LOWORD(wParam);
\r
3480 wmEvent = HIWORD(wParam);
\r
3485 AnalysisPopDown();
\r
3488 case IDM_LoadGame:
\r
3489 LoadGameDialog(hwnd, "Load Game from File");
\r
3492 case IDM_LoadNextGame:
\r
3496 case IDM_LoadPrevGame:
\r
3500 case IDM_ReloadGame:
\r
3504 case IDM_LoadPosition:
\r
3505 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
3506 Reset(FALSE, TRUE);
\r
3509 f = OpenFileDialog(hwnd, FALSE, "",
\r
3510 appData.oldSaveStyle ? "pos" : "fen",
\r
3512 "Load Position from File", &number, fileTitle, NULL);
\r
3514 LoadPosition(f, number, fileTitle);
\r
3518 case IDM_LoadNextPosition:
\r
3519 ReloadPosition(1);
\r
3522 case IDM_LoadPrevPosition:
\r
3523 ReloadPosition(-1);
\r
3526 case IDM_ReloadPosition:
\r
3527 ReloadPosition(0);
\r
3530 case IDM_SaveGame:
\r
3531 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
3532 f = OpenFileDialog(hwnd, TRUE, defName,
\r
3533 appData.oldSaveStyle ? "gam" : "pgn",
\r
3535 "Save Game to File", NULL, fileTitle, NULL);
\r
3537 SaveGame(f, 0, "");
\r
3541 case IDM_SavePosition:
\r
3542 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
3543 f = OpenFileDialog(hwnd, TRUE, defName,
\r
3544 appData.oldSaveStyle ? "pos" : "fen",
\r
3546 "Save Position to File", NULL, fileTitle, NULL);
\r
3548 SavePosition(f, 0, "");
\r
3552 case IDM_CopyGame:
\r
3553 CopyGameToClipboard();
\r
3556 case IDM_PasteGame:
\r
3557 PasteGameFromClipboard();
\r
3560 case IDM_CopyPosition:
\r
3561 CopyFENToClipboard();
\r
3564 case IDM_PastePosition:
\r
3565 PasteFENFromClipboard();
\r
3568 case IDM_MailMove:
\r
3572 case IDM_ReloadCMailMsg:
\r
3573 Reset(TRUE, TRUE);
\r
3574 ReloadCmailMsgEvent(FALSE);
\r
3577 case IDM_Minimize:
\r
3578 ShowWindow(hwnd, SW_MINIMIZE);
\r
3585 case IDM_MachineWhite:
\r
3586 MachineWhiteEvent();
\r
3588 * refresh the tags dialog only if it's visible
\r
3590 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
3592 tags = PGNTags(&gameInfo);
\r
3593 TagsPopUp(tags, CmailMsg());
\r
3598 case IDM_MachineBlack:
\r
3599 MachineBlackEvent();
\r
3601 * refresh the tags dialog only if it's visible
\r
3603 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
3605 tags = PGNTags(&gameInfo);
\r
3606 TagsPopUp(tags, CmailMsg());
\r
3611 case IDM_TwoMachines:
\r
3612 TwoMachinesEvent();
\r
3614 * refresh the tags dialog only if it's visible
\r
3616 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
3618 tags = PGNTags(&gameInfo);
\r
3619 TagsPopUp(tags, CmailMsg());
\r
3624 case IDM_AnalysisMode:
\r
3625 if (!first.analysisSupport) {
\r
3626 char buf[MSG_SIZ];
\r
3627 sprintf(buf, "%s does not support analysis", first.tidy);
\r
3628 DisplayError(buf, 0);
\r
3630 if (!appData.showThinking) ToggleShowThinking();
\r
3631 AnalyzeModeEvent();
\r
3635 case IDM_AnalyzeFile:
\r
3636 if (!first.analysisSupport) {
\r
3637 char buf[MSG_SIZ];
\r
3638 sprintf(buf, "%s does not support analysis", first.tidy);
\r
3639 DisplayError(buf, 0);
\r
3641 if (!appData.showThinking) ToggleShowThinking();
\r
3642 AnalyzeFileEvent();
\r
3643 LoadGameDialog(hwnd, "Analyze Game from File");
\r
3644 AnalysisPeriodicEvent(1);
\r
3648 case IDM_IcsClient:
\r
3652 case IDM_EditGame:
\r
3656 case IDM_EditPosition:
\r
3657 EditPositionEvent();
\r
3660 case IDM_Training:
\r
3664 case IDM_ShowGameList:
\r
3665 ShowGameListProc();
\r
3668 case IDM_EditTags:
\r
3672 case IDM_EditComment:
\r
3673 if (commentDialogUp && editComment) {
\r
3676 EditCommentEvent();
\r
3696 case IDM_CallFlag:
\r
3716 case IDM_StopObserving:
\r
3717 StopObservingEvent();
\r
3720 case IDM_StopExamining:
\r
3721 StopExaminingEvent();
\r
3724 case IDM_TypeInMove:
\r
3725 PopUpMoveDialog('\000');
\r
3728 case IDM_Backward:
\r
3730 SetFocus(hwndMain);
\r
3735 SetFocus(hwndMain);
\r
3740 SetFocus(hwndMain);
\r
3745 SetFocus(hwndMain);
\r
3752 case IDM_TruncateGame:
\r
3753 TruncateGameEvent();
\r
3760 case IDM_RetractMove:
\r
3761 RetractMoveEvent();
\r
3764 case IDM_FlipView:
\r
3765 flipView = !flipView;
\r
3766 DrawPosition(FALSE, NULL);
\r
3769 case IDM_GeneralOptions:
\r
3770 GeneralOptionsPopup(hwnd);
\r
3773 case IDM_BoardOptions:
\r
3774 BoardOptionsPopup(hwnd);
\r
3777 case IDM_IcsOptions:
\r
3778 IcsOptionsPopup(hwnd);
\r
3782 FontsOptionsPopup(hwnd);
\r
3786 SoundOptionsPopup(hwnd);
\r
3789 case IDM_CommPort:
\r
3790 CommPortOptionsPopup(hwnd);
\r
3793 case IDM_LoadOptions:
\r
3794 LoadOptionsPopup(hwnd);
\r
3797 case IDM_SaveOptions:
\r
3798 SaveOptionsPopup(hwnd);
\r
3801 case IDM_TimeControl:
\r
3802 TimeControlOptionsPopup(hwnd);
\r
3805 case IDM_SaveSettings:
\r
3806 SaveSettings(settingsFileName);
\r
3809 case IDM_SaveSettingsOnExit:
\r
3810 saveSettingsOnExit = !saveSettingsOnExit;
\r
3811 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
3812 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
3813 MF_CHECKED : MF_UNCHECKED));
\r
3824 case IDM_AboutGame:
\r
3829 appData.debugMode = !appData.debugMode;
\r
3830 if (appData.debugMode) {
\r
3831 char dir[MSG_SIZ];
\r
3832 GetCurrentDirectory(MSG_SIZ, dir);
\r
3833 SetCurrentDirectory(installDir);
\r
3834 debugFP = fopen("WinBoard.debug", "w");
\r
3835 SetCurrentDirectory(dir);
\r
3836 setbuf(debugFP, NULL);
\r
3843 case IDM_HELPCONTENTS:
\r
3844 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
3845 MessageBox (GetFocus(),
\r
3846 "Unable to activate help",
\r
3847 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3851 case IDM_HELPSEARCH:
\r
3852 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
3853 MessageBox (GetFocus(),
\r
3854 "Unable to activate help",
\r
3855 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3859 case IDM_HELPHELP:
\r
3860 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
3861 MessageBox (GetFocus(),
\r
3862 "Unable to activate help",
\r
3863 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3868 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
3870 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
3871 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
3872 FreeProcInstance(lpProc);
\r
3875 case IDM_DirectCommand1:
\r
3876 AskQuestionEvent("Direct Command",
\r
3877 "Send to chess program:", "", "1");
\r
3879 case IDM_DirectCommand2:
\r
3880 AskQuestionEvent("Direct Command",
\r
3881 "Send to second chess program:", "", "2");
\r
3884 case EP_WhitePawn:
\r
3885 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
3886 fromX = fromY = -1;
\r
3889 case EP_WhiteKnight:
\r
3890 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
3891 fromX = fromY = -1;
\r
3894 case EP_WhiteBishop:
\r
3895 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
3896 fromX = fromY = -1;
\r
3899 case EP_WhiteRook:
\r
3900 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
3901 fromX = fromY = -1;
\r
3904 case EP_WhiteQueen:
\r
3905 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
3906 fromX = fromY = -1;
\r
3909 case EP_WhiteKing:
\r
3910 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
3911 fromX = fromY = -1;
\r
3914 case EP_BlackPawn:
\r
3915 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
3916 fromX = fromY = -1;
\r
3919 case EP_BlackKnight:
\r
3920 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
3921 fromX = fromY = -1;
\r
3924 case EP_BlackBishop:
\r
3925 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
3926 fromX = fromY = -1;
\r
3929 case EP_BlackRook:
\r
3930 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
3931 fromX = fromY = -1;
\r
3934 case EP_BlackQueen:
\r
3935 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
3936 fromX = fromY = -1;
\r
3939 case EP_BlackKing:
\r
3940 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
3941 fromX = fromY = -1;
\r
3944 case EP_EmptySquare:
\r
3945 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
3946 fromX = fromY = -1;
\r
3949 case EP_ClearBoard:
\r
3950 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
3951 fromX = fromY = -1;
\r
3955 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
3956 fromX = fromY = -1;
\r
3960 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
3961 fromX = fromY = -1;
\r
3965 DropMenuEvent(WhitePawn, fromX, fromY);
\r
3966 fromX = fromY = -1;
\r
3970 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
3971 fromX = fromY = -1;
\r
3975 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
3976 fromX = fromY = -1;
\r
3980 DropMenuEvent(WhiteRook, fromX, fromY);
\r
3981 fromX = fromY = -1;
\r
3985 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
3986 fromX = fromY = -1;
\r
3990 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
3996 case CLOCK_TIMER_ID:
\r
3997 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
3998 clockTimerEvent = 0;
\r
3999 DecrementClocks(); /* call into back end */
\r
4001 case LOAD_GAME_TIMER_ID:
\r
4002 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
4003 loadGameTimerEvent = 0;
\r
4004 AutoPlayGameLoop(); /* call into back end */
\r
4006 case ANALYSIS_TIMER_ID:
\r
4007 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
4008 appData.periodicUpdates) {
\r
4009 AnalysisPeriodicEvent(0);
\r
4011 KillTimer(hwnd, analysisTimerEvent);
\r
4012 analysisTimerEvent = 0;
\r
4015 case DELAYED_TIMER_ID:
\r
4016 KillTimer(hwnd, delayedTimerEvent);
\r
4017 delayedTimerEvent = 0;
\r
4018 delayedTimerCallback();
\r
4023 case WM_USER_Input:
\r
4024 InputEvent(hwnd, message, wParam, lParam);
\r
4027 case WM_ENTERSIZEMOVE:
\r
4028 if (hwnd == hwndMain) {
\r
4029 doingSizing = TRUE;
\r
4035 if (hwnd == hwndMain) {
\r
4036 lastSizing = wParam;
\r
4040 case WM_EXITSIZEMOVE:
\r
4041 if (hwnd == hwndMain) {
\r
4043 doingSizing = FALSE;
\r
4044 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4045 GetClientRect(hwnd, &client);
\r
4046 ResizeBoard(client.right, client.bottom, lastSizing);
\r
4051 case WM_DESTROY: /* message: window being destroyed */
\r
4052 PostQuitMessage(0);
\r
4056 if (hwnd == hwndMain) {
\r
4061 default: /* Passes it on if unprocessed */
\r
4062 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4067 /*---------------------------------------------------------------------------*\
\r
4069 * Misc utility routines
\r
4071 \*---------------------------------------------------------------------------*/
\r
4074 * returns TRUE if user selects a different color, FALSE otherwise
\r
4078 ChangeColor(HWND hwnd, COLORREF *which)
\r
4080 static BOOL firstTime = TRUE;
\r
4081 static DWORD customColors[16];
\r
4083 COLORREF newcolor;
\r
4088 /* Make initial colors in use available as custom colors */
\r
4089 /* Should we put the compiled-in defaults here instead? */
\r
4091 customColors[i++] = lightSquareColor & 0xffffff;
\r
4092 customColors[i++] = darkSquareColor & 0xffffff;
\r
4093 customColors[i++] = whitePieceColor & 0xffffff;
\r
4094 customColors[i++] = blackPieceColor & 0xffffff;
\r
4095 customColors[i++] = highlightSquareColor & 0xffffff;
\r
4096 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
4098 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
4099 customColors[i++] = textAttribs[ccl].color;
\r
4101 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
4102 firstTime = FALSE;
\r
4105 cc.lStructSize = sizeof(cc);
\r
4106 cc.hwndOwner = hwnd;
\r
4107 cc.hInstance = NULL;
\r
4108 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
4109 cc.lpCustColors = (LPDWORD) customColors;
\r
4110 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
4112 if (!ChooseColor(&cc)) return FALSE;
\r
4114 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
4115 if (newcolor == *which) return FALSE;
\r
4116 *which = newcolor;
\r
4120 InitDrawingColors();
\r
4121 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4126 MyLoadSound(MySound *ms)
\r
4132 if (ms->data) free(ms->data);
\r
4135 switch (ms->name[0]) {
\r
4141 /* System sound from Control Panel. Don't preload here. */
\r
4145 if (ms->name[1] == NULLCHAR) {
\r
4146 /* "!" alone = silence */
\r
4149 /* Builtin wave resource. Error if not found. */
\r
4150 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
4151 if (h == NULL) break;
\r
4152 ms->data = (void *)LoadResource(hInst, h);
\r
4153 if (h == NULL) break;
\r
4158 /* .wav file. Error if not found. */
\r
4159 f = fopen(ms->name, "rb");
\r
4160 if (f == NULL) break;
\r
4161 if (fstat(fileno(f), &st) < 0) break;
\r
4162 ms->data = malloc(st.st_size);
\r
4163 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
4169 char buf[MSG_SIZ];
\r
4170 sprintf(buf, "Error loading sound %s", ms->name);
\r
4171 DisplayError(buf, GetLastError());
\r
4177 MyPlaySound(MySound *ms)
\r
4179 BOOLEAN ok = FALSE;
\r
4180 switch (ms->name[0]) {
\r
4186 /* System sound from Control Panel (deprecated feature).
\r
4187 "$" alone or an unset sound name gets default beep (still in use). */
\r
4188 if (ms->name[1]) {
\r
4189 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
4191 if (!ok) ok = MessageBeep(MB_OK);
\r
4194 /* Builtin wave resource, or "!" alone for silence */
\r
4195 if (ms->name[1]) {
\r
4196 if (ms->data == NULL) return FALSE;
\r
4197 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4203 /* .wav file. Error if not found. */
\r
4204 if (ms->data == NULL) return FALSE;
\r
4205 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4208 /* Don't print an error: this can happen innocently if the sound driver
\r
4209 is busy; for instance, if another instance of WinBoard is playing
\r
4210 a sound at about the same time. */
\r
4213 char buf[MSG_SIZ];
\r
4214 sprintf(buf, "Error playing sound %s", ms->name);
\r
4215 DisplayError(buf, GetLastError());
\r
4223 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4226 OPENFILENAME *ofn;
\r
4227 static UINT *number; /* gross that this is static */
\r
4229 switch (message) {
\r
4230 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4231 /* Center the dialog over the application window */
\r
4232 ofn = (OPENFILENAME *) lParam;
\r
4233 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
4234 number = (UINT *) ofn->lCustData;
\r
4235 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
4239 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4240 return FALSE; /* Allow for further processing */
\r
4243 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
4244 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
4246 return FALSE; /* Allow for further processing */
\r
4252 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
4254 static UINT *number;
\r
4255 OPENFILENAME *ofname;
\r
4258 case WM_INITDIALOG:
\r
4259 ofname = (OPENFILENAME *)lParam;
\r
4260 number = (UINT *)(ofname->lCustData);
\r
4263 ofnot = (OFNOTIFY *)lParam;
\r
4264 if (ofnot->hdr.code == CDN_FILEOK) {
\r
4265 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
4274 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
4275 char *nameFilt, char *dlgTitle, UINT *number,
\r
4276 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
4278 OPENFILENAME openFileName;
\r
4279 char buf1[MSG_SIZ];
\r
4282 if (fileName == NULL) fileName = buf1;
\r
4283 if (defName == NULL) {
\r
4284 strcpy(fileName, "*.");
\r
4285 strcat(fileName, defExt);
\r
4287 strcpy(fileName, defName);
\r
4289 if (fileTitle) strcpy(fileTitle, "");
\r
4290 if (number) *number = 0;
\r
4292 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
4293 openFileName.hwndOwner = hwnd;
\r
4294 openFileName.hInstance = (HANDLE) hInst;
\r
4295 openFileName.lpstrFilter = nameFilt;
\r
4296 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
4297 openFileName.nMaxCustFilter = 0L;
\r
4298 openFileName.nFilterIndex = 1L;
\r
4299 openFileName.lpstrFile = fileName;
\r
4300 openFileName.nMaxFile = MSG_SIZ;
\r
4301 openFileName.lpstrFileTitle = fileTitle;
\r
4302 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
4303 openFileName.lpstrInitialDir = NULL;
\r
4304 openFileName.lpstrTitle = dlgTitle;
\r
4305 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
4306 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
4307 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
4308 | (oldDialog ? 0 : OFN_EXPLORER);
\r
4309 openFileName.nFileOffset = 0;
\r
4310 openFileName.nFileExtension = 0;
\r
4311 openFileName.lpstrDefExt = defExt;
\r
4312 openFileName.lCustData = (LONG) number;
\r
4313 openFileName.lpfnHook = oldDialog ?
\r
4314 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
4315 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
4317 if (write ? GetSaveFileName(&openFileName) :
\r
4318 GetOpenFileName(&openFileName)) {
\r
4319 /* open the file */
\r
4320 f = fopen(openFileName.lpstrFile, write ? "a" : "r");
\r
4322 MessageBox(hwnd, "File open failed", NULL,
\r
4323 MB_OK|MB_ICONEXCLAMATION);
\r
4327 int err = CommDlgExtendedError();
\r
4328 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
4337 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
4339 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
4342 * Get the first pop-up menu in the menu template. This is the
\r
4343 * menu that TrackPopupMenu displays.
\r
4345 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
4347 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
4350 * TrackPopup uses screen coordinates, so convert the
\r
4351 * coordinates of the mouse click to screen coordinates.
\r
4353 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
4355 /* Draw and track the floating pop-up menu. */
\r
4356 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
4357 pt.x, pt.y, 0, hwnd, NULL);
\r
4359 /* Destroy the menu.*/
\r
4360 DestroyMenu(hmenu);
\r
4365 int sizeX, sizeY, newSizeX, newSizeY;
\r
4367 } ResizeEditPlusButtonsClosure;
\r
4370 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
4372 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
4376 if (hChild == cl->hText) return TRUE;
\r
4377 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
4378 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
4379 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
4380 ScreenToClient(cl->hDlg, &pt);
\r
4381 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
4382 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
4386 /* Resize a dialog that has a (rich) edit field filling most of
\r
4387 the top, with a row of buttons below */
\r
4389 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
4392 int newTextHeight, newTextWidth;
\r
4393 ResizeEditPlusButtonsClosure cl;
\r
4395 /*if (IsIconic(hDlg)) return;*/
\r
4396 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
4398 cl.hdwp = BeginDeferWindowPos(8);
\r
4400 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
4401 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
4402 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
4403 if (newTextHeight < 0) {
\r
4404 newSizeY += -newTextHeight;
\r
4405 newTextHeight = 0;
\r
4407 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
4408 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
4414 cl.newSizeX = newSizeX;
\r
4415 cl.newSizeY = newSizeY;
\r
4416 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
4418 EndDeferWindowPos(cl.hdwp);
\r
4421 /* Center one window over another */
\r
4422 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
4424 RECT rChild, rParent;
\r
4425 int wChild, hChild, wParent, hParent;
\r
4426 int wScreen, hScreen, xNew, yNew;
\r
4429 /* Get the Height and Width of the child window */
\r
4430 GetWindowRect (hwndChild, &rChild);
\r
4431 wChild = rChild.right - rChild.left;
\r
4432 hChild = rChild.bottom - rChild.top;
\r
4434 /* Get the Height and Width of the parent window */
\r
4435 GetWindowRect (hwndParent, &rParent);
\r
4436 wParent = rParent.right - rParent.left;
\r
4437 hParent = rParent.bottom - rParent.top;
\r
4439 /* Get the display limits */
\r
4440 hdc = GetDC (hwndChild);
\r
4441 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
4442 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
4443 ReleaseDC(hwndChild, hdc);
\r
4445 /* Calculate new X position, then adjust for screen */
\r
4446 xNew = rParent.left + ((wParent - wChild) /2);
\r
4449 } else if ((xNew+wChild) > wScreen) {
\r
4450 xNew = wScreen - wChild;
\r
4453 /* Calculate new Y position, then adjust for screen */
\r
4454 yNew = rParent.top + ((hParent - hChild) /2);
\r
4457 } else if ((yNew+hChild) > hScreen) {
\r
4458 yNew = hScreen - hChild;
\r
4461 /* Set it, and return */
\r
4462 return SetWindowPos (hwndChild, NULL,
\r
4463 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
4466 /*---------------------------------------------------------------------------*\
\r
4468 * Startup Dialog functions
\r
4470 \*---------------------------------------------------------------------------*/
\r
4472 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
4474 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
4476 while (*cd != NULL) {
\r
4477 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
4483 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
4485 char buf1[ARG_MAX];
\r
4488 if (str[0] == '@') {
\r
4489 FILE* f = fopen(str + 1, "r");
\r
4491 DisplayFatalError(str + 1, errno, 2);
\r
4494 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
4496 buf1[len] = NULLCHAR;
\r
4500 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
4503 char buf[MSG_SIZ];
\r
4504 char *end = strchr(str, '\n');
\r
4505 if (end == NULL) return;
\r
4506 memcpy(buf, str, end - str);
\r
4507 buf[end - str] = NULLCHAR;
\r
4508 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
4514 SetStartupDialogEnables(HWND hDlg)
\r
4516 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
4517 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
4518 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
4519 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
4520 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
4521 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
4522 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
4523 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
4524 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
4525 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
4526 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
4527 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
4528 IsDlgButtonChecked(hDlg, OPT_View));
\r
4532 QuoteForFilename(char *filename)
\r
4534 int dquote, space;
\r
4535 dquote = strchr(filename, '"') != NULL;
\r
4536 space = strchr(filename, ' ') != NULL;
\r
4537 if (dquote || space) {
\r
4549 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
4551 char buf[MSG_SIZ];
\r
4554 InitComboStringsFromOption(hwndCombo, nthnames);
\r
4555 q = QuoteForFilename(nthcp);
\r
4556 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
4557 if (*nthdir != NULLCHAR) {
\r
4558 q = QuoteForFilename(nthdir);
\r
4559 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
4561 if (*nthcp == NULLCHAR) {
\r
4562 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
4563 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
4564 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
4565 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
4570 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4572 char buf[MSG_SIZ];
\r
4576 switch (message) {
\r
4577 case WM_INITDIALOG:
\r
4578 /* Center the dialog */
\r
4579 CenterWindow (hDlg, GetDesktopWindow());
\r
4580 /* Initialize the dialog items */
\r
4581 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
4582 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
4583 firstChessProgramNames);
\r
4584 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
4585 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
4586 secondChessProgramNames);
\r
4587 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
4588 InitComboStringsFromOption(hwndCombo, icsNames);
\r
4589 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
4590 if (*appData.icsHelper != NULLCHAR) {
\r
4591 char *q = QuoteForFilename(appData.icsHelper);
\r
4592 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
4594 if (*appData.icsHost == NULLCHAR) {
\r
4595 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
4596 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
4597 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
4598 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
4599 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
4601 if (chessProgram) {
\r
4602 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
4603 } else if (appData.icsActive) {
\r
4604 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
4605 } else if (appData.noChessProgram) {
\r
4606 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
4608 SetStartupDialogEnables(hDlg);
\r
4612 switch (LOWORD(wParam)) {
\r
4614 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
4615 strcpy(buf, "/fcp=");
\r
4616 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4618 ParseArgs(StringGet, &p);
\r
4619 strcpy(buf, "/scp=");
\r
4620 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4622 ParseArgs(StringGet, &p);
\r
4623 appData.noChessProgram = FALSE;
\r
4624 appData.icsActive = FALSE;
\r
4625 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
4626 strcpy(buf, "/ics /icshost=");
\r
4627 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4629 ParseArgs(StringGet, &p);
\r
4630 if (appData.zippyPlay) {
\r
4631 strcpy(buf, "/fcp=");
\r
4632 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4634 ParseArgs(StringGet, &p);
\r
4636 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
4637 appData.noChessProgram = TRUE;
\r
4638 appData.icsActive = FALSE;
\r
4640 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
4641 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
4644 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
4645 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
4647 ParseArgs(StringGet, &p);
\r
4649 EndDialog(hDlg, TRUE);
\r
4656 case IDM_HELPCONTENTS:
\r
4657 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
4658 MessageBox (GetFocus(),
\r
4659 "Unable to activate help",
\r
4660 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4665 SetStartupDialogEnables(hDlg);
\r
4673 /*---------------------------------------------------------------------------*\
\r
4675 * About box dialog functions
\r
4677 \*---------------------------------------------------------------------------*/
\r
4679 /* Process messages for "About" dialog box */
\r
4681 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4683 switch (message) {
\r
4684 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4685 /* Center the dialog over the application window */
\r
4686 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4687 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
4690 case WM_COMMAND: /* message: received a command */
\r
4691 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
4692 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
4693 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4701 /*---------------------------------------------------------------------------*\
\r
4703 * Comment Dialog functions
\r
4705 \*---------------------------------------------------------------------------*/
\r
4708 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4710 static HANDLE hwndText = NULL;
\r
4711 int len, newSizeX, newSizeY, flags;
\r
4712 static int sizeX, sizeY;
\r
4717 switch (message) {
\r
4718 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4719 /* Initialize the dialog items */
\r
4720 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
4721 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
4722 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
4723 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
4724 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
4725 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
4726 SetWindowText(hDlg, commentTitle);
\r
4727 if (editComment) {
\r
4728 SetFocus(hwndText);
\r
4730 SetFocus(GetDlgItem(hDlg, IDOK));
\r
4732 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
4733 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
4734 MAKELPARAM(FALSE, 0));
\r
4735 /* Size and position the dialog */
\r
4736 if (!commentDialog) {
\r
4737 commentDialog = hDlg;
\r
4738 flags = SWP_NOZORDER;
\r
4739 GetClientRect(hDlg, &rect);
\r
4740 sizeX = rect.right;
\r
4741 sizeY = rect.bottom;
\r
4742 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
4743 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
4744 WINDOWPLACEMENT wp;
\r
4745 EnsureOnScreen(&commentX, &commentY);
\r
4746 wp.length = sizeof(WINDOWPLACEMENT);
\r
4748 wp.showCmd = SW_SHOW;
\r
4749 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
4750 wp.rcNormalPosition.left = commentX;
\r
4751 wp.rcNormalPosition.right = commentX + commentW;
\r
4752 wp.rcNormalPosition.top = commentY;
\r
4753 wp.rcNormalPosition.bottom = commentY + commentH;
\r
4754 SetWindowPlacement(hDlg, &wp);
\r
4756 GetClientRect(hDlg, &rect);
\r
4757 newSizeX = rect.right;
\r
4758 newSizeY = rect.bottom;
\r
4759 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
4760 newSizeX, newSizeY);
\r
4767 case WM_COMMAND: /* message: received a command */
\r
4768 switch (LOWORD(wParam)) {
\r
4770 if (editComment) {
\r
4772 /* Read changed options from the dialog box */
\r
4773 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
4774 len = GetWindowTextLength(hwndText);
\r
4775 str = (char *) malloc(len + 1);
\r
4776 GetWindowText(hwndText, str, len + 1);
\r
4785 ReplaceComment(commentIndex, str);
\r
4792 case OPT_CancelComment:
\r
4796 case OPT_ClearComment:
\r
4797 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
4800 case OPT_EditComment:
\r
4801 EditCommentEvent();
\r
4810 newSizeX = LOWORD(lParam);
\r
4811 newSizeY = HIWORD(lParam);
\r
4812 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
4817 case WM_GETMINMAXINFO:
\r
4818 /* Prevent resizing window too small */
\r
4819 mmi = (MINMAXINFO *) lParam;
\r
4820 mmi->ptMinTrackSize.x = 100;
\r
4821 mmi->ptMinTrackSize.y = 100;
\r
4828 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
4833 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
4835 if (str == NULL) str = "";
\r
4836 p = (char *) malloc(2 * strlen(str) + 2);
\r
4839 if (*str == '\n') *q++ = '\r';
\r
4843 if (commentText != NULL) free(commentText);
\r
4845 commentIndex = index;
\r
4846 commentTitle = title;
\r
4848 editComment = edit;
\r
4850 if (commentDialog) {
\r
4851 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
4852 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
4854 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
4855 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
4856 hwndMain, (DLGPROC)lpProc);
\r
4857 FreeProcInstance(lpProc);
\r
4859 commentDialogUp = TRUE;
\r
4863 /*---------------------------------------------------------------------------*\
\r
4865 * Type-in move dialog functions
\r
4867 \*---------------------------------------------------------------------------*/
\r
4870 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4872 char move[MSG_SIZ];
\r
4874 ChessMove moveType;
\r
4875 int fromX, fromY, toX, toY;
\r
4878 switch (message) {
\r
4879 case WM_INITDIALOG:
\r
4880 move[0] = (char) lParam;
\r
4881 move[1] = NULLCHAR;
\r
4882 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4883 hInput = GetDlgItem(hDlg, OPT_Move);
\r
4884 SetWindowText(hInput, move);
\r
4886 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
4890 switch (LOWORD(wParam)) {
\r
4892 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
4893 gameMode != Training) {
\r
4894 DisplayMoveError("Displayed move is not current");
\r
4896 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
4897 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
4898 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
4899 if (gameMode != Training)
\r
4900 forwardMostMove = currentMove;
\r
4901 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4903 DisplayMoveError("Could not parse move");
\r
4906 EndDialog(hDlg, TRUE);
\r
4909 EndDialog(hDlg, FALSE);
\r
4920 PopUpMoveDialog(char firstchar)
\r
4924 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
4925 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
4926 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
4927 gameMode == EditPosition || gameMode == IcsExamining ||
\r
4928 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
4929 gameMode == Training) {
\r
4930 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
4931 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
4932 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
4933 FreeProcInstance(lpProc);
\r
4937 /*---------------------------------------------------------------------------*\
\r
4941 \*---------------------------------------------------------------------------*/
\r
4943 /* Nonmodal error box */
\r
4947 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
4948 if (errorDialog == NULL) return;
\r
4949 DestroyWindow(errorDialog);
\r
4950 errorDialog = NULL;
\r
4954 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4959 switch (message) {
\r
4960 case WM_INITDIALOG:
\r
4961 GetWindowRect(hDlg, &rChild);
\r
4962 SetWindowPos(hDlg, NULL, rChild.left,
\r
4963 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
4964 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
4965 errorDialog = hDlg;
\r
4966 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
4967 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
4971 switch (LOWORD(wParam)) {
\r
4974 if (errorDialog = hDlg) errorDialog = NULL;
\r
4975 DestroyWindow(hDlg);
\r
4986 /*---------------------------------------------------------------------------*\
\r
4988 * Ics Interaction console functions
\r
4990 \*---------------------------------------------------------------------------*/
\r
4992 #define HISTORY_SIZE 64
\r
4993 static char *history[HISTORY_SIZE];
\r
4994 int histIn = 0, histP = 0;
\r
4997 SaveInHistory(char *cmd)
\r
4999 if (history[histIn] != NULL) {
\r
5000 free(history[histIn]);
\r
5001 history[histIn] = NULL;
\r
5003 if (*cmd == NULLCHAR) return;
\r
5004 history[histIn] = StrSave(cmd);
\r
5005 histIn = (histIn + 1) % HISTORY_SIZE;
\r
5006 if (history[histIn] != NULL) {
\r
5007 free(history[histIn]);
\r
5008 history[histIn] = NULL;
\r
5014 PrevInHistory(char *cmd)
\r
5017 if (histP == histIn) {
\r
5018 if (history[histIn] != NULL) free(history[histIn]);
\r
5019 history[histIn] = StrSave(cmd);
\r
5021 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
5022 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
5024 return history[histP];
\r
5030 if (histP == histIn) return NULL;
\r
5031 histP = (histP + 1) % HISTORY_SIZE;
\r
5032 return history[histP];
\r
5039 BOOLEAN immediate;
\r
5040 } IcsTextMenuEntry;
\r
5041 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
5042 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
5045 ParseIcsTextMenu(char *icsTextMenuString)
\r
5048 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
5049 char *p = icsTextMenuString;
\r
5050 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5053 if (e->command != NULL) {
\r
5055 e->command = NULL;
\r
5059 e = icsTextMenuEntry;
\r
5060 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5061 if (*p == ';' || *p == '\n') {
\r
5062 e->item = strdup("-");
\r
5063 e->command = NULL;
\r
5065 } else if (*p == '-') {
\r
5066 e->item = strdup("-");
\r
5067 e->command = NULL;
\r
5071 char *q, *r, *s, *t;
\r
5073 q = strchr(p, ',');
\r
5074 if (q == NULL) break;
\r
5076 r = strchr(q + 1, ',');
\r
5077 if (r == NULL) break;
\r
5079 s = strchr(r + 1, ',');
\r
5080 if (s == NULL) break;
\r
5083 t = strchr(s + 1, c);
\r
5086 t = strchr(s + 1, c);
\r
5088 if (t != NULL) *t = NULLCHAR;
\r
5089 e->item = strdup(p);
\r
5090 e->command = strdup(q + 1);
\r
5091 e->getname = *(r + 1) != '0';
\r
5092 e->immediate = *(s + 1) != '0';
\r
5096 if (t == NULL) break;
\r
5105 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
5109 hmenu = LoadMenu(hInst, "TextMenu");
\r
5110 h = GetSubMenu(hmenu, 0);
\r
5112 if (strcmp(e->item, "-") == 0) {
\r
5113 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
5115 if (e->item[0] == '|') {
\r
5116 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
5117 IDM_CommandX + i, &e->item[1]);
\r
5119 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
5128 WNDPROC consoleTextWindowProc;
\r
5131 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
5133 char buf[MSG_SIZ], name[MSG_SIZ];
\r
5134 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5138 SetWindowText(hInput, command);
\r
5140 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5142 sel.cpMin = 999999;
\r
5143 sel.cpMax = 999999;
\r
5144 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5149 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5150 if (sel.cpMin == sel.cpMax) {
\r
5151 /* Expand to surrounding word */
\r
5154 tr.chrg.cpMax = sel.cpMin;
\r
5155 tr.chrg.cpMin = --sel.cpMin;
\r
5156 if (sel.cpMin < 0) break;
\r
5157 tr.lpstrText = name;
\r
5158 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5159 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5163 tr.chrg.cpMin = sel.cpMax;
\r
5164 tr.chrg.cpMax = ++sel.cpMax;
\r
5165 tr.lpstrText = name;
\r
5166 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
5167 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5170 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5171 MessageBeep(MB_ICONEXCLAMATION);
\r
5175 tr.lpstrText = name;
\r
5176 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5178 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5179 MessageBeep(MB_ICONEXCLAMATION);
\r
5182 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
5185 sprintf(buf, "%s %s", command, name);
\r
5186 SetWindowText(hInput, buf);
\r
5187 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5189 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
5190 SetWindowText(hInput, buf);
\r
5191 sel.cpMin = 999999;
\r
5192 sel.cpMax = 999999;
\r
5193 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5199 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5204 switch (message) {
\r
5206 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5209 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
5212 sel.cpMin = 999999;
\r
5213 sel.cpMax = 999999;
\r
5214 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5215 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
5220 if (wParam == '\t') {
\r
5221 if (GetKeyState(VK_SHIFT) < 0) {
\r
5223 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5224 if (buttonDesc[0].hwnd) {
\r
5225 SetFocus(buttonDesc[0].hwnd);
\r
5227 SetFocus(hwndMain);
\r
5231 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
5234 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5236 SendMessage(hInput, message, wParam, lParam);
\r
5240 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5242 return SendMessage(hInput, message, wParam, lParam);
\r
5243 case WM_MBUTTONDOWN:
\r
5244 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5245 case WM_RBUTTONDOWN:
\r
5246 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
5247 /* Move selection here if it was empty */
\r
5249 pt.x = LOWORD(lParam);
\r
5250 pt.y = HIWORD(lParam);
\r
5251 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5252 if (sel.cpMin == sel.cpMax) {
\r
5253 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
5254 sel.cpMax = sel.cpMin;
\r
5255 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5257 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
5260 case WM_RBUTTONUP:
\r
5261 if (GetKeyState(VK_SHIFT) & ~1) {
\r
5262 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5263 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5266 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
5267 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5268 if (sel.cpMin == sel.cpMax) {
\r
5269 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
5270 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
5272 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
5273 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
5275 pt.x = LOWORD(lParam);
\r
5276 pt.y = HIWORD(lParam);
\r
5277 MenuPopup(hwnd, pt, hmenu, -1);
\r
5281 switch (LOWORD(wParam)) {
\r
5282 case IDM_QuickPaste:
\r
5284 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5285 if (sel.cpMin == sel.cpMax) {
\r
5286 MessageBeep(MB_ICONEXCLAMATION);
\r
5289 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5290 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5291 SendMessage(hInput, WM_PASTE, 0, 0);
\r
5296 SendMessage(hwnd, WM_CUT, 0, 0);
\r
5299 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
5302 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5306 int i = LOWORD(wParam) - IDM_CommandX;
\r
5307 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
5308 icsTextMenuEntry[i].command != NULL) {
\r
5309 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
5310 icsTextMenuEntry[i].getname,
\r
5311 icsTextMenuEntry[i].immediate);
\r
5319 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
5322 WNDPROC consoleInputWindowProc;
\r
5325 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5327 char buf[MSG_SIZ];
\r
5329 static BOOL sendNextChar = FALSE;
\r
5330 static BOOL quoteNextChar = FALSE;
\r
5331 InputSource *is = consoleInputSource;
\r
5335 switch (message) {
\r
5337 if (!appData.localLineEditing || sendNextChar) {
\r
5338 is->buf[0] = (CHAR) wParam;
\r
5340 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5341 sendNextChar = FALSE;
\r
5344 if (quoteNextChar) {
\r
5345 buf[0] = (char) wParam;
\r
5346 buf[1] = NULLCHAR;
\r
5347 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
5348 quoteNextChar = FALSE;
\r
5352 case '\r': /* Enter key */
\r
5353 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
5354 if (consoleEcho) SaveInHistory(is->buf);
\r
5355 is->buf[is->count++] = '\n';
\r
5356 is->buf[is->count] = NULLCHAR;
\r
5357 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5358 if (consoleEcho) {
\r
5359 ConsoleOutput(is->buf, is->count, TRUE);
\r
5360 } else if (appData.localLineEditing) {
\r
5361 ConsoleOutput("\n", 1, TRUE);
\r
5364 case '\033': /* Escape key */
\r
5365 SetWindowText(hwnd, "");
\r
5366 cf.cbSize = sizeof(CHARFORMAT);
\r
5367 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
5368 if (consoleEcho) {
\r
5369 cf.crTextColor = textAttribs[ColorNormal].color;
\r
5371 cf.crTextColor = COLOR_ECHOOFF;
\r
5373 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
5374 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
5376 case '\t': /* Tab key */
\r
5377 if (GetKeyState(VK_SHIFT) < 0) {
\r
5379 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
5382 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5383 if (buttonDesc[0].hwnd) {
\r
5384 SetFocus(buttonDesc[0].hwnd);
\r
5386 SetFocus(hwndMain);
\r
5390 case '\023': /* Ctrl+S */
\r
5391 sendNextChar = TRUE;
\r
5393 case '\021': /* Ctrl+Q */
\r
5394 quoteNextChar = TRUE;
\r
5403 GetWindowText(hwnd, buf, MSG_SIZ);
\r
5404 p = PrevInHistory(buf);
\r
5406 SetWindowText(hwnd, p);
\r
5407 sel.cpMin = 999999;
\r
5408 sel.cpMax = 999999;
\r
5409 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5414 p = NextInHistory();
\r
5416 SetWindowText(hwnd, p);
\r
5417 sel.cpMin = 999999;
\r
5418 sel.cpMax = 999999;
\r
5419 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5425 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5429 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
5433 case WM_MBUTTONDOWN:
\r
5434 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5435 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5437 case WM_RBUTTONUP:
\r
5438 if (GetKeyState(VK_SHIFT) & ~1) {
\r
5439 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5440 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5444 hmenu = LoadMenu(hInst, "InputMenu");
\r
5445 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5446 if (sel.cpMin == sel.cpMax) {
\r
5447 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
5448 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
5450 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
5451 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
5453 pt.x = LOWORD(lParam);
\r
5454 pt.y = HIWORD(lParam);
\r
5455 MenuPopup(hwnd, pt, hmenu, -1);
\r
5459 switch (LOWORD(wParam)) {
\r
5461 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
5463 case IDM_SelectAll:
\r
5465 sel.cpMax = -1; /*999999?*/
\r
5466 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5469 SendMessage(hwnd, WM_CUT, 0, 0);
\r
5472 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
5475 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5480 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
5483 #define CO_MAX 100000
\r
5484 #define CO_TRIM 1000
\r
5487 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5489 static HWND hText, hInput, hFocus;
\r
5490 InputSource *is = consoleInputSource;
\r
5492 static int sizeX, sizeY;
\r
5493 int newSizeX, newSizeY;
\r
5496 switch (message) {
\r
5497 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5498 hwndConsole = hDlg;
\r
5499 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
5500 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
5502 consoleTextWindowProc = (WNDPROC)
\r
5503 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
5504 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
5505 consoleInputWindowProc = (WNDPROC)
\r
5506 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
5507 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
5508 Colorize(ColorNormal, TRUE);
\r
5509 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
5510 ChangedConsoleFont();
\r
5511 GetClientRect(hDlg, &rect);
\r
5512 sizeX = rect.right;
\r
5513 sizeY = rect.bottom;
\r
5514 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
5515 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
5516 WINDOWPLACEMENT wp;
\r
5517 EnsureOnScreen(&consoleX, &consoleY);
\r
5518 wp.length = sizeof(WINDOWPLACEMENT);
\r
5520 wp.showCmd = SW_SHOW;
\r
5521 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
5522 wp.rcNormalPosition.left = consoleX;
\r
5523 wp.rcNormalPosition.right = consoleX + consoleW;
\r
5524 wp.rcNormalPosition.top = consoleY;
\r
5525 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
5526 SetWindowPlacement(hDlg, &wp);
\r
5540 if (IsIconic(hDlg)) break;
\r
5541 newSizeX = LOWORD(lParam);
\r
5542 newSizeY = HIWORD(lParam);
\r
5543 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
5544 RECT rectText, rectInput;
\r
5546 int newTextHeight, newTextWidth;
\r
5547 GetWindowRect(hText, &rectText);
\r
5548 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5549 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5550 if (newTextHeight < 0) {
\r
5551 newSizeY += -newTextHeight;
\r
5552 newTextHeight = 0;
\r
5554 SetWindowPos(hText, NULL, 0, 0,
\r
5555 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5556 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
5557 pt.x = rectInput.left;
\r
5558 pt.y = rectInput.top + newSizeY - sizeY;
\r
5559 ScreenToClient(hDlg, &pt);
\r
5560 SetWindowPos(hInput, NULL,
\r
5561 pt.x, pt.y, /* needs client coords */
\r
5562 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
5563 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
5569 case WM_GETMINMAXINFO:
\r
5570 /* Prevent resizing window too small */
\r
5571 mmi = (MINMAXINFO *) lParam;
\r
5572 mmi->ptMinTrackSize.x = 100;
\r
5573 mmi->ptMinTrackSize.y = 100;
\r
5576 return DefWindowProc(hDlg, message, wParam, lParam);
\r
5584 if (hwndConsole) return;
\r
5585 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
5586 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
5591 ConsoleOutput(char* data, int length, int forceVisible)
\r
5596 char buf[CO_MAX+1];
\r
5599 static int delayLF = 0;
\r
5600 CHARRANGE savesel, sel;
\r
5602 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
5610 while (length--) {
\r
5618 } else if (*p == '\007') {
\r
5619 MyPlaySound(&sounds[(int)SoundBell]);
\r
5626 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5627 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
5628 /* Save current selection */
\r
5629 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
5630 exlen = GetWindowTextLength(hText);
\r
5631 /* Find out whether current end of text is visible */
\r
5632 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
5633 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
5634 /* Trim existing text if it's too long */
\r
5635 if (exlen + (q - buf) > CO_MAX) {
\r
5636 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
5639 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5640 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
5642 savesel.cpMin -= trim;
\r
5643 savesel.cpMax -= trim;
\r
5644 if (exlen < 0) exlen = 0;
\r
5645 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
5646 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
5648 /* Append the new text */
\r
5649 sel.cpMin = exlen;
\r
5650 sel.cpMax = exlen;
\r
5651 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5652 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
5653 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
5654 if (forceVisible || exlen == 0 ||
\r
5655 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
5656 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
5657 /* Scroll to make new end of text visible if old end of text
\r
5658 was visible or new text is an echo of user typein */
\r
5659 sel.cpMin = 9999999;
\r
5660 sel.cpMax = 9999999;
\r
5661 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5662 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
5663 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
5664 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
5666 if (savesel.cpMax == exlen || forceVisible) {
\r
5667 /* Move insert point to new end of text if it was at the old
\r
5668 end of text or if the new text is an echo of user typein */
\r
5669 sel.cpMin = 9999999;
\r
5670 sel.cpMax = 9999999;
\r
5671 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5673 /* Restore previous selection */
\r
5674 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
5676 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
5683 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
5684 RECT *rect, char *color)
\r
5688 COLORREF oldFg, oldBg;
\r
5691 if (appData.clockMode) {
\r
5693 sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));
\r
5695 sprintf(buf, "%s: %s", color, TimeString(timeRemaining));
\r
5702 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
5703 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
5705 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
5706 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
5708 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
5710 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
5711 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
5712 rect, str, strlen(str), NULL);
\r
5714 (void) SetTextColor(hdc, oldFg);
\r
5715 (void) SetBkColor(hdc, oldBg);
\r
5716 (void) SelectObject(hdc, oldFont);
\r
5721 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
5726 ResetEvent(ovl->hEvent);
\r
5727 ovl->Offset = ovl->OffsetHigh = 0;
\r
5728 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
5732 err = GetLastError();
\r
5733 if (err == ERROR_IO_PENDING) {
\r
5734 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
5738 err = GetLastError();
\r
5745 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
5750 ResetEvent(ovl->hEvent);
\r
5751 ovl->Offset = ovl->OffsetHigh = 0;
\r
5752 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
5756 err = GetLastError();
\r
5757 if (err == ERROR_IO_PENDING) {
\r
5758 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
5762 err = GetLastError();
\r
5770 InputThread(LPVOID arg)
\r
5775 is = (InputSource *) arg;
\r
5776 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
5777 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
5778 while (is->hThread != NULL) {
\r
5779 is->error = DoReadFile(is->hFile, is->next,
\r
5780 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
5781 &is->count, &ovl);
\r
5782 if (is->error == NO_ERROR) {
\r
5783 is->next += is->count;
\r
5785 if (is->error == ERROR_BROKEN_PIPE) {
\r
5786 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
5789 is->count = (DWORD) -1;
\r
5792 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5793 if (is->count <= 0) break; /* Quit on EOF or error */
\r
5795 CloseHandle(ovl.hEvent);
\r
5796 CloseHandle(is->hFile);
\r
5801 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
5803 NonOvlInputThread(LPVOID arg)
\r
5810 is = (InputSource *) arg;
\r
5811 while (is->hThread != NULL) {
\r
5812 is->error = ReadFile(is->hFile, is->next,
\r
5813 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
5814 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
5815 if (is->error == NO_ERROR) {
\r
5816 /* Change CRLF to LF */
\r
5817 if (is->next > is->buf) {
\r
5819 i = is->count + 1;
\r
5827 if (prev == '\r' && *p == '\n') {
\r
5839 if (is->error == ERROR_BROKEN_PIPE) {
\r
5840 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
5843 is->count = (DWORD) -1;
\r
5846 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5847 if (is->count < 0) break; /* Quit on error */
\r
5849 CloseHandle(is->hFile);
\r
5854 SocketInputThread(LPVOID arg)
\r
5858 is = (InputSource *) arg;
\r
5859 while (is->hThread != NULL) {
\r
5860 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
5861 if ((int)is->count == SOCKET_ERROR) {
\r
5862 is->count = (DWORD) -1;
\r
5863 is->error = WSAGetLastError();
\r
5865 is->error = NO_ERROR;
\r
5866 is->next += is->count;
\r
5867 if (is->count == 0 && is->second == is) {
\r
5868 /* End of file on stderr; quit with no message */
\r
5872 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5873 if (is->count <= 0) break; /* Quit on EOF or error */
\r
5879 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5883 is = (InputSource *) lParam;
\r
5884 if (is->lineByLine) {
\r
5885 /* Feed in lines one by one */
\r
5886 char *p = is->buf;
\r
5888 while (q < is->next) {
\r
5889 if (*q++ == '\n') {
\r
5890 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
5894 /* Move any partial line to the start of the buffer */
\r
5896 while (p < is->next) {
\r
5900 if (is->error != NO_ERROR || is->count == 0) {
\r
5901 /* Notify backend of the error. Note: If there was a partial
\r
5902 line at the end, it is not flushed through. */
\r
5903 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
5906 /* Feed in the whole chunk of input at once */
\r
5907 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
5908 is->next = is->buf;
\r
5912 /*---------------------------------------------------------------------------*\
\r
5914 * Menu enables. Used when setting various modes.
\r
5916 \*---------------------------------------------------------------------------*/
\r
5924 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
5926 while (enab->item > 0) {
\r
5927 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
5932 Enables gnuEnables[] = {
\r
5933 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
5934 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
5935 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
5936 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
5937 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
5938 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
5939 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
5940 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
5941 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
5942 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
5946 Enables icsEnables[] = {
\r
5947 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
5948 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
5949 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
5950 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
5951 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
5952 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
5953 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
5954 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
5955 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
5956 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
5957 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
5958 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
5963 Enables zippyEnables[] = {
\r
5964 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
5965 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
5966 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
5971 Enables ncpEnables[] = {
\r
5972 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
5973 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
5974 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
5975 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
5976 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
5977 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
5978 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
5979 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
5980 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
5981 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
5982 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
5983 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
5984 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
5985 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
5986 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
5990 Enables trainingOnEnables[] = {
\r
5991 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
5992 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
5993 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
5994 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
5995 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
5996 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
5997 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
5998 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
6002 Enables trainingOffEnables[] = {
\r
6003 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
6004 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
6005 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
6006 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
6007 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
6008 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
6009 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6010 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
6014 /* These modify either ncpEnables or gnuEnables */
\r
6015 Enables cmailEnables[] = {
\r
6016 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
6017 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
6018 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
6019 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
6020 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
6021 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6022 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
6026 Enables machineThinkingEnables[] = {
\r
6027 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6028 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
6029 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
6030 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6031 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
6032 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6033 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6034 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6035 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6036 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
6037 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6038 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6039 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6040 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
6041 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6045 Enables userThinkingEnables[] = {
\r
6046 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6047 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
6048 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
6049 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6050 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
6051 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6052 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6053 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6054 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6055 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
6056 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
6057 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
6058 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
6059 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
6060 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
6064 /*---------------------------------------------------------------------------*\
\r
6066 * Front-end interface functions exported by XBoard.
\r
6067 * Functions appear in same order as prototypes in frontend.h.
\r
6069 \*---------------------------------------------------------------------------*/
\r
6073 static UINT prevChecked = 0;
\r
6074 static int prevPausing = 0;
\r
6077 if (pausing != prevPausing) {
\r
6078 prevPausing = pausing;
\r
6079 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
6080 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
6081 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
6084 switch (gameMode) {
\r
6085 case BeginningOfGame:
\r
6086 if (appData.icsActive)
\r
6087 nowChecked = IDM_IcsClient;
\r
6088 else if (appData.noChessProgram)
\r
6089 nowChecked = IDM_EditGame;
\r
6091 nowChecked = IDM_MachineBlack;
\r
6093 case MachinePlaysBlack:
\r
6094 nowChecked = IDM_MachineBlack;
\r
6096 case MachinePlaysWhite:
\r
6097 nowChecked = IDM_MachineWhite;
\r
6099 case TwoMachinesPlay:
\r
6100 nowChecked = IDM_TwoMachines;
\r
6103 nowChecked = IDM_AnalysisMode;
\r
6106 nowChecked = IDM_AnalyzeFile;
\r
6109 nowChecked = IDM_EditGame;
\r
6111 case PlayFromGameFile:
\r
6112 nowChecked = IDM_LoadGame;
\r
6114 case EditPosition:
\r
6115 nowChecked = IDM_EditPosition;
\r
6118 nowChecked = IDM_Training;
\r
6120 case IcsPlayingWhite:
\r
6121 case IcsPlayingBlack:
\r
6122 case IcsObserving:
\r
6124 nowChecked = IDM_IcsClient;
\r
6131 if (prevChecked != 0)
\r
6132 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6133 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
6134 if (nowChecked != 0)
\r
6135 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6136 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
6138 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
6139 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
6140 MF_BYCOMMAND|MF_ENABLED);
\r
6142 (void) EnableMenuItem(GetMenu(hwndMain),
\r
6143 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
6146 prevChecked = nowChecked;
\r
6152 HMENU hmenu = GetMenu(hwndMain);
\r
6153 SetMenuEnables(hmenu, icsEnables);
\r
6154 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
6155 MF_BYPOSITION|MF_ENABLED);
\r
6157 if (appData.zippyPlay) {
\r
6158 SetMenuEnables(hmenu, zippyEnables);
\r
6166 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
6172 HMENU hmenu = GetMenu(hwndMain);
\r
6173 SetMenuEnables(hmenu, ncpEnables);
\r
6174 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
6175 MF_BYPOSITION|MF_GRAYED);
\r
6176 DrawMenuBar(hwndMain);
\r
6182 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
6186 SetTrainingModeOn()
\r
6189 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
6190 for (i = 0; i < N_BUTTONS; i++) {
\r
6191 if (buttonDesc[i].hwnd != NULL)
\r
6192 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
6197 VOID SetTrainingModeOff()
\r
6200 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
6201 for (i = 0; i < N_BUTTONS; i++) {
\r
6202 if (buttonDesc[i].hwnd != NULL)
\r
6203 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
6209 SetUserThinkingEnables()
\r
6211 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
6215 SetMachineThinkingEnables()
\r
6217 HMENU hMenu = GetMenu(hwndMain);
\r
6218 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
6220 SetMenuEnables(hMenu, machineThinkingEnables);
\r
6222 if (gameMode == MachinePlaysBlack) {
\r
6223 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
6224 } else if (gameMode == MachinePlaysWhite) {
\r
6225 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
6226 } else if (gameMode == TwoMachinesPlay) {
\r
6227 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
6233 DisplayTitle(char *str)
\r
6235 char title[MSG_SIZ], *host;
\r
6236 if (str[0] != NULLCHAR) {
\r
6237 strcpy(title, str);
\r
6238 } else if (appData.icsActive) {
\r
6239 if (appData.icsCommPort[0] != NULLCHAR)
\r
6242 host = appData.icsHost;
\r
6243 sprintf(title, "%s: %s", szTitle, host);
\r
6244 } else if (appData.noChessProgram) {
\r
6245 strcpy(title, szTitle);
\r
6247 strcpy(title, szTitle);
\r
6248 strcat(title, ": ");
\r
6249 strcat(title, first.tidy);
\r
6251 SetWindowText(hwndMain, title);
\r
6256 DisplayMessage(char *str1, char *str2)
\r
6260 int remain = MESSAGE_TEXT_MAX - 1;
\r
6263 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
6264 messageText[0] = NULLCHAR;
\r
6266 len = strlen(str1);
\r
6267 if (len > remain) len = remain;
\r
6268 strncpy(messageText, str1, len);
\r
6269 messageText[len] = NULLCHAR;
\r
6272 if (*str2 && remain >= 2) {
\r
6274 strcat(messageText, " ");
\r
6277 len = strlen(str2);
\r
6278 if (len > remain) len = remain;
\r
6279 strncat(messageText, str2, len);
\r
6281 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
6283 if (IsIconic(hwndMain)) return;
\r
6284 hdc = GetDC(hwndMain);
\r
6285 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
6286 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
6287 &messageRect, messageText, strlen(messageText), NULL);
\r
6288 (void) SelectObject(hdc, oldFont);
\r
6289 (void) ReleaseDC(hwndMain, hdc);
\r
6293 DisplayError(char *str, int error)
\r
6296 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
6303 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
6304 NULL, error, LANG_NEUTRAL,
\r
6305 (LPSTR) buf2, MSG_SIZ, NULL);
\r
6307 sprintf(buf, "%s:\n%s", str, buf2);
\r
6309 ErrorMap *em = errmap;
\r
6310 while (em->err != 0 && em->err != error) em++;
\r
6311 if (em->err != 0) {
\r
6312 sprintf(buf, "%s:\n%s", str, em->msg);
\r
6314 sprintf(buf, "%s:\nError code %d", str, error);
\r
6322 if (hwndMain != NULL /*!!?*/) {
\r
6335 if (hwndMain == NULL) {
\r
6336 MessageBox(NULL, errorMessage, "Error", MB_OK|MB_ICONEXCLAMATION);
\r
6338 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6339 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6340 hwndMain, (DLGPROC)lpProc);
\r
6341 FreeProcInstance(lpProc);
\r
6347 DisplayMoveError(char *str)
\r
6349 fromX = fromY = -1;
\r
6350 ClearHighlights();
\r
6351 DrawPosition(FALSE, NULL);
\r
6352 if (appData.popupMoveErrors) {
\r
6353 DisplayError(str, 0);
\r
6355 DisplayMessage(str, "");
\r
6356 moveErrorMessageUp = TRUE;
\r
6361 DisplayFatalError(char *str, int error, int exitStatus)
\r
6363 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
6365 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
6368 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
6369 NULL, error, LANG_NEUTRAL,
\r
6370 (LPSTR) buf2, MSG_SIZ, NULL);
\r
6372 sprintf(buf, "%s:\n%s", str, buf2);
\r
6374 ErrorMap *em = errmap;
\r
6375 while (em->err != 0 && em->err != error) em++;
\r
6376 if (em->err != 0) {
\r
6377 sprintf(buf, "%s:\n%s", str, em->msg);
\r
6379 sprintf(buf, "%s:\nError code %d", str, error);
\r
6384 if (appData.debugMode) {
\r
6385 fprintf(debugFP, "%s: %s\n", label, str);
\r
6387 if (appData.popupExitMessage) {
\r
6388 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
6389 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
6391 ExitEvent(exitStatus);
\r
6396 DisplayInformation(char *str)
\r
6398 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
6403 char *title, *question, *replyPrefix;
\r
6408 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6410 static QuestionParams *qp;
\r
6411 char reply[MSG_SIZ];
\r
6414 switch (message) {
\r
6415 case WM_INITDIALOG:
\r
6416 qp = (QuestionParams *) lParam;
\r
6417 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
6418 SetWindowText(hDlg, qp->title);
\r
6419 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
6420 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
6424 switch (LOWORD(wParam)) {
\r
6426 strcpy(reply, qp->replyPrefix);
\r
6427 if (*reply) strcat(reply, " ");
\r
6428 len = strlen(reply);
\r
6429 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
6430 strcat(reply, "\n");
\r
6431 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
6432 EndDialog(hDlg, TRUE);
\r
6433 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
6436 EndDialog(hDlg, FALSE);
\r
6447 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
6449 QuestionParams qp;
\r
6453 qp.question = question;
\r
6454 qp.replyPrefix = replyPrefix;
\r
6456 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
6457 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
6458 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
6459 FreeProcInstance(lpProc);
\r
6464 DisplayIcsInteractionTitle(char *str)
\r
6466 char consoleTitle[MSG_SIZ];
\r
6468 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
6469 SetWindowText(hwndConsole, consoleTitle);
\r
6473 DrawPosition(int fullRedraw, Board board)
\r
6475 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
6482 fromX = fromY = -1;
\r
6483 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
6484 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
6485 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
6486 dragInfo.lastpos = dragInfo.pos;
\r
6487 dragInfo.start.x = dragInfo.start.y = -1;
\r
6488 dragInfo.from = dragInfo.start;
\r
6490 DrawPosition(TRUE, NULL);
\r
6496 CommentPopUp(char *title, char *str)
\r
6498 HWND hwnd = GetActiveWindow();
\r
6499 EitherCommentPopUp(0, title, str, FALSE);
\r
6500 SetActiveWindow(hwnd);
\r
6504 CommentPopDown(void)
\r
6506 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
6507 if (commentDialog) {
\r
6508 ShowWindow(commentDialog, SW_HIDE);
\r
6510 commentDialogUp = FALSE;
\r
6514 EditCommentPopUp(int index, char *title, char *str)
\r
6516 EitherCommentPopUp(index, title, str, TRUE);
\r
6523 MyPlaySound(&sounds[(int)SoundMove]);
\r
6526 VOID PlayIcsWinSound()
\r
6528 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
6531 VOID PlayIcsLossSound()
\r
6533 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
6536 VOID PlayIcsDrawSound()
\r
6538 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
6541 VOID PlayIcsUnfinishedSound()
\r
6543 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
6549 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
6557 consoleEcho = TRUE;
\r
6558 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6559 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
6560 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6569 consoleEcho = FALSE;
\r
6570 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6571 /* This works OK: set text and background both to the same color */
\r
6573 cf.crTextColor = COLOR_ECHOOFF;
\r
6574 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6575 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
6578 /* No Raw()...? */
\r
6580 void Colorize(ColorClass cc, int continuation)
\r
6582 currentColorClass = cc;
\r
6583 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6584 consoleCF.crTextColor = textAttribs[cc].color;
\r
6585 consoleCF.dwEffects = textAttribs[cc].effects;
\r
6586 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
6592 static char buf[MSG_SIZ];
\r
6593 DWORD bufsiz = MSG_SIZ;
\r
6595 if (!GetUserName(buf, &bufsiz)) {
\r
6596 /*DisplayError("Error getting user name", GetLastError());*/
\r
6597 strcpy(buf, "User");
\r
6605 static char buf[MSG_SIZ];
\r
6606 DWORD bufsiz = MSG_SIZ;
\r
6608 if (!GetComputerName(buf, &bufsiz)) {
\r
6609 /*DisplayError("Error getting host name", GetLastError());*/
\r
6610 strcpy(buf, "Unknown");
\r
6617 ClockTimerRunning()
\r
6619 return clockTimerEvent != 0;
\r
6625 if (clockTimerEvent == 0) return FALSE;
\r
6626 KillTimer(hwndMain, clockTimerEvent);
\r
6627 clockTimerEvent = 0;
\r
6632 StartClockTimer(long millisec)
\r
6634 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
6635 (UINT) millisec, NULL);
\r
6639 DisplayWhiteClock(long timeRemaining, int highlight)
\r
6642 hdc = GetDC(hwndMain);
\r
6643 if (!IsIconic(hwndMain)) {
\r
6644 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");
\r
6646 if (highlight && iconCurrent == iconBlack) {
\r
6647 iconCurrent = iconWhite;
\r
6648 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6649 if (IsIconic(hwndMain)) {
\r
6650 DrawIcon(hdc, 2, 2, iconCurrent);
\r
6653 (void) ReleaseDC(hwndMain, hdc);
\r
6655 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6659 DisplayBlackClock(long timeRemaining, int highlight)
\r
6662 hdc = GetDC(hwndMain);
\r
6663 if (!IsIconic(hwndMain)) {
\r
6664 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");
\r
6666 if (highlight && iconCurrent == iconWhite) {
\r
6667 iconCurrent = iconBlack;
\r
6668 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6669 if (IsIconic(hwndMain)) {
\r
6670 DrawIcon(hdc, 2, 2, iconCurrent);
\r
6673 (void) ReleaseDC(hwndMain, hdc);
\r
6675 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6680 LoadGameTimerRunning()
\r
6682 return loadGameTimerEvent != 0;
\r
6686 StopLoadGameTimer()
\r
6688 if (loadGameTimerEvent == 0) return FALSE;
\r
6689 KillTimer(hwndMain, loadGameTimerEvent);
\r
6690 loadGameTimerEvent = 0;
\r
6695 StartLoadGameTimer(long millisec)
\r
6697 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
6698 (UINT) millisec, NULL);
\r
6706 char fileTitle[MSG_SIZ];
\r
6708 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
6709 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
6710 appData.oldSaveStyle ? "gam" : "pgn",
\r
6712 "Save Game to File", NULL, fileTitle, NULL);
\r
6714 SaveGame(f, 0, "");
\r
6721 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
6723 if (delayedTimerEvent != 0) {
\r
6724 if (appData.debugMode) {
\r
6725 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
6727 KillTimer(hwndMain, delayedTimerEvent);
\r
6728 delayedTimerEvent = 0;
\r
6729 delayedTimerCallback();
\r
6731 delayedTimerCallback = cb;
\r
6732 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
6733 (UINT) millisec, NULL);
\r
6736 DelayedEventCallback
\r
6739 if (delayedTimerEvent) {
\r
6740 return delayedTimerCallback;
\r
6747 CancelDelayedEvent()
\r
6749 if (delayedTimerEvent) {
\r
6750 KillTimer(hwndMain, delayedTimerEvent);
\r
6751 delayedTimerEvent = 0;
\r
6755 /* Start a child process running the given program.
\r
6756 The process's standard output can be read from "from", and its
\r
6757 standard input can be written to "to".
\r
6758 Exit with fatal error if anything goes wrong.
\r
6759 Returns an opaque pointer that can be used to destroy the process
\r
6763 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
6765 #define BUFSIZE 4096
\r
6767 HANDLE hChildStdinRd, hChildStdinWr,
\r
6768 hChildStdoutRd, hChildStdoutWr;
\r
6769 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
6770 SECURITY_ATTRIBUTES saAttr;
\r
6772 PROCESS_INFORMATION piProcInfo;
\r
6773 STARTUPINFO siStartInfo;
\r
6775 char buf[MSG_SIZ];
\r
6778 if (appData.debugMode) {
\r
6779 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
6784 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
6785 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
6786 saAttr.bInheritHandle = TRUE;
\r
6787 saAttr.lpSecurityDescriptor = NULL;
\r
6790 * The steps for redirecting child's STDOUT:
\r
6791 * 1. Create anonymous pipe to be STDOUT for child.
\r
6792 * 2. Create a noninheritable duplicate of read handle,
\r
6793 * and close the inheritable read handle.
\r
6796 /* Create a pipe for the child's STDOUT. */
\r
6797 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
6798 return GetLastError();
\r
6801 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
6802 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
6803 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
6804 FALSE, /* not inherited */
\r
6805 DUPLICATE_SAME_ACCESS);
\r
6807 return GetLastError();
\r
6809 CloseHandle(hChildStdoutRd);
\r
6812 * The steps for redirecting child's STDIN:
\r
6813 * 1. Create anonymous pipe to be STDIN for child.
\r
6814 * 2. Create a noninheritable duplicate of write handle,
\r
6815 * and close the inheritable write handle.
\r
6818 /* Create a pipe for the child's STDIN. */
\r
6819 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
6820 return GetLastError();
\r
6823 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
6824 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
6825 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
6826 FALSE, /* not inherited */
\r
6827 DUPLICATE_SAME_ACCESS);
\r
6829 return GetLastError();
\r
6831 CloseHandle(hChildStdinWr);
\r
6833 /* Arrange to (1) look in dir for the child .exe file, and
\r
6834 * (2) have dir be the child's working directory. Interpret
\r
6835 * dir relative to the directory WinBoard loaded from. */
\r
6836 GetCurrentDirectory(MSG_SIZ, buf);
\r
6837 SetCurrentDirectory(installDir);
\r
6838 SetCurrentDirectory(dir);
\r
6840 /* Now create the child process. */
\r
6842 siStartInfo.cb = sizeof(STARTUPINFO);
\r
6843 siStartInfo.lpReserved = NULL;
\r
6844 siStartInfo.lpDesktop = NULL;
\r
6845 siStartInfo.lpTitle = NULL;
\r
6846 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
6847 siStartInfo.cbReserved2 = 0;
\r
6848 siStartInfo.lpReserved2 = NULL;
\r
6849 siStartInfo.hStdInput = hChildStdinRd;
\r
6850 siStartInfo.hStdOutput = hChildStdoutWr;
\r
6851 siStartInfo.hStdError = hChildStdoutWr;
\r
6853 fSuccess = CreateProcess(NULL,
\r
6854 cmdLine, /* command line */
\r
6855 NULL, /* process security attributes */
\r
6856 NULL, /* primary thread security attrs */
\r
6857 TRUE, /* handles are inherited */
\r
6858 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
6859 NULL, /* use parent's environment */
\r
6861 &siStartInfo, /* STARTUPINFO pointer */
\r
6862 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
6864 err = GetLastError();
\r
6865 SetCurrentDirectory(buf); /* return to prev directory */
\r
6870 /* Close the handles we don't need in the parent */
\r
6871 CloseHandle(piProcInfo.hThread);
\r
6872 CloseHandle(hChildStdinRd);
\r
6873 CloseHandle(hChildStdoutWr);
\r
6875 /* Prepare return value */
\r
6876 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
6877 cp->kind = CPReal;
\r
6878 cp->hProcess = piProcInfo.hProcess;
\r
6879 cp->pid = piProcInfo.dwProcessId;
\r
6880 cp->hFrom = hChildStdoutRdDup;
\r
6881 cp->hTo = hChildStdinWrDup;
\r
6883 *pr = (void *) cp;
\r
6885 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
6886 2000 where engines sometimes don't see the initial command(s)
\r
6887 from WinBoard and hang. I don't understand how that can happen,
\r
6888 but the Sleep is harmless, so I've put it in. Others have also
\r
6889 reported what may be the same problem, so hopefully this will fix
\r
6890 it for them too. */
\r
6898 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
6902 cp = (ChildProc *) pr;
\r
6903 if (cp == NULL) return;
\r
6905 switch (cp->kind) {
\r
6907 /* TerminateProcess is considered harmful, so... */
\r
6908 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
6909 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
6910 /* The following doesn't work because the chess program
\r
6911 doesn't "have the same console" as WinBoard. Maybe
\r
6912 we could arrange for this even though neither WinBoard
\r
6913 nor the chess program uses a console for stdio? */
\r
6914 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
6915 CloseHandle(cp->hProcess);
\r
6919 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
6923 closesocket(cp->sock);
\r
6928 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
6929 closesocket(cp->sock);
\r
6930 closesocket(cp->sock2);
\r
6938 InterruptChildProcess(ProcRef pr)
\r
6942 cp = (ChildProc *) pr;
\r
6943 if (cp == NULL) return;
\r
6944 switch (cp->kind) {
\r
6946 /* The following doesn't work because the chess program
\r
6947 doesn't "have the same console" as WinBoard. Maybe
\r
6948 we could arrange for this even though neither WinBoard
\r
6949 nor the chess program uses a console for stdio */
\r
6950 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
6955 /* Can't interrupt */
\r
6959 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
6966 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
6968 char cmdLine[MSG_SIZ];
\r
6970 if (port[0] == NULLCHAR) {
\r
6971 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
6973 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
6975 return StartChildProcess(cmdLine, "", pr);
\r
6979 /* Code to open TCP sockets */
\r
6982 OpenTCP(char *host, char *port, ProcRef *pr)
\r
6987 struct sockaddr_in sa, mysa;
\r
6988 struct hostent FAR *hp;
\r
6989 unsigned short uport;
\r
6990 WORD wVersionRequested;
\r
6993 /* Initialize socket DLL */
\r
6994 wVersionRequested = MAKEWORD(1, 1);
\r
6995 err = WSAStartup(wVersionRequested, &wsaData);
\r
6996 if (err != 0) return err;
\r
6999 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7000 err = WSAGetLastError();
\r
7005 /* Bind local address using (mostly) don't-care values.
\r
7007 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7008 mysa.sin_family = AF_INET;
\r
7009 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7010 uport = (unsigned short) 0;
\r
7011 mysa.sin_port = htons(uport);
\r
7012 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7013 == SOCKET_ERROR) {
\r
7014 err = WSAGetLastError();
\r
7019 /* Resolve remote host name */
\r
7020 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7021 if (!(hp = gethostbyname(host))) {
\r
7022 unsigned int b0, b1, b2, b3;
\r
7024 err = WSAGetLastError();
\r
7026 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7027 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7028 hp->h_addrtype = AF_INET;
\r
7030 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7031 hp->h_addr_list[0] = (char *) malloc(4);
\r
7032 hp->h_addr_list[0][0] = (char) b0;
\r
7033 hp->h_addr_list[0][1] = (char) b1;
\r
7034 hp->h_addr_list[0][2] = (char) b2;
\r
7035 hp->h_addr_list[0][3] = (char) b3;
\r
7041 sa.sin_family = hp->h_addrtype;
\r
7042 uport = (unsigned short) atoi(port);
\r
7043 sa.sin_port = htons(uport);
\r
7044 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7046 /* Make connection */
\r
7047 if (connect(s, (struct sockaddr *) &sa,
\r
7048 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7049 err = WSAGetLastError();
\r
7054 /* Prepare return value */
\r
7055 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7056 cp->kind = CPSock;
\r
7058 *pr = (ProcRef *) cp;
\r
7064 OpenCommPort(char *name, ProcRef *pr)
\r
7069 char fullname[MSG_SIZ];
\r
7071 if (*name != '\\')
\r
7072 sprintf(fullname, "\\\\.\\%s", name);
\r
7074 strcpy(fullname, name);
\r
7076 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
7077 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
7078 if (h == (HANDLE) -1) {
\r
7079 return GetLastError();
\r
7083 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
7085 /* Accumulate characters until a 100ms pause, then parse */
\r
7086 ct.ReadIntervalTimeout = 100;
\r
7087 ct.ReadTotalTimeoutMultiplier = 0;
\r
7088 ct.ReadTotalTimeoutConstant = 0;
\r
7089 ct.WriteTotalTimeoutMultiplier = 0;
\r
7090 ct.WriteTotalTimeoutConstant = 0;
\r
7091 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
7093 /* Prepare return value */
\r
7094 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7095 cp->kind = CPComm;
\r
7098 *pr = (ProcRef *) cp;
\r
7104 OpenLoopback(ProcRef *pr)
\r
7106 DisplayFatalError("Not implemented", 0, 1);
\r
7112 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
7117 struct sockaddr_in sa, mysa;
\r
7118 struct hostent FAR *hp;
\r
7119 unsigned short uport;
\r
7120 WORD wVersionRequested;
\r
7123 char stderrPortStr[MSG_SIZ];
\r
7125 /* Initialize socket DLL */
\r
7126 wVersionRequested = MAKEWORD(1, 1);
\r
7127 err = WSAStartup(wVersionRequested, &wsaData);
\r
7128 if (err != 0) return err;
\r
7130 /* Resolve remote host name */
\r
7131 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7132 if (!(hp = gethostbyname(host))) {
\r
7133 unsigned int b0, b1, b2, b3;
\r
7135 err = WSAGetLastError();
\r
7137 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7138 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7139 hp->h_addrtype = AF_INET;
\r
7141 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7142 hp->h_addr_list[0] = (char *) malloc(4);
\r
7143 hp->h_addr_list[0][0] = (char) b0;
\r
7144 hp->h_addr_list[0][1] = (char) b1;
\r
7145 hp->h_addr_list[0][2] = (char) b2;
\r
7146 hp->h_addr_list[0][3] = (char) b3;
\r
7152 sa.sin_family = hp->h_addrtype;
\r
7153 uport = (unsigned short) 514;
\r
7154 sa.sin_port = htons(uport);
\r
7155 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7157 /* Bind local socket to unused "privileged" port address
\r
7159 s = INVALID_SOCKET;
\r
7160 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7161 mysa.sin_family = AF_INET;
\r
7162 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7163 for (fromPort = 1023;; fromPort--) {
\r
7164 if (fromPort < 0) {
\r
7166 return WSAEADDRINUSE;
\r
7168 if (s == INVALID_SOCKET) {
\r
7169 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7170 err = WSAGetLastError();
\r
7175 uport = (unsigned short) fromPort;
\r
7176 mysa.sin_port = htons(uport);
\r
7177 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7178 == SOCKET_ERROR) {
\r
7179 err = WSAGetLastError();
\r
7180 if (err == WSAEADDRINUSE) continue;
\r
7184 if (connect(s, (struct sockaddr *) &sa,
\r
7185 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7186 err = WSAGetLastError();
\r
7187 if (err == WSAEADDRINUSE) {
\r
7198 /* Bind stderr local socket to unused "privileged" port address
\r
7200 s2 = INVALID_SOCKET;
\r
7201 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7202 mysa.sin_family = AF_INET;
\r
7203 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7204 for (fromPort = 1023;; fromPort--) {
\r
7205 if (fromPort < 0) {
\r
7206 (void) closesocket(s);
\r
7208 return WSAEADDRINUSE;
\r
7210 if (s2 == INVALID_SOCKET) {
\r
7211 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7212 err = WSAGetLastError();
\r
7218 uport = (unsigned short) fromPort;
\r
7219 mysa.sin_port = htons(uport);
\r
7220 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7221 == SOCKET_ERROR) {
\r
7222 err = WSAGetLastError();
\r
7223 if (err == WSAEADDRINUSE) continue;
\r
7224 (void) closesocket(s);
\r
7228 if (listen(s2, 1) == SOCKET_ERROR) {
\r
7229 err = WSAGetLastError();
\r
7230 if (err == WSAEADDRINUSE) {
\r
7232 s2 = INVALID_SOCKET;
\r
7235 (void) closesocket(s);
\r
7236 (void) closesocket(s2);
\r
7242 sprintf(stderrPortStr, "%d", fromPort);
\r
7244 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
7245 err = WSAGetLastError();
\r
7246 (void) closesocket(s);
\r
7247 (void) closesocket(s2);
\r
7252 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
7253 err = WSAGetLastError();
\r
7254 (void) closesocket(s);
\r
7255 (void) closesocket(s2);
\r
7259 if (*user == NULLCHAR) user = UserName();
\r
7260 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
7261 err = WSAGetLastError();
\r
7262 (void) closesocket(s);
\r
7263 (void) closesocket(s2);
\r
7267 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
7268 err = WSAGetLastError();
\r
7269 (void) closesocket(s);
\r
7270 (void) closesocket(s2);
\r
7275 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
7276 err = WSAGetLastError();
\r
7277 (void) closesocket(s);
\r
7278 (void) closesocket(s2);
\r
7282 (void) closesocket(s2); /* Stop listening */
\r
7284 /* Prepare return value */
\r
7285 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7286 cp->kind = CPRcmd;
\r
7289 *pr = (ProcRef *) cp;
\r
7296 AddInputSource(ProcRef pr, int lineByLine,
\r
7297 InputCallback func, VOIDSTAR closure)
\r
7299 InputSource *is, *is2;
\r
7300 ChildProc *cp = (ChildProc *) pr;
\r
7302 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
7303 is->lineByLine = lineByLine;
\r
7305 is->closure = closure;
\r
7306 is->second = NULL;
\r
7307 is->next = is->buf;
\r
7308 if (pr == NoProc) {
\r
7309 is->kind = CPReal;
\r
7310 consoleInputSource = is;
\r
7312 is->kind = cp->kind;
\r
7313 switch (cp->kind) {
\r
7315 is->hFile = cp->hFrom;
\r
7316 cp->hFrom = NULL; /* now owned by InputThread */
\r
7318 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
7319 (LPVOID) is, 0, &is->id);
\r
7323 is->hFile = cp->hFrom;
\r
7324 cp->hFrom = NULL; /* now owned by InputThread */
\r
7326 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
7327 (LPVOID) is, 0, &is->id);
\r
7331 is->sock = cp->sock;
\r
7333 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7334 (LPVOID) is, 0, &is->id);
\r
7338 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
7340 is->sock = cp->sock;
\r
7342 is2->sock = cp->sock2;
\r
7343 is2->second = is2;
\r
7345 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7346 (LPVOID) is, 0, &is->id);
\r
7348 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7349 (LPVOID) is2, 0, &is2->id);
\r
7353 return (InputSourceRef) is;
\r
7357 RemoveInputSource(InputSourceRef isr)
\r
7361 is = (InputSource *) isr;
\r
7362 is->hThread = NULL; /* tell thread to stop */
\r
7363 CloseHandle(is->hThread);
\r
7364 if (is->second != NULL) {
\r
7365 is->second->hThread = NULL;
\r
7366 CloseHandle(is->second->hThread);
\r
7372 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
7375 int outCount = SOCKET_ERROR;
\r
7376 ChildProc *cp = (ChildProc *) pr;
\r
7377 static OVERLAPPED ovl;
\r
7379 if (pr == NoProc) {
\r
7380 ConsoleOutput(message, count, FALSE);
\r
7384 if (ovl.hEvent == NULL) {
\r
7385 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7387 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7389 switch (cp->kind) {
\r
7392 outCount = send(cp->sock, message, count, 0);
\r
7393 if (outCount == SOCKET_ERROR) {
\r
7394 *outError = WSAGetLastError();
\r
7396 *outError = NO_ERROR;
\r
7401 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
7402 &dOutCount, NULL)) {
\r
7403 *outError = NO_ERROR;
\r
7404 outCount = (int) dOutCount;
\r
7406 *outError = GetLastError();
\r
7411 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
7412 &dOutCount, &ovl);
\r
7413 if (*outError == NO_ERROR) {
\r
7414 outCount = (int) dOutCount;
\r
7422 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
7425 /* Ignore delay, not implemented for WinBoard */
\r
7426 return OutputToProcess(pr, message, count, outError);
\r
7431 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
7432 char *buf, int count, int error)
\r
7434 DisplayFatalError("Not implemented", 0, 1);
\r
7437 /* see wgamelist.c for Game List functions */
\r
7438 /* see wedittags.c for Edit Tags functions */
\r
7445 char buf[MSG_SIZ];
\r
7448 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
7449 f = fopen(buf, "r");
\r
7451 ProcessICSInitScript(f);
\r
7459 StartAnalysisClock()
\r
7461 if (analysisTimerEvent) return;
\r
7462 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
7463 (UINT) 2000, NULL);
\r
7467 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7469 static HANDLE hwndText;
\r
7471 static int sizeX, sizeY;
\r
7472 int newSizeX, newSizeY, flags;
\r
7475 switch (message) {
\r
7476 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7477 /* Initialize the dialog items */
\r
7478 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
7479 SetWindowText(hDlg, analysisTitle);
\r
7480 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
7481 /* Size and position the dialog */
\r
7482 if (!analysisDialog) {
\r
7483 analysisDialog = hDlg;
\r
7484 flags = SWP_NOZORDER;
\r
7485 GetClientRect(hDlg, &rect);
\r
7486 sizeX = rect.right;
\r
7487 sizeY = rect.bottom;
\r
7488 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
7489 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
7490 WINDOWPLACEMENT wp;
\r
7491 EnsureOnScreen(&analysisX, &analysisY);
\r
7492 wp.length = sizeof(WINDOWPLACEMENT);
\r
7494 wp.showCmd = SW_SHOW;
\r
7495 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7496 wp.rcNormalPosition.left = analysisX;
\r
7497 wp.rcNormalPosition.right = analysisX + analysisW;
\r
7498 wp.rcNormalPosition.top = analysisY;
\r
7499 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
7500 SetWindowPlacement(hDlg, &wp);
\r
7502 GetClientRect(hDlg, &rect);
\r
7503 newSizeX = rect.right;
\r
7504 newSizeY = rect.bottom;
\r
7505 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7506 newSizeX, newSizeY);
\r
7513 case WM_COMMAND: /* message: received a command */
\r
7514 switch (LOWORD(wParam)) {
\r
7524 newSizeX = LOWORD(lParam);
\r
7525 newSizeY = HIWORD(lParam);
\r
7526 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7531 case WM_GETMINMAXINFO:
\r
7532 /* Prevent resizing window too small */
\r
7533 mmi = (MINMAXINFO *) lParam;
\r
7534 mmi->ptMinTrackSize.x = 100;
\r
7535 mmi->ptMinTrackSize.y = 100;
\r
7542 AnalysisPopUp(char* title, char* str)
\r
7547 if (str == NULL) str = "";
\r
7548 p = (char *) malloc(2 * strlen(str) + 2);
\r
7551 if (*str == '\n') *q++ = '\r';
\r
7555 if (analysisText != NULL) free(analysisText);
\r
7558 if (analysisDialog) {
\r
7559 SetWindowText(analysisDialog, title);
\r
7560 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
7561 ShowWindow(analysisDialog, SW_SHOW);
\r
7563 analysisTitle = title;
\r
7564 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
7565 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
7566 hwndMain, (DLGPROC)lpProc);
\r
7567 FreeProcInstance(lpProc);
\r
7569 analysisDialogUp = TRUE;
\r
7575 if (analysisDialog) {
\r
7576 ShowWindow(analysisDialog, SW_HIDE);
\r
7578 analysisDialogUp = FALSE;
\r
7583 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
7585 highlightInfo.sq[0].x = fromX;
\r
7586 highlightInfo.sq[0].y = fromY;
\r
7587 highlightInfo.sq[1].x = toX;
\r
7588 highlightInfo.sq[1].y = toY;
\r
7594 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
7595 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
7599 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
7601 premoveHighlightInfo.sq[0].x = fromX;
\r
7602 premoveHighlightInfo.sq[0].y = fromY;
\r
7603 premoveHighlightInfo.sq[1].x = toX;
\r
7604 premoveHighlightInfo.sq[1].y = toY;
\r
7608 ClearPremoveHighlights()
\r
7610 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
7611 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
7615 ShutDownFrontEnd()
\r
7617 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
7618 DeleteClipboardTempFiles();
\r
7624 if (IsIconic(hwndMain))
\r
7625 ShowWindow(hwndMain, SW_RESTORE);
\r
7627 SetActiveWindow(hwndMain);
\r
7631 * Prototypes for animation support routines
\r
7633 static void ScreenSquare(int column, int row, POINT * pt);
\r
7634 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
7635 POINT frames[], int * nFrames);
\r
7641 AnimateMove(board, fromX, fromY, toX, toY)
\r
7648 ChessSquare piece;
\r
7649 POINT start, finish, mid;
\r
7650 POINT frames[kFactor * 2 + 1];
\r
7653 if (!appData.animate) return;
\r
7654 if (doingSizing) return;
\r
7655 if (fromY < 0 || fromX < 0) return;
\r
7656 piece = board[fromY][fromX];
\r
7657 if (piece >= EmptySquare) return;
\r
7659 ScreenSquare(fromX, fromY, &start);
\r
7660 ScreenSquare(toX, toY, &finish);
\r
7662 /* All pieces except knights move in straight line */
\r
7663 if (piece != WhiteKnight && piece != BlackKnight) {
\r
7664 mid.x = start.x + (finish.x - start.x) / 2;
\r
7665 mid.y = start.y + (finish.y - start.y) / 2;
\r
7667 /* Knight: make diagonal movement then straight */
\r
7668 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
7669 mid.x = start.x + (finish.x - start.x) / 2;
\r
7673 mid.y = start.y + (finish.y - start.y) / 2;
\r
7677 /* Don't use as many frames for very short moves */
\r
7678 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
7679 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
7681 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
7683 animInfo.from.x = fromX;
\r
7684 animInfo.from.y = fromY;
\r
7685 animInfo.to.x = toX;
\r
7686 animInfo.to.y = toY;
\r
7687 animInfo.lastpos = start;
\r
7688 animInfo.piece = piece;
\r
7689 for (n = 0; n < nFrames; n++) {
\r
7690 animInfo.pos = frames[n];
\r
7691 DrawPosition(FALSE, NULL);
\r
7692 animInfo.lastpos = animInfo.pos;
\r
7693 Sleep(appData.animSpeed);
\r
7695 animInfo.pos = finish;
\r
7696 DrawPosition(FALSE, NULL);
\r
7697 animInfo.piece = EmptySquare;
\r
7700 /* Convert board position to corner of screen rect and color */
\r
7703 ScreenSquare(column, row, pt)
\r
7704 int column; int row; POINT * pt;
\r
7707 pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
7708 pt->y = lineGap + row * (squareSize + lineGap);
\r
7710 pt->x = lineGap + column * (squareSize + lineGap);
\r
7711 pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
7715 /* Generate a series of frame coords from start->mid->finish.
\r
7716 The movement rate doubles until the half way point is
\r
7717 reached, then halves back down to the final destination,
\r
7718 which gives a nice slow in/out effect. The algorithmn
\r
7719 may seem to generate too many intermediates for short
\r
7720 moves, but remember that the purpose is to attract the
\r
7721 viewers attention to the piece about to be moved and
\r
7722 then to where it ends up. Too few frames would be less
\r
7726 Tween(start, mid, finish, factor, frames, nFrames)
\r
7727 POINT * start; POINT * mid;
\r
7728 POINT * finish; int factor;
\r
7729 POINT frames[]; int * nFrames;
\r
7731 int n, fraction = 1, count = 0;
\r
7733 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
7734 for (n = 0; n < factor; n++)
\r
7736 for (n = 0; n < factor; n++) {
\r
7737 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
7738 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
7740 fraction = fraction / 2;
\r
7744 frames[count] = *mid;
\r
7747 /* Slow out, stepping 1/2, then 1/4, ... */
\r
7749 for (n = 0; n < factor; n++) {
\r
7750 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
7751 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
7753 fraction = fraction * 2;
\r
7759 HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current)
\r
7761 /* Currently not implemented in WinBoard */
\r