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
56 #include <winsock.h>
\r
61 #include <sys/stat.h>
\r
64 #include <commdlg.h>
\r
66 #include <richedit.h>
\r
67 #include <mmsystem.h>
\r
75 #include "winboard.h"
\r
76 #include "frontend.h"
\r
77 #include "backend.h"
\r
79 #include "wclipbrd.h"
\r
80 #include "wgamelist.h"
\r
81 #include "wedittags.h"
\r
82 #include "woptions.h"
\r
83 #include "wsockerr.h"
\r
84 #include "defaults.h"
\r
88 POINT pos; /* window coordinates of current pos */
\r
89 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
90 POINT from; /* board coordinates of the piece's orig pos */
\r
91 POINT to; /* board coordinates of the piece's new pos */
\r
94 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
97 POINT start; /* window coordinates of start pos */
\r
98 POINT pos; /* window coordinates of current pos */
\r
99 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
100 POINT from; /* board coordinates of the piece's orig pos */
\r
103 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
106 POINT sq[2]; /* board coordinates of from, to squares */
\r
109 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
110 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
112 /* Window class names */
\r
113 char szAppName[] = "WinBoard";
\r
114 char szConsoleName[] = "WBConsole";
\r
116 /* Title bar text */
\r
117 char szTitle[] = "WinBoard";
\r
118 char szConsoleTitle[] = "ICS Interaction";
\r
121 char *settingsFileName;
\r
122 BOOLEAN saveSettingsOnExit;
\r
123 char installDir[MSG_SIZ];
\r
125 BoardSize boardSize;
\r
126 BOOLEAN chessProgram;
\r
127 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
128 static int squareSize, lineGap;
\r
129 static int winWidth, winHeight;
\r
130 static RECT messageRect, whiteRect, blackRect;
\r
131 static char messageText[MESSAGE_TEXT_MAX];
\r
132 static int clockTimerEvent = 0;
\r
133 static int loadGameTimerEvent = 0;
\r
134 static int analysisTimerEvent = 0;
\r
135 static DelayedEventCallback delayedTimerCallback;
\r
136 static int delayedTimerEvent = 0;
\r
137 static int buttonCount = 2;
\r
138 char *icsTextMenuString;
\r
140 char *firstChessProgramNames;
\r
141 char *secondChessProgramNames;
\r
143 #define ARG_MAX 20000
\r
145 #define PALETTESIZE 256
\r
147 HINSTANCE hInst; /* current instance */
\r
148 HWND hwndMain = NULL; /* root window*/
\r
149 HWND hwndConsole = NULL;
\r
150 BOOLEAN alwaysOnTop = FALSE;
\r
152 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
153 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
155 ColorClass currentColorClass;
\r
157 HWND hCommPort = NULL; /* currently open comm port */
\r
158 static HWND hwndPause; /* pause button */
\r
159 static HBITMAP pieceBitmap[3][(int) WhiteKing + 1];
\r
160 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
161 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
162 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
163 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
164 static HPEN gridPen = NULL;
\r
165 static HPEN highlightPen = NULL;
\r
166 static HPEN premovePen = NULL;
\r
167 static NPLOGPALETTE pLogPal;
\r
168 static BOOL paletteChanged = FALSE;
\r
169 static HICON iconWhite, iconBlack, iconCurrent;
\r
170 static int doingSizing = FALSE;
\r
171 static int lastSizing = 0;
\r
172 static int prevStderrPort;
\r
174 #if __GNUC__ && !defined(_winmajor)
\r
175 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
177 #define oldDialog (_winmajor < 4)
\r
180 char *defaultTextAttribs[] =
\r
182 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
183 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
193 int cliWidth, cliHeight;
\r
196 SizeInfo sizeInfo[] =
\r
198 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
199 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
200 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
201 { "petite", 33, 1, 1, 1, 0, 0 },
\r
202 { "slim", 37, 2, 1, 0, 0, 0 },
\r
203 { "small", 40, 2, 1, 0, 0, 0 },
\r
204 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
205 { "middling", 49, 2, 0, 0, 0, 0 },
\r
206 { "average", 54, 2, 0, 0, 0, 0 },
\r
207 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
208 { "medium", 64, 3, 0, 0, 0, 0 },
\r
209 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
210 { "large", 80, 3, 0, 0, 0, 0 },
\r
211 { "big", 87, 3, 0, 0, 0, 0 },
\r
212 { "huge", 95, 3, 0, 0, 0, 0 },
\r
213 { "giant", 108, 3, 0, 0, 0, 0 },
\r
214 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
215 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
216 { NULL, 0, 0, 0, 0, 0, 0 }
\r
219 #define MF(x) {x, {0, }, {0, }, 0}
\r
220 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
222 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY),
\r
223 MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY),
\r
224 MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY) },
\r
225 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY),
\r
226 MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY),
\r
227 MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY) },
\r
228 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY),
\r
229 MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY),
\r
230 MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY) },
\r
231 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE),
\r
232 MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE),
\r
233 MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE) },
\r
234 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM),
\r
235 MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM),
\r
236 MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM) },
\r
237 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL),
\r
238 MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL),
\r
239 MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL) },
\r
240 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE),
\r
241 MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE),
\r
242 MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE) },
\r
243 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING),
\r
244 MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING),
\r
245 MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING) },
\r
246 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE),
\r
247 MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE),
\r
248 MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE) },
\r
249 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE),
\r
250 MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE),
\r
251 MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE) },
\r
252 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM),
\r
253 MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM),
\r
254 MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM) },
\r
255 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY),
\r
256 MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY),
\r
257 MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY) },
\r
258 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE),
\r
259 MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE),
\r
260 MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE) },
\r
261 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG),
\r
262 MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG),
\r
263 MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG) },
\r
264 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE),
\r
265 MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE),
\r
266 MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE) },
\r
267 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT),
\r
268 MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT),
\r
269 MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT) },
\r
270 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL),
\r
271 MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL),
\r
272 MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL) },
\r
273 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC),
\r
274 MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC),
\r
275 MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC) },
\r
278 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
287 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
288 #define N_BUTTONS 5
\r
290 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
292 {"<<", IDM_ToStart, NULL, NULL},
\r
293 {"<", IDM_Backward, NULL, NULL},
\r
294 {"P", IDM_Pause, NULL, NULL},
\r
295 {">", IDM_Forward, NULL, NULL},
\r
296 {">>", IDM_ToEnd, NULL, NULL},
\r
299 int tinyLayout = 0, smallLayout = 0;
\r
300 #define MENU_BAR_ITEMS 6
\r
301 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
302 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
303 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
307 MySound sounds[(int)NSoundClasses];
\r
308 MyTextAttribs textAttribs[(int)NColorClasses];
\r
310 MyColorizeAttribs colorizeAttribs[] = {
\r
311 { (COLORREF)0, 0, "Shout Text" },
\r
312 { (COLORREF)0, 0, "SShout/CShout" },
\r
313 { (COLORREF)0, 0, "Channel 1 Text" },
\r
314 { (COLORREF)0, 0, "Channel Text" },
\r
315 { (COLORREF)0, 0, "Kibitz Text" },
\r
316 { (COLORREF)0, 0, "Tell Text" },
\r
317 { (COLORREF)0, 0, "Challenge Text" },
\r
318 { (COLORREF)0, 0, "Request Text" },
\r
319 { (COLORREF)0, 0, "Seek Text" },
\r
320 { (COLORREF)0, 0, "Normal Text" },
\r
321 { (COLORREF)0, 0, "None" }
\r
326 static char *commentTitle;
\r
327 static char *commentText;
\r
328 static int commentIndex;
\r
329 static Boolean editComment = FALSE;
\r
330 HWND commentDialog = NULL;
\r
331 BOOLEAN commentDialogUp = FALSE;
\r
332 static int commentX, commentY, commentH, commentW;
\r
334 static char *analysisTitle;
\r
335 static char *analysisText;
\r
336 HWND analysisDialog = NULL;
\r
337 BOOLEAN analysisDialogUp = FALSE;
\r
338 static int analysisX, analysisY, analysisH, analysisW;
\r
340 char errorMessage[2*MSG_SIZ];
\r
341 HWND errorDialog = NULL;
\r
342 BOOLEAN moveErrorMessageUp = FALSE;
\r
343 BOOLEAN consoleEcho = TRUE;
\r
344 CHARFORMAT consoleCF;
\r
345 COLORREF consoleBackgroundColor;
\r
347 char *programVersion;
\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 gameInfo.variant == VariantGiveaway) ?
\r
3251 SW_SHOW : SW_HIDE);
\r
3254 case WM_COMMAND: /* message: received a command */
\r
3255 switch (LOWORD(wParam)) {
\r
3257 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3258 ClearHighlights();
\r
3259 DrawPosition(FALSE, NULL);
\r
3279 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3280 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
3281 if (!appData.highlightLastMove) {
\r
3282 ClearHighlights();
\r
3283 DrawPosition(FALSE, NULL);
\r
3290 /* Pop up promotion dialog */
\r
3292 PromotionPopup(HWND hwnd)
\r
3296 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
3297 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
3298 hwnd, (DLGPROC)lpProc);
\r
3299 FreeProcInstance(lpProc);
\r
3302 /* Toggle ShowThinking */
\r
3304 ToggleShowThinking()
\r
3306 ShowThinkingEvent(!appData.showThinking);
\r
3310 LoadGameDialog(HWND hwnd, char* title)
\r
3314 char fileTitle[MSG_SIZ];
\r
3315 f = OpenFileDialog(hwnd, FALSE, "",
\r
3316 appData.oldSaveStyle ? "gam" : "pgn",
\r
3318 title, &number, fileTitle, NULL);
\r
3320 cmailMsgLoaded = FALSE;
\r
3321 if (number == 0) {
\r
3322 int error = GameListBuild(f);
\r
3324 DisplayError("Cannot build game list", error);
\r
3325 } else if (!ListEmpty(&gameList) &&
\r
3326 ((ListGame *) gameList.tailPred)->number > 1) {
\r
3327 GameListPopUp(f, fileTitle);
\r
3330 GameListDestroy();
\r
3333 LoadGame(f, number, fileTitle, FALSE);
\r
3338 ChangedConsoleFont()
\r
3341 CHARRANGE tmpsel, sel;
\r
3342 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
3343 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3344 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3347 cfmt.cbSize = sizeof(CHARFORMAT);
\r
3348 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
3349 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
3350 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
3351 * size. This was undocumented in the version of MSVC++ that I had
\r
3352 * when I wrote the code, but is apparently documented now.
\r
3354 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
3355 cfmt.bCharSet = f->lf.lfCharSet;
\r
3356 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
3357 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
3358 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
3359 /* Why are the following seemingly needed too? */
\r
3360 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
3361 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
3362 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
3364 tmpsel.cpMax = -1; /*999999?*/
\r
3365 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
3366 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
3367 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
3368 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
3370 paraf.cbSize = sizeof(paraf);
\r
3371 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
3372 paraf.dxStartIndent = 0;
\r
3373 paraf.dxOffset = WRAP_INDENT;
\r
3374 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
3375 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
3378 /*---------------------------------------------------------------------------*\
\r
3380 * Window Proc for main window
\r
3382 \*---------------------------------------------------------------------------*/
\r
3384 /* Process messages for main window, etc. */
\r
3386 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3389 int wmId, wmEvent;
\r
3393 char fileTitle[MSG_SIZ];
\r
3395 switch (message) {
\r
3397 case WM_PAINT: /* message: repaint portion of window */
\r
3401 case WM_ERASEBKGND:
\r
3402 if (IsIconic(hwnd)) {
\r
3403 /* Cheat; change the message */
\r
3404 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
3406 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
3410 case WM_LBUTTONDOWN:
\r
3411 case WM_MBUTTONDOWN:
\r
3412 case WM_RBUTTONDOWN:
\r
3413 case WM_LBUTTONUP:
\r
3414 case WM_MBUTTONUP:
\r
3415 case WM_RBUTTONUP:
\r
3416 case WM_MOUSEMOVE:
\r
3417 MouseEvent(hwnd, message, wParam, lParam);
\r
3422 if (appData.icsActive) {
\r
3423 if (wParam == '\t') {
\r
3424 if (GetKeyState(VK_SHIFT) < 0) {
\r
3426 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3427 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3431 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3432 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3436 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3437 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3439 SendMessage(h, message, wParam, lParam);
\r
3441 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
3442 PopUpMoveDialog((char)wParam);
\r
3446 case WM_PALETTECHANGED:
\r
3447 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
3449 HDC hdc = GetDC(hwndMain);
\r
3450 SelectPalette(hdc, hPal, TRUE);
\r
3451 nnew = RealizePalette(hdc);
\r
3453 paletteChanged = TRUE;
\r
3455 UpdateColors(hdc);
\r
3457 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
3460 ReleaseDC(hwnd, hdc);
\r
3464 case WM_QUERYNEWPALETTE:
\r
3465 if (!appData.monoMode /*&& paletteChanged*/) {
\r
3467 HDC hdc = GetDC(hwndMain);
\r
3468 paletteChanged = FALSE;
\r
3469 SelectPalette(hdc, hPal, FALSE);
\r
3470 nnew = RealizePalette(hdc);
\r
3472 InvalidateRect(hwnd, &boardRect, FALSE);
\r
3474 ReleaseDC(hwnd, hdc);
\r
3479 case WM_COMMAND: /* message: command from application menu */
\r
3480 wmId = LOWORD(wParam);
\r
3481 wmEvent = HIWORD(wParam);
\r
3486 AnalysisPopDown();
\r
3489 case IDM_LoadGame:
\r
3490 LoadGameDialog(hwnd, "Load Game from File");
\r
3493 case IDM_LoadNextGame:
\r
3497 case IDM_LoadPrevGame:
\r
3501 case IDM_ReloadGame:
\r
3505 case IDM_LoadPosition:
\r
3506 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
3507 Reset(FALSE, TRUE);
\r
3510 f = OpenFileDialog(hwnd, FALSE, "",
\r
3511 appData.oldSaveStyle ? "pos" : "fen",
\r
3513 "Load Position from File", &number, fileTitle, NULL);
\r
3515 LoadPosition(f, number, fileTitle);
\r
3519 case IDM_LoadNextPosition:
\r
3520 ReloadPosition(1);
\r
3523 case IDM_LoadPrevPosition:
\r
3524 ReloadPosition(-1);
\r
3527 case IDM_ReloadPosition:
\r
3528 ReloadPosition(0);
\r
3531 case IDM_SaveGame:
\r
3532 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
3533 f = OpenFileDialog(hwnd, TRUE, defName,
\r
3534 appData.oldSaveStyle ? "gam" : "pgn",
\r
3536 "Save Game to File", NULL, fileTitle, NULL);
\r
3538 SaveGame(f, 0, "");
\r
3542 case IDM_SavePosition:
\r
3543 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
3544 f = OpenFileDialog(hwnd, TRUE, defName,
\r
3545 appData.oldSaveStyle ? "pos" : "fen",
\r
3547 "Save Position to File", NULL, fileTitle, NULL);
\r
3549 SavePosition(f, 0, "");
\r
3553 case IDM_CopyGame:
\r
3554 CopyGameToClipboard();
\r
3557 case IDM_PasteGame:
\r
3558 PasteGameFromClipboard();
\r
3561 case IDM_CopyPosition:
\r
3562 CopyFENToClipboard();
\r
3565 case IDM_PastePosition:
\r
3566 PasteFENFromClipboard();
\r
3569 case IDM_MailMove:
\r
3573 case IDM_ReloadCMailMsg:
\r
3574 Reset(TRUE, TRUE);
\r
3575 ReloadCmailMsgEvent(FALSE);
\r
3578 case IDM_Minimize:
\r
3579 ShowWindow(hwnd, SW_MINIMIZE);
\r
3586 case IDM_MachineWhite:
\r
3587 MachineWhiteEvent();
\r
3589 * refresh the tags dialog only if it's visible
\r
3591 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
3593 tags = PGNTags(&gameInfo);
\r
3594 TagsPopUp(tags, CmailMsg());
\r
3599 case IDM_MachineBlack:
\r
3600 MachineBlackEvent();
\r
3602 * refresh the tags dialog only if it's visible
\r
3604 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
3606 tags = PGNTags(&gameInfo);
\r
3607 TagsPopUp(tags, CmailMsg());
\r
3612 case IDM_TwoMachines:
\r
3613 TwoMachinesEvent();
\r
3615 * refresh the tags dialog only if it's visible
\r
3617 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
3619 tags = PGNTags(&gameInfo);
\r
3620 TagsPopUp(tags, CmailMsg());
\r
3625 case IDM_AnalysisMode:
\r
3626 if (!first.analysisSupport) {
\r
3627 char buf[MSG_SIZ];
\r
3628 sprintf(buf, "%s does not support analysis", first.tidy);
\r
3629 DisplayError(buf, 0);
\r
3631 if (!appData.showThinking) ToggleShowThinking();
\r
3632 AnalyzeModeEvent();
\r
3636 case IDM_AnalyzeFile:
\r
3637 if (!first.analysisSupport) {
\r
3638 char buf[MSG_SIZ];
\r
3639 sprintf(buf, "%s does not support analysis", first.tidy);
\r
3640 DisplayError(buf, 0);
\r
3642 if (!appData.showThinking) ToggleShowThinking();
\r
3643 AnalyzeFileEvent();
\r
3644 LoadGameDialog(hwnd, "Analyze Game from File");
\r
3645 AnalysisPeriodicEvent(1);
\r
3649 case IDM_IcsClient:
\r
3653 case IDM_EditGame:
\r
3657 case IDM_EditPosition:
\r
3658 EditPositionEvent();
\r
3661 case IDM_Training:
\r
3665 case IDM_ShowGameList:
\r
3666 ShowGameListProc();
\r
3669 case IDM_EditTags:
\r
3673 case IDM_EditComment:
\r
3674 if (commentDialogUp && editComment) {
\r
3677 EditCommentEvent();
\r
3697 case IDM_CallFlag:
\r
3717 case IDM_StopObserving:
\r
3718 StopObservingEvent();
\r
3721 case IDM_StopExamining:
\r
3722 StopExaminingEvent();
\r
3725 case IDM_TypeInMove:
\r
3726 PopUpMoveDialog('\000');
\r
3729 case IDM_Backward:
\r
3731 SetFocus(hwndMain);
\r
3736 SetFocus(hwndMain);
\r
3741 SetFocus(hwndMain);
\r
3746 SetFocus(hwndMain);
\r
3753 case IDM_TruncateGame:
\r
3754 TruncateGameEvent();
\r
3761 case IDM_RetractMove:
\r
3762 RetractMoveEvent();
\r
3765 case IDM_FlipView:
\r
3766 flipView = !flipView;
\r
3767 DrawPosition(FALSE, NULL);
\r
3770 case IDM_GeneralOptions:
\r
3771 GeneralOptionsPopup(hwnd);
\r
3774 case IDM_BoardOptions:
\r
3775 BoardOptionsPopup(hwnd);
\r
3778 case IDM_IcsOptions:
\r
3779 IcsOptionsPopup(hwnd);
\r
3783 FontsOptionsPopup(hwnd);
\r
3787 SoundOptionsPopup(hwnd);
\r
3790 case IDM_CommPort:
\r
3791 CommPortOptionsPopup(hwnd);
\r
3794 case IDM_LoadOptions:
\r
3795 LoadOptionsPopup(hwnd);
\r
3798 case IDM_SaveOptions:
\r
3799 SaveOptionsPopup(hwnd);
\r
3802 case IDM_TimeControl:
\r
3803 TimeControlOptionsPopup(hwnd);
\r
3806 case IDM_SaveSettings:
\r
3807 SaveSettings(settingsFileName);
\r
3810 case IDM_SaveSettingsOnExit:
\r
3811 saveSettingsOnExit = !saveSettingsOnExit;
\r
3812 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
3813 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
3814 MF_CHECKED : MF_UNCHECKED));
\r
3825 case IDM_AboutGame:
\r
3830 appData.debugMode = !appData.debugMode;
\r
3831 if (appData.debugMode) {
\r
3832 char dir[MSG_SIZ];
\r
3833 GetCurrentDirectory(MSG_SIZ, dir);
\r
3834 SetCurrentDirectory(installDir);
\r
3835 debugFP = fopen("WinBoard.debug", "w");
\r
3836 SetCurrentDirectory(dir);
\r
3837 setbuf(debugFP, NULL);
\r
3844 case IDM_HELPCONTENTS:
\r
3845 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
3846 MessageBox (GetFocus(),
\r
3847 "Unable to activate help",
\r
3848 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3852 case IDM_HELPSEARCH:
\r
3853 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
3854 MessageBox (GetFocus(),
\r
3855 "Unable to activate help",
\r
3856 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3860 case IDM_HELPHELP:
\r
3861 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
3862 MessageBox (GetFocus(),
\r
3863 "Unable to activate help",
\r
3864 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3869 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
3871 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
3872 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
3873 FreeProcInstance(lpProc);
\r
3876 case IDM_DirectCommand1:
\r
3877 AskQuestionEvent("Direct Command",
\r
3878 "Send to chess program:", "", "1");
\r
3880 case IDM_DirectCommand2:
\r
3881 AskQuestionEvent("Direct Command",
\r
3882 "Send to second chess program:", "", "2");
\r
3885 case EP_WhitePawn:
\r
3886 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
3887 fromX = fromY = -1;
\r
3890 case EP_WhiteKnight:
\r
3891 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
3892 fromX = fromY = -1;
\r
3895 case EP_WhiteBishop:
\r
3896 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
3897 fromX = fromY = -1;
\r
3900 case EP_WhiteRook:
\r
3901 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
3902 fromX = fromY = -1;
\r
3905 case EP_WhiteQueen:
\r
3906 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
3907 fromX = fromY = -1;
\r
3910 case EP_WhiteKing:
\r
3911 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
3912 fromX = fromY = -1;
\r
3915 case EP_BlackPawn:
\r
3916 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
3917 fromX = fromY = -1;
\r
3920 case EP_BlackKnight:
\r
3921 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
3922 fromX = fromY = -1;
\r
3925 case EP_BlackBishop:
\r
3926 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
3927 fromX = fromY = -1;
\r
3930 case EP_BlackRook:
\r
3931 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
3932 fromX = fromY = -1;
\r
3935 case EP_BlackQueen:
\r
3936 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
3937 fromX = fromY = -1;
\r
3940 case EP_BlackKing:
\r
3941 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
3942 fromX = fromY = -1;
\r
3945 case EP_EmptySquare:
\r
3946 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
3947 fromX = fromY = -1;
\r
3950 case EP_ClearBoard:
\r
3951 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
3952 fromX = fromY = -1;
\r
3956 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
3957 fromX = fromY = -1;
\r
3961 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
3962 fromX = fromY = -1;
\r
3966 DropMenuEvent(WhitePawn, fromX, fromY);
\r
3967 fromX = fromY = -1;
\r
3971 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
3972 fromX = fromY = -1;
\r
3976 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
3977 fromX = fromY = -1;
\r
3981 DropMenuEvent(WhiteRook, fromX, fromY);
\r
3982 fromX = fromY = -1;
\r
3986 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
3987 fromX = fromY = -1;
\r
3991 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
3997 case CLOCK_TIMER_ID:
\r
3998 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
3999 clockTimerEvent = 0;
\r
4000 DecrementClocks(); /* call into back end */
\r
4002 case LOAD_GAME_TIMER_ID:
\r
4003 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
4004 loadGameTimerEvent = 0;
\r
4005 AutoPlayGameLoop(); /* call into back end */
\r
4007 case ANALYSIS_TIMER_ID:
\r
4008 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
4009 appData.periodicUpdates) {
\r
4010 AnalysisPeriodicEvent(0);
\r
4012 KillTimer(hwnd, analysisTimerEvent);
\r
4013 analysisTimerEvent = 0;
\r
4016 case DELAYED_TIMER_ID:
\r
4017 KillTimer(hwnd, delayedTimerEvent);
\r
4018 delayedTimerEvent = 0;
\r
4019 delayedTimerCallback();
\r
4024 case WM_USER_Input:
\r
4025 InputEvent(hwnd, message, wParam, lParam);
\r
4028 case WM_ENTERSIZEMOVE:
\r
4029 if (hwnd == hwndMain) {
\r
4030 doingSizing = TRUE;
\r
4036 if (hwnd == hwndMain) {
\r
4037 lastSizing = wParam;
\r
4041 case WM_EXITSIZEMOVE:
\r
4042 if (hwnd == hwndMain) {
\r
4044 doingSizing = FALSE;
\r
4045 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4046 GetClientRect(hwnd, &client);
\r
4047 ResizeBoard(client.right, client.bottom, lastSizing);
\r
4052 case WM_DESTROY: /* message: window being destroyed */
\r
4053 PostQuitMessage(0);
\r
4057 if (hwnd == hwndMain) {
\r
4062 default: /* Passes it on if unprocessed */
\r
4063 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4068 /*---------------------------------------------------------------------------*\
\r
4070 * Misc utility routines
\r
4072 \*---------------------------------------------------------------------------*/
\r
4075 * returns TRUE if user selects a different color, FALSE otherwise
\r
4079 ChangeColor(HWND hwnd, COLORREF *which)
\r
4081 static BOOL firstTime = TRUE;
\r
4082 static DWORD customColors[16];
\r
4084 COLORREF newcolor;
\r
4089 /* Make initial colors in use available as custom colors */
\r
4090 /* Should we put the compiled-in defaults here instead? */
\r
4092 customColors[i++] = lightSquareColor & 0xffffff;
\r
4093 customColors[i++] = darkSquareColor & 0xffffff;
\r
4094 customColors[i++] = whitePieceColor & 0xffffff;
\r
4095 customColors[i++] = blackPieceColor & 0xffffff;
\r
4096 customColors[i++] = highlightSquareColor & 0xffffff;
\r
4097 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
4099 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
4100 customColors[i++] = textAttribs[ccl].color;
\r
4102 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
4103 firstTime = FALSE;
\r
4106 cc.lStructSize = sizeof(cc);
\r
4107 cc.hwndOwner = hwnd;
\r
4108 cc.hInstance = NULL;
\r
4109 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
4110 cc.lpCustColors = (LPDWORD) customColors;
\r
4111 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
4113 if (!ChooseColor(&cc)) return FALSE;
\r
4115 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
4116 if (newcolor == *which) return FALSE;
\r
4117 *which = newcolor;
\r
4121 InitDrawingColors();
\r
4122 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4127 MyLoadSound(MySound *ms)
\r
4133 if (ms->data) free(ms->data);
\r
4136 switch (ms->name[0]) {
\r
4142 /* System sound from Control Panel. Don't preload here. */
\r
4146 if (ms->name[1] == NULLCHAR) {
\r
4147 /* "!" alone = silence */
\r
4150 /* Builtin wave resource. Error if not found. */
\r
4151 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
4152 if (h == NULL) break;
\r
4153 ms->data = (void *)LoadResource(hInst, h);
\r
4154 if (h == NULL) break;
\r
4159 /* .wav file. Error if not found. */
\r
4160 f = fopen(ms->name, "rb");
\r
4161 if (f == NULL) break;
\r
4162 if (fstat(fileno(f), &st) < 0) break;
\r
4163 ms->data = malloc(st.st_size);
\r
4164 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
4170 char buf[MSG_SIZ];
\r
4171 sprintf(buf, "Error loading sound %s", ms->name);
\r
4172 DisplayError(buf, GetLastError());
\r
4178 MyPlaySound(MySound *ms)
\r
4180 BOOLEAN ok = FALSE;
\r
4181 switch (ms->name[0]) {
\r
4187 /* System sound from Control Panel (deprecated feature).
\r
4188 "$" alone or an unset sound name gets default beep (still in use). */
\r
4189 if (ms->name[1]) {
\r
4190 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
4192 if (!ok) ok = MessageBeep(MB_OK);
\r
4195 /* Builtin wave resource, or "!" alone for silence */
\r
4196 if (ms->name[1]) {
\r
4197 if (ms->data == NULL) return FALSE;
\r
4198 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4204 /* .wav file. Error if not found. */
\r
4205 if (ms->data == NULL) return FALSE;
\r
4206 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4209 /* Don't print an error: this can happen innocently if the sound driver
\r
4210 is busy; for instance, if another instance of WinBoard is playing
\r
4211 a sound at about the same time. */
\r
4214 char buf[MSG_SIZ];
\r
4215 sprintf(buf, "Error playing sound %s", ms->name);
\r
4216 DisplayError(buf, GetLastError());
\r
4224 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4227 OPENFILENAME *ofn;
\r
4228 static UINT *number; /* gross that this is static */
\r
4230 switch (message) {
\r
4231 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4232 /* Center the dialog over the application window */
\r
4233 ofn = (OPENFILENAME *) lParam;
\r
4234 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
4235 number = (UINT *) ofn->lCustData;
\r
4236 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
4240 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4241 return FALSE; /* Allow for further processing */
\r
4244 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
4245 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
4247 return FALSE; /* Allow for further processing */
\r
4253 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
4255 static UINT *number;
\r
4256 OPENFILENAME *ofname;
\r
4259 case WM_INITDIALOG:
\r
4260 ofname = (OPENFILENAME *)lParam;
\r
4261 number = (UINT *)(ofname->lCustData);
\r
4264 ofnot = (OFNOTIFY *)lParam;
\r
4265 if (ofnot->hdr.code == CDN_FILEOK) {
\r
4266 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
4275 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
4276 char *nameFilt, char *dlgTitle, UINT *number,
\r
4277 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
4279 OPENFILENAME openFileName;
\r
4280 char buf1[MSG_SIZ];
\r
4283 if (fileName == NULL) fileName = buf1;
\r
4284 if (defName == NULL) {
\r
4285 strcpy(fileName, "*.");
\r
4286 strcat(fileName, defExt);
\r
4288 strcpy(fileName, defName);
\r
4290 if (fileTitle) strcpy(fileTitle, "");
\r
4291 if (number) *number = 0;
\r
4293 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
4294 openFileName.hwndOwner = hwnd;
\r
4295 openFileName.hInstance = (HANDLE) hInst;
\r
4296 openFileName.lpstrFilter = nameFilt;
\r
4297 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
4298 openFileName.nMaxCustFilter = 0L;
\r
4299 openFileName.nFilterIndex = 1L;
\r
4300 openFileName.lpstrFile = fileName;
\r
4301 openFileName.nMaxFile = MSG_SIZ;
\r
4302 openFileName.lpstrFileTitle = fileTitle;
\r
4303 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
4304 openFileName.lpstrInitialDir = NULL;
\r
4305 openFileName.lpstrTitle = dlgTitle;
\r
4306 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
4307 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
4308 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
4309 | (oldDialog ? 0 : OFN_EXPLORER);
\r
4310 openFileName.nFileOffset = 0;
\r
4311 openFileName.nFileExtension = 0;
\r
4312 openFileName.lpstrDefExt = defExt;
\r
4313 openFileName.lCustData = (LONG) number;
\r
4314 openFileName.lpfnHook = oldDialog ?
\r
4315 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
4316 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
4318 if (write ? GetSaveFileName(&openFileName) :
\r
4319 GetOpenFileName(&openFileName)) {
\r
4320 /* open the file */
\r
4321 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
4323 MessageBox(hwnd, "File open failed", NULL,
\r
4324 MB_OK|MB_ICONEXCLAMATION);
\r
4328 int err = CommDlgExtendedError();
\r
4329 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
4338 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
4340 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
4343 * Get the first pop-up menu in the menu template. This is the
\r
4344 * menu that TrackPopupMenu displays.
\r
4346 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
4348 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
4351 * TrackPopup uses screen coordinates, so convert the
\r
4352 * coordinates of the mouse click to screen coordinates.
\r
4354 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
4356 /* Draw and track the floating pop-up menu. */
\r
4357 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
4358 pt.x, pt.y, 0, hwnd, NULL);
\r
4360 /* Destroy the menu.*/
\r
4361 DestroyMenu(hmenu);
\r
4366 int sizeX, sizeY, newSizeX, newSizeY;
\r
4368 } ResizeEditPlusButtonsClosure;
\r
4371 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
4373 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
4377 if (hChild == cl->hText) return TRUE;
\r
4378 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
4379 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
4380 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
4381 ScreenToClient(cl->hDlg, &pt);
\r
4382 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
4383 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
4387 /* Resize a dialog that has a (rich) edit field filling most of
\r
4388 the top, with a row of buttons below */
\r
4390 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
4393 int newTextHeight, newTextWidth;
\r
4394 ResizeEditPlusButtonsClosure cl;
\r
4396 /*if (IsIconic(hDlg)) return;*/
\r
4397 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
4399 cl.hdwp = BeginDeferWindowPos(8);
\r
4401 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
4402 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
4403 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
4404 if (newTextHeight < 0) {
\r
4405 newSizeY += -newTextHeight;
\r
4406 newTextHeight = 0;
\r
4408 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
4409 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
4415 cl.newSizeX = newSizeX;
\r
4416 cl.newSizeY = newSizeY;
\r
4417 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
4419 EndDeferWindowPos(cl.hdwp);
\r
4422 /* Center one window over another */
\r
4423 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
4425 RECT rChild, rParent;
\r
4426 int wChild, hChild, wParent, hParent;
\r
4427 int wScreen, hScreen, xNew, yNew;
\r
4430 /* Get the Height and Width of the child window */
\r
4431 GetWindowRect (hwndChild, &rChild);
\r
4432 wChild = rChild.right - rChild.left;
\r
4433 hChild = rChild.bottom - rChild.top;
\r
4435 /* Get the Height and Width of the parent window */
\r
4436 GetWindowRect (hwndParent, &rParent);
\r
4437 wParent = rParent.right - rParent.left;
\r
4438 hParent = rParent.bottom - rParent.top;
\r
4440 /* Get the display limits */
\r
4441 hdc = GetDC (hwndChild);
\r
4442 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
4443 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
4444 ReleaseDC(hwndChild, hdc);
\r
4446 /* Calculate new X position, then adjust for screen */
\r
4447 xNew = rParent.left + ((wParent - wChild) /2);
\r
4450 } else if ((xNew+wChild) > wScreen) {
\r
4451 xNew = wScreen - wChild;
\r
4454 /* Calculate new Y position, then adjust for screen */
\r
4455 yNew = rParent.top + ((hParent - hChild) /2);
\r
4458 } else if ((yNew+hChild) > hScreen) {
\r
4459 yNew = hScreen - hChild;
\r
4462 /* Set it, and return */
\r
4463 return SetWindowPos (hwndChild, NULL,
\r
4464 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
4467 /*---------------------------------------------------------------------------*\
\r
4469 * Startup Dialog functions
\r
4471 \*---------------------------------------------------------------------------*/
\r
4473 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
4475 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
4477 while (*cd != NULL) {
\r
4478 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
4484 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
4486 char buf1[ARG_MAX];
\r
4489 if (str[0] == '@') {
\r
4490 FILE* f = fopen(str + 1, "r");
\r
4492 DisplayFatalError(str + 1, errno, 2);
\r
4495 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
4497 buf1[len] = NULLCHAR;
\r
4501 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
4504 char buf[MSG_SIZ];
\r
4505 char *end = strchr(str, '\n');
\r
4506 if (end == NULL) return;
\r
4507 memcpy(buf, str, end - str);
\r
4508 buf[end - str] = NULLCHAR;
\r
4509 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
4515 SetStartupDialogEnables(HWND hDlg)
\r
4517 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
4518 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
4519 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
4520 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
4521 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
4522 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
4523 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
4524 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
4525 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
4526 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
4527 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
4528 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
4529 IsDlgButtonChecked(hDlg, OPT_View));
\r
4533 QuoteForFilename(char *filename)
\r
4535 int dquote, space;
\r
4536 dquote = strchr(filename, '"') != NULL;
\r
4537 space = strchr(filename, ' ') != NULL;
\r
4538 if (dquote || space) {
\r
4550 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
4552 char buf[MSG_SIZ];
\r
4555 InitComboStringsFromOption(hwndCombo, nthnames);
\r
4556 q = QuoteForFilename(nthcp);
\r
4557 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
4558 if (*nthdir != NULLCHAR) {
\r
4559 q = QuoteForFilename(nthdir);
\r
4560 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
4562 if (*nthcp == NULLCHAR) {
\r
4563 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
4564 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
4565 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
4566 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
4571 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4573 char buf[MSG_SIZ];
\r
4577 switch (message) {
\r
4578 case WM_INITDIALOG:
\r
4579 /* Center the dialog */
\r
4580 CenterWindow (hDlg, GetDesktopWindow());
\r
4581 /* Initialize the dialog items */
\r
4582 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
4583 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
4584 firstChessProgramNames);
\r
4585 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
4586 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
4587 secondChessProgramNames);
\r
4588 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
4589 InitComboStringsFromOption(hwndCombo, icsNames);
\r
4590 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
4591 if (*appData.icsHelper != NULLCHAR) {
\r
4592 char *q = QuoteForFilename(appData.icsHelper);
\r
4593 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
4595 if (*appData.icsHost == NULLCHAR) {
\r
4596 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
4597 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
4598 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
4599 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
4600 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
4602 if (chessProgram) {
\r
4603 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
4604 } else if (appData.icsActive) {
\r
4605 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
4606 } else if (appData.noChessProgram) {
\r
4607 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
4609 SetStartupDialogEnables(hDlg);
\r
4613 switch (LOWORD(wParam)) {
\r
4615 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
4616 strcpy(buf, "/fcp=");
\r
4617 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4619 ParseArgs(StringGet, &p);
\r
4620 strcpy(buf, "/scp=");
\r
4621 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4623 ParseArgs(StringGet, &p);
\r
4624 appData.noChessProgram = FALSE;
\r
4625 appData.icsActive = FALSE;
\r
4626 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
4627 strcpy(buf, "/ics /icshost=");
\r
4628 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4630 ParseArgs(StringGet, &p);
\r
4631 if (appData.zippyPlay) {
\r
4632 strcpy(buf, "/fcp=");
\r
4633 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4635 ParseArgs(StringGet, &p);
\r
4637 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
4638 appData.noChessProgram = TRUE;
\r
4639 appData.icsActive = FALSE;
\r
4641 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
4642 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
4645 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
4646 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
4648 ParseArgs(StringGet, &p);
\r
4650 EndDialog(hDlg, TRUE);
\r
4657 case IDM_HELPCONTENTS:
\r
4658 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
4659 MessageBox (GetFocus(),
\r
4660 "Unable to activate help",
\r
4661 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4666 SetStartupDialogEnables(hDlg);
\r
4674 /*---------------------------------------------------------------------------*\
\r
4676 * About box dialog functions
\r
4678 \*---------------------------------------------------------------------------*/
\r
4680 /* Process messages for "About" dialog box */
\r
4682 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4684 switch (message) {
\r
4685 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4686 /* Center the dialog over the application window */
\r
4687 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4688 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
4691 case WM_COMMAND: /* message: received a command */
\r
4692 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
4693 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
4694 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4702 /*---------------------------------------------------------------------------*\
\r
4704 * Comment Dialog functions
\r
4706 \*---------------------------------------------------------------------------*/
\r
4709 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4711 static HANDLE hwndText = NULL;
\r
4712 int len, newSizeX, newSizeY, flags;
\r
4713 static int sizeX, sizeY;
\r
4718 switch (message) {
\r
4719 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4720 /* Initialize the dialog items */
\r
4721 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
4722 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
4723 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
4724 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
4725 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
4726 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
4727 SetWindowText(hDlg, commentTitle);
\r
4728 if (editComment) {
\r
4729 SetFocus(hwndText);
\r
4731 SetFocus(GetDlgItem(hDlg, IDOK));
\r
4733 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
4734 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
4735 MAKELPARAM(FALSE, 0));
\r
4736 /* Size and position the dialog */
\r
4737 if (!commentDialog) {
\r
4738 commentDialog = hDlg;
\r
4739 flags = SWP_NOZORDER;
\r
4740 GetClientRect(hDlg, &rect);
\r
4741 sizeX = rect.right;
\r
4742 sizeY = rect.bottom;
\r
4743 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
4744 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
4745 WINDOWPLACEMENT wp;
\r
4746 EnsureOnScreen(&commentX, &commentY);
\r
4747 wp.length = sizeof(WINDOWPLACEMENT);
\r
4749 wp.showCmd = SW_SHOW;
\r
4750 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
4751 wp.rcNormalPosition.left = commentX;
\r
4752 wp.rcNormalPosition.right = commentX + commentW;
\r
4753 wp.rcNormalPosition.top = commentY;
\r
4754 wp.rcNormalPosition.bottom = commentY + commentH;
\r
4755 SetWindowPlacement(hDlg, &wp);
\r
4757 GetClientRect(hDlg, &rect);
\r
4758 newSizeX = rect.right;
\r
4759 newSizeY = rect.bottom;
\r
4760 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
4761 newSizeX, newSizeY);
\r
4768 case WM_COMMAND: /* message: received a command */
\r
4769 switch (LOWORD(wParam)) {
\r
4771 if (editComment) {
\r
4773 /* Read changed options from the dialog box */
\r
4774 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
4775 len = GetWindowTextLength(hwndText);
\r
4776 str = (char *) malloc(len + 1);
\r
4777 GetWindowText(hwndText, str, len + 1);
\r
4786 ReplaceComment(commentIndex, str);
\r
4793 case OPT_CancelComment:
\r
4797 case OPT_ClearComment:
\r
4798 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
4801 case OPT_EditComment:
\r
4802 EditCommentEvent();
\r
4811 newSizeX = LOWORD(lParam);
\r
4812 newSizeY = HIWORD(lParam);
\r
4813 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
4818 case WM_GETMINMAXINFO:
\r
4819 /* Prevent resizing window too small */
\r
4820 mmi = (MINMAXINFO *) lParam;
\r
4821 mmi->ptMinTrackSize.x = 100;
\r
4822 mmi->ptMinTrackSize.y = 100;
\r
4829 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
4834 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
4836 if (str == NULL) str = "";
\r
4837 p = (char *) malloc(2 * strlen(str) + 2);
\r
4840 if (*str == '\n') *q++ = '\r';
\r
4844 if (commentText != NULL) free(commentText);
\r
4846 commentIndex = index;
\r
4847 commentTitle = title;
\r
4849 editComment = edit;
\r
4851 if (commentDialog) {
\r
4852 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
4853 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
4855 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
4856 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
4857 hwndMain, (DLGPROC)lpProc);
\r
4858 FreeProcInstance(lpProc);
\r
4860 commentDialogUp = TRUE;
\r
4864 /*---------------------------------------------------------------------------*\
\r
4866 * Type-in move dialog functions
\r
4868 \*---------------------------------------------------------------------------*/
\r
4871 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4873 char move[MSG_SIZ];
\r
4875 ChessMove moveType;
\r
4876 int fromX, fromY, toX, toY;
\r
4879 switch (message) {
\r
4880 case WM_INITDIALOG:
\r
4881 move[0] = (char) lParam;
\r
4882 move[1] = NULLCHAR;
\r
4883 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4884 hInput = GetDlgItem(hDlg, OPT_Move);
\r
4885 SetWindowText(hInput, move);
\r
4887 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
4891 switch (LOWORD(wParam)) {
\r
4893 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
4894 gameMode != Training) {
\r
4895 DisplayMoveError("Displayed move is not current");
\r
4897 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
4898 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
4899 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
4900 if (gameMode != Training)
\r
4901 forwardMostMove = currentMove;
\r
4902 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4904 DisplayMoveError("Could not parse move");
\r
4907 EndDialog(hDlg, TRUE);
\r
4910 EndDialog(hDlg, FALSE);
\r
4921 PopUpMoveDialog(char firstchar)
\r
4925 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
4926 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
4927 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
4928 gameMode == EditPosition || gameMode == IcsExamining ||
\r
4929 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
4930 gameMode == Training) {
\r
4931 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
4932 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
4933 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
4934 FreeProcInstance(lpProc);
\r
4938 /*---------------------------------------------------------------------------*\
\r
4942 \*---------------------------------------------------------------------------*/
\r
4944 /* Nonmodal error box */
\r
4948 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
4949 if (errorDialog == NULL) return;
\r
4950 DestroyWindow(errorDialog);
\r
4951 errorDialog = NULL;
\r
4955 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4960 switch (message) {
\r
4961 case WM_INITDIALOG:
\r
4962 GetWindowRect(hDlg, &rChild);
\r
4963 SetWindowPos(hDlg, NULL, rChild.left,
\r
4964 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
4965 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
4966 errorDialog = hDlg;
\r
4967 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
4968 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
4972 switch (LOWORD(wParam)) {
\r
4975 if (errorDialog == hDlg) errorDialog = NULL;
\r
4976 DestroyWindow(hDlg);
\r
4987 /*---------------------------------------------------------------------------*\
\r
4989 * Ics Interaction console functions
\r
4991 \*---------------------------------------------------------------------------*/
\r
4993 #define HISTORY_SIZE 64
\r
4994 static char *history[HISTORY_SIZE];
\r
4995 int histIn = 0, histP = 0;
\r
4998 SaveInHistory(char *cmd)
\r
5000 if (history[histIn] != NULL) {
\r
5001 free(history[histIn]);
\r
5002 history[histIn] = NULL;
\r
5004 if (*cmd == NULLCHAR) return;
\r
5005 history[histIn] = StrSave(cmd);
\r
5006 histIn = (histIn + 1) % HISTORY_SIZE;
\r
5007 if (history[histIn] != NULL) {
\r
5008 free(history[histIn]);
\r
5009 history[histIn] = NULL;
\r
5015 PrevInHistory(char *cmd)
\r
5018 if (histP == histIn) {
\r
5019 if (history[histIn] != NULL) free(history[histIn]);
\r
5020 history[histIn] = StrSave(cmd);
\r
5022 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
5023 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
5025 return history[histP];
\r
5031 if (histP == histIn) return NULL;
\r
5032 histP = (histP + 1) % HISTORY_SIZE;
\r
5033 return history[histP];
\r
5040 BOOLEAN immediate;
\r
5041 } IcsTextMenuEntry;
\r
5042 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
5043 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
5046 ParseIcsTextMenu(char *icsTextMenuString)
\r
5049 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
5050 char *p = icsTextMenuString;
\r
5051 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5054 if (e->command != NULL) {
\r
5056 e->command = NULL;
\r
5060 e = icsTextMenuEntry;
\r
5061 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5062 if (*p == ';' || *p == '\n') {
\r
5063 e->item = strdup("-");
\r
5064 e->command = NULL;
\r
5066 } else if (*p == '-') {
\r
5067 e->item = strdup("-");
\r
5068 e->command = NULL;
\r
5072 char *q, *r, *s, *t;
\r
5074 q = strchr(p, ',');
\r
5075 if (q == NULL) break;
\r
5077 r = strchr(q + 1, ',');
\r
5078 if (r == NULL) break;
\r
5080 s = strchr(r + 1, ',');
\r
5081 if (s == NULL) break;
\r
5084 t = strchr(s + 1, c);
\r
5087 t = strchr(s + 1, c);
\r
5089 if (t != NULL) *t = NULLCHAR;
\r
5090 e->item = strdup(p);
\r
5091 e->command = strdup(q + 1);
\r
5092 e->getname = *(r + 1) != '0';
\r
5093 e->immediate = *(s + 1) != '0';
\r
5097 if (t == NULL) break;
\r
5106 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
5110 hmenu = LoadMenu(hInst, "TextMenu");
\r
5111 h = GetSubMenu(hmenu, 0);
\r
5113 if (strcmp(e->item, "-") == 0) {
\r
5114 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
5116 if (e->item[0] == '|') {
\r
5117 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
5118 IDM_CommandX + i, &e->item[1]);
\r
5120 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
5129 WNDPROC consoleTextWindowProc;
\r
5132 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
5134 char buf[MSG_SIZ], name[MSG_SIZ];
\r
5135 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5139 SetWindowText(hInput, command);
\r
5141 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5143 sel.cpMin = 999999;
\r
5144 sel.cpMax = 999999;
\r
5145 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5150 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5151 if (sel.cpMin == sel.cpMax) {
\r
5152 /* Expand to surrounding word */
\r
5155 tr.chrg.cpMax = sel.cpMin;
\r
5156 tr.chrg.cpMin = --sel.cpMin;
\r
5157 if (sel.cpMin < 0) break;
\r
5158 tr.lpstrText = name;
\r
5159 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5160 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5164 tr.chrg.cpMin = sel.cpMax;
\r
5165 tr.chrg.cpMax = ++sel.cpMax;
\r
5166 tr.lpstrText = name;
\r
5167 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
5168 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5171 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5172 MessageBeep(MB_ICONEXCLAMATION);
\r
5176 tr.lpstrText = name;
\r
5177 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5179 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5180 MessageBeep(MB_ICONEXCLAMATION);
\r
5183 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
5186 sprintf(buf, "%s %s", command, name);
\r
5187 SetWindowText(hInput, buf);
\r
5188 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5190 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
5191 SetWindowText(hInput, buf);
\r
5192 sel.cpMin = 999999;
\r
5193 sel.cpMax = 999999;
\r
5194 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5200 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5205 switch (message) {
\r
5207 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5210 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
5213 sel.cpMin = 999999;
\r
5214 sel.cpMax = 999999;
\r
5215 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5216 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
5221 if (wParam == '\t') {
\r
5222 if (GetKeyState(VK_SHIFT) < 0) {
\r
5224 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5225 if (buttonDesc[0].hwnd) {
\r
5226 SetFocus(buttonDesc[0].hwnd);
\r
5228 SetFocus(hwndMain);
\r
5232 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
5235 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5237 SendMessage(hInput, message, wParam, lParam);
\r
5241 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5243 return SendMessage(hInput, message, wParam, lParam);
\r
5244 case WM_MBUTTONDOWN:
\r
5245 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5246 case WM_RBUTTONDOWN:
\r
5247 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
5248 /* Move selection here if it was empty */
\r
5250 pt.x = LOWORD(lParam);
\r
5251 pt.y = HIWORD(lParam);
\r
5252 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5253 if (sel.cpMin == sel.cpMax) {
\r
5254 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
5255 sel.cpMax = sel.cpMin;
\r
5256 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5258 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
5261 case WM_RBUTTONUP:
\r
5262 if (GetKeyState(VK_SHIFT) & ~1) {
\r
5263 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5264 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5267 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
5268 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5269 if (sel.cpMin == sel.cpMax) {
\r
5270 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
5271 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
5273 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
5274 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
5276 pt.x = LOWORD(lParam);
\r
5277 pt.y = HIWORD(lParam);
\r
5278 MenuPopup(hwnd, pt, hmenu, -1);
\r
5282 switch (LOWORD(wParam)) {
\r
5283 case IDM_QuickPaste:
\r
5285 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5286 if (sel.cpMin == sel.cpMax) {
\r
5287 MessageBeep(MB_ICONEXCLAMATION);
\r
5290 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5291 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5292 SendMessage(hInput, WM_PASTE, 0, 0);
\r
5297 SendMessage(hwnd, WM_CUT, 0, 0);
\r
5300 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
5303 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5307 int i = LOWORD(wParam) - IDM_CommandX;
\r
5308 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
5309 icsTextMenuEntry[i].command != NULL) {
\r
5310 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
5311 icsTextMenuEntry[i].getname,
\r
5312 icsTextMenuEntry[i].immediate);
\r
5320 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
5323 WNDPROC consoleInputWindowProc;
\r
5326 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5328 char buf[MSG_SIZ];
\r
5330 static BOOL sendNextChar = FALSE;
\r
5331 static BOOL quoteNextChar = FALSE;
\r
5332 InputSource *is = consoleInputSource;
\r
5336 switch (message) {
\r
5338 if (!appData.localLineEditing || sendNextChar) {
\r
5339 is->buf[0] = (CHAR) wParam;
\r
5341 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5342 sendNextChar = FALSE;
\r
5345 if (quoteNextChar) {
\r
5346 buf[0] = (char) wParam;
\r
5347 buf[1] = NULLCHAR;
\r
5348 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
5349 quoteNextChar = FALSE;
\r
5353 case '\r': /* Enter key */
\r
5354 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
5355 if (consoleEcho) SaveInHistory(is->buf);
\r
5356 is->buf[is->count++] = '\n';
\r
5357 is->buf[is->count] = NULLCHAR;
\r
5358 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5359 if (consoleEcho) {
\r
5360 ConsoleOutput(is->buf, is->count, TRUE);
\r
5361 } else if (appData.localLineEditing) {
\r
5362 ConsoleOutput("\n", 1, TRUE);
\r
5365 case '\033': /* Escape key */
\r
5366 SetWindowText(hwnd, "");
\r
5367 cf.cbSize = sizeof(CHARFORMAT);
\r
5368 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
5369 if (consoleEcho) {
\r
5370 cf.crTextColor = textAttribs[ColorNormal].color;
\r
5372 cf.crTextColor = COLOR_ECHOOFF;
\r
5374 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
5375 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
5377 case '\t': /* Tab key */
\r
5378 if (GetKeyState(VK_SHIFT) < 0) {
\r
5380 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
5383 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5384 if (buttonDesc[0].hwnd) {
\r
5385 SetFocus(buttonDesc[0].hwnd);
\r
5387 SetFocus(hwndMain);
\r
5391 case '\023': /* Ctrl+S */
\r
5392 sendNextChar = TRUE;
\r
5394 case '\021': /* Ctrl+Q */
\r
5395 quoteNextChar = TRUE;
\r
5404 GetWindowText(hwnd, buf, MSG_SIZ);
\r
5405 p = PrevInHistory(buf);
\r
5407 SetWindowText(hwnd, p);
\r
5408 sel.cpMin = 999999;
\r
5409 sel.cpMax = 999999;
\r
5410 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5415 p = NextInHistory();
\r
5417 SetWindowText(hwnd, p);
\r
5418 sel.cpMin = 999999;
\r
5419 sel.cpMax = 999999;
\r
5420 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5426 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5430 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
5434 case WM_MBUTTONDOWN:
\r
5435 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5436 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5438 case WM_RBUTTONUP:
\r
5439 if (GetKeyState(VK_SHIFT) & ~1) {
\r
5440 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5441 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5445 hmenu = LoadMenu(hInst, "InputMenu");
\r
5446 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5447 if (sel.cpMin == sel.cpMax) {
\r
5448 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
5449 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
5451 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
5452 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
5454 pt.x = LOWORD(lParam);
\r
5455 pt.y = HIWORD(lParam);
\r
5456 MenuPopup(hwnd, pt, hmenu, -1);
\r
5460 switch (LOWORD(wParam)) {
\r
5462 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
5464 case IDM_SelectAll:
\r
5466 sel.cpMax = -1; /*999999?*/
\r
5467 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5470 SendMessage(hwnd, WM_CUT, 0, 0);
\r
5473 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
5476 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5481 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
5484 #define CO_MAX 100000
\r
5485 #define CO_TRIM 1000
\r
5488 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5490 static HWND hText, hInput, hFocus;
\r
5491 InputSource *is = consoleInputSource;
\r
5493 static int sizeX, sizeY;
\r
5494 int newSizeX, newSizeY;
\r
5497 switch (message) {
\r
5498 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5499 hwndConsole = hDlg;
\r
5500 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
5501 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
5503 consoleTextWindowProc = (WNDPROC)
\r
5504 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
5505 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
5506 consoleInputWindowProc = (WNDPROC)
\r
5507 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
5508 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
5509 Colorize(ColorNormal, TRUE);
\r
5510 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
5511 ChangedConsoleFont();
\r
5512 GetClientRect(hDlg, &rect);
\r
5513 sizeX = rect.right;
\r
5514 sizeY = rect.bottom;
\r
5515 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
5516 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
5517 WINDOWPLACEMENT wp;
\r
5518 EnsureOnScreen(&consoleX, &consoleY);
\r
5519 wp.length = sizeof(WINDOWPLACEMENT);
\r
5521 wp.showCmd = SW_SHOW;
\r
5522 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
5523 wp.rcNormalPosition.left = consoleX;
\r
5524 wp.rcNormalPosition.right = consoleX + consoleW;
\r
5525 wp.rcNormalPosition.top = consoleY;
\r
5526 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
5527 SetWindowPlacement(hDlg, &wp);
\r
5541 if (IsIconic(hDlg)) break;
\r
5542 newSizeX = LOWORD(lParam);
\r
5543 newSizeY = HIWORD(lParam);
\r
5544 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
5545 RECT rectText, rectInput;
\r
5547 int newTextHeight, newTextWidth;
\r
5548 GetWindowRect(hText, &rectText);
\r
5549 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5550 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5551 if (newTextHeight < 0) {
\r
5552 newSizeY += -newTextHeight;
\r
5553 newTextHeight = 0;
\r
5555 SetWindowPos(hText, NULL, 0, 0,
\r
5556 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5557 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
5558 pt.x = rectInput.left;
\r
5559 pt.y = rectInput.top + newSizeY - sizeY;
\r
5560 ScreenToClient(hDlg, &pt);
\r
5561 SetWindowPos(hInput, NULL,
\r
5562 pt.x, pt.y, /* needs client coords */
\r
5563 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
5564 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
5570 case WM_GETMINMAXINFO:
\r
5571 /* Prevent resizing window too small */
\r
5572 mmi = (MINMAXINFO *) lParam;
\r
5573 mmi->ptMinTrackSize.x = 100;
\r
5574 mmi->ptMinTrackSize.y = 100;
\r
5577 return DefWindowProc(hDlg, message, wParam, lParam);
\r
5585 if (hwndConsole) return;
\r
5586 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
5587 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
5592 ConsoleOutput(char* data, int length, int forceVisible)
\r
5597 char buf[CO_MAX+1];
\r
5600 static int delayLF = 0;
\r
5601 CHARRANGE savesel, sel;
\r
5603 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
5611 while (length--) {
\r
5619 } else if (*p == '\007') {
\r
5620 MyPlaySound(&sounds[(int)SoundBell]);
\r
5627 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5628 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
5629 /* Save current selection */
\r
5630 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
5631 exlen = GetWindowTextLength(hText);
\r
5632 /* Find out whether current end of text is visible */
\r
5633 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
5634 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
5635 /* Trim existing text if it's too long */
\r
5636 if (exlen + (q - buf) > CO_MAX) {
\r
5637 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
5640 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5641 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
5643 savesel.cpMin -= trim;
\r
5644 savesel.cpMax -= trim;
\r
5645 if (exlen < 0) exlen = 0;
\r
5646 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
5647 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
5649 /* Append the new text */
\r
5650 sel.cpMin = exlen;
\r
5651 sel.cpMax = exlen;
\r
5652 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5653 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
5654 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
5655 if (forceVisible || exlen == 0 ||
\r
5656 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
5657 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
5658 /* Scroll to make new end of text visible if old end of text
\r
5659 was visible or new text is an echo of user typein */
\r
5660 sel.cpMin = 9999999;
\r
5661 sel.cpMax = 9999999;
\r
5662 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5663 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
5664 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
5665 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
5667 if (savesel.cpMax == exlen || forceVisible) {
\r
5668 /* Move insert point to new end of text if it was at the old
\r
5669 end of text or if the new text is an echo of user typein */
\r
5670 sel.cpMin = 9999999;
\r
5671 sel.cpMax = 9999999;
\r
5672 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5674 /* Restore previous selection */
\r
5675 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
5677 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
5684 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
5685 RECT *rect, char *color)
\r
5689 COLORREF oldFg, oldBg;
\r
5692 if (appData.clockMode) {
\r
5694 sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));
\r
5696 sprintf(buf, "%s: %s", color, TimeString(timeRemaining));
\r
5703 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
5704 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
5706 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
5707 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
5709 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
5711 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
5712 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
5713 rect, str, strlen(str), NULL);
\r
5715 (void) SetTextColor(hdc, oldFg);
\r
5716 (void) SetBkColor(hdc, oldBg);
\r
5717 (void) SelectObject(hdc, oldFont);
\r
5722 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
5727 ResetEvent(ovl->hEvent);
\r
5728 ovl->Offset = ovl->OffsetHigh = 0;
\r
5729 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
5733 err = GetLastError();
\r
5734 if (err == ERROR_IO_PENDING) {
\r
5735 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
5739 err = GetLastError();
\r
5746 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
5751 ResetEvent(ovl->hEvent);
\r
5752 ovl->Offset = ovl->OffsetHigh = 0;
\r
5753 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
5757 err = GetLastError();
\r
5758 if (err == ERROR_IO_PENDING) {
\r
5759 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
5763 err = GetLastError();
\r
5771 InputThread(LPVOID arg)
\r
5776 is = (InputSource *) arg;
\r
5777 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
5778 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
5779 while (is->hThread != NULL) {
\r
5780 is->error = DoReadFile(is->hFile, is->next,
\r
5781 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
5782 &is->count, &ovl);
\r
5783 if (is->error == NO_ERROR) {
\r
5784 is->next += is->count;
\r
5786 if (is->error == ERROR_BROKEN_PIPE) {
\r
5787 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
5790 is->count = (DWORD) -1;
\r
5793 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5794 if (is->count <= 0) break; /* Quit on EOF or error */
\r
5796 CloseHandle(ovl.hEvent);
\r
5797 CloseHandle(is->hFile);
\r
5802 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
5804 NonOvlInputThread(LPVOID arg)
\r
5811 is = (InputSource *) arg;
\r
5812 while (is->hThread != NULL) {
\r
5813 is->error = ReadFile(is->hFile, is->next,
\r
5814 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
5815 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
5816 if (is->error == NO_ERROR) {
\r
5817 /* Change CRLF to LF */
\r
5818 if (is->next > is->buf) {
\r
5820 i = is->count + 1;
\r
5828 if (prev == '\r' && *p == '\n') {
\r
5840 if (is->error == ERROR_BROKEN_PIPE) {
\r
5841 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
5844 is->count = (DWORD) -1;
\r
5847 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5848 if (is->count < 0) break; /* Quit on error */
\r
5850 CloseHandle(is->hFile);
\r
5855 SocketInputThread(LPVOID arg)
\r
5859 is = (InputSource *) arg;
\r
5860 while (is->hThread != NULL) {
\r
5861 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
5862 if ((int)is->count == SOCKET_ERROR) {
\r
5863 is->count = (DWORD) -1;
\r
5864 is->error = WSAGetLastError();
\r
5866 is->error = NO_ERROR;
\r
5867 is->next += is->count;
\r
5868 if (is->count == 0 && is->second == is) {
\r
5869 /* End of file on stderr; quit with no message */
\r
5873 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5874 if (is->count <= 0) break; /* Quit on EOF or error */
\r
5880 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5884 is = (InputSource *) lParam;
\r
5885 if (is->lineByLine) {
\r
5886 /* Feed in lines one by one */
\r
5887 char *p = is->buf;
\r
5889 while (q < is->next) {
\r
5890 if (*q++ == '\n') {
\r
5891 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
5895 /* Move any partial line to the start of the buffer */
\r
5897 while (p < is->next) {
\r
5901 if (is->error != NO_ERROR || is->count == 0) {
\r
5902 /* Notify backend of the error. Note: If there was a partial
\r
5903 line at the end, it is not flushed through. */
\r
5904 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
5907 /* Feed in the whole chunk of input at once */
\r
5908 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
5909 is->next = is->buf;
\r
5913 /*---------------------------------------------------------------------------*\
\r
5915 * Menu enables. Used when setting various modes.
\r
5917 \*---------------------------------------------------------------------------*/
\r
5925 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
5927 while (enab->item > 0) {
\r
5928 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
5933 Enables gnuEnables[] = {
\r
5934 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
5935 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
5936 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
5937 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
5938 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
5939 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
5940 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
5941 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
5942 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
5943 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
5947 Enables icsEnables[] = {
\r
5948 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
5949 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
5950 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
5951 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
5952 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
5953 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
5954 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
5955 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
5956 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
5957 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
5958 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
5959 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
5964 Enables zippyEnables[] = {
\r
5965 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
5966 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
5967 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
5972 Enables ncpEnables[] = {
\r
5973 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
5974 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
5975 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
5976 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
5977 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
5978 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
5979 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
5980 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
5981 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
5982 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
5983 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
5984 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
5985 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
5986 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
5987 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
5991 Enables trainingOnEnables[] = {
\r
5992 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
5993 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
5994 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
5995 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
5996 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
5997 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
5998 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
5999 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
6003 Enables trainingOffEnables[] = {
\r
6004 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
6005 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
6006 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
6007 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
6008 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
6009 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
6010 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6011 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
6015 /* These modify either ncpEnables or gnuEnables */
\r
6016 Enables cmailEnables[] = {
\r
6017 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
6018 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
6019 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
6020 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
6021 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
6022 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6023 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
6027 Enables machineThinkingEnables[] = {
\r
6028 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6029 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
6030 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
6031 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6032 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
6033 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6034 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6035 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6036 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6037 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
6038 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6039 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6040 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6041 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
6042 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6046 Enables userThinkingEnables[] = {
\r
6047 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6048 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
6049 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
6050 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6051 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
6052 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6053 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6054 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6055 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6056 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
6057 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
6058 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
6059 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
6060 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
6061 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
6065 /*---------------------------------------------------------------------------*\
\r
6067 * Front-end interface functions exported by XBoard.
\r
6068 * Functions appear in same order as prototypes in frontend.h.
\r
6070 \*---------------------------------------------------------------------------*/
\r
6074 static UINT prevChecked = 0;
\r
6075 static int prevPausing = 0;
\r
6078 if (pausing != prevPausing) {
\r
6079 prevPausing = pausing;
\r
6080 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
6081 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
6082 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
6085 switch (gameMode) {
\r
6086 case BeginningOfGame:
\r
6087 if (appData.icsActive)
\r
6088 nowChecked = IDM_IcsClient;
\r
6089 else if (appData.noChessProgram)
\r
6090 nowChecked = IDM_EditGame;
\r
6092 nowChecked = IDM_MachineBlack;
\r
6094 case MachinePlaysBlack:
\r
6095 nowChecked = IDM_MachineBlack;
\r
6097 case MachinePlaysWhite:
\r
6098 nowChecked = IDM_MachineWhite;
\r
6100 case TwoMachinesPlay:
\r
6101 nowChecked = IDM_TwoMachines;
\r
6104 nowChecked = IDM_AnalysisMode;
\r
6107 nowChecked = IDM_AnalyzeFile;
\r
6110 nowChecked = IDM_EditGame;
\r
6112 case PlayFromGameFile:
\r
6113 nowChecked = IDM_LoadGame;
\r
6115 case EditPosition:
\r
6116 nowChecked = IDM_EditPosition;
\r
6119 nowChecked = IDM_Training;
\r
6121 case IcsPlayingWhite:
\r
6122 case IcsPlayingBlack:
\r
6123 case IcsObserving:
\r
6125 nowChecked = IDM_IcsClient;
\r
6132 if (prevChecked != 0)
\r
6133 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6134 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
6135 if (nowChecked != 0)
\r
6136 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6137 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
6139 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
6140 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
6141 MF_BYCOMMAND|MF_ENABLED);
\r
6143 (void) EnableMenuItem(GetMenu(hwndMain),
\r
6144 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
6147 prevChecked = nowChecked;
\r
6153 HMENU hmenu = GetMenu(hwndMain);
\r
6154 SetMenuEnables(hmenu, icsEnables);
\r
6155 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
6156 MF_BYPOSITION|MF_ENABLED);
\r
6158 if (appData.zippyPlay) {
\r
6159 SetMenuEnables(hmenu, zippyEnables);
\r
6167 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
6173 HMENU hmenu = GetMenu(hwndMain);
\r
6174 SetMenuEnables(hmenu, ncpEnables);
\r
6175 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
6176 MF_BYPOSITION|MF_GRAYED);
\r
6177 DrawMenuBar(hwndMain);
\r
6183 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
6187 SetTrainingModeOn()
\r
6190 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
6191 for (i = 0; i < N_BUTTONS; i++) {
\r
6192 if (buttonDesc[i].hwnd != NULL)
\r
6193 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
6198 VOID SetTrainingModeOff()
\r
6201 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
6202 for (i = 0; i < N_BUTTONS; i++) {
\r
6203 if (buttonDesc[i].hwnd != NULL)
\r
6204 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
6210 SetUserThinkingEnables()
\r
6212 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
6216 SetMachineThinkingEnables()
\r
6218 HMENU hMenu = GetMenu(hwndMain);
\r
6219 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
6221 SetMenuEnables(hMenu, machineThinkingEnables);
\r
6223 if (gameMode == MachinePlaysBlack) {
\r
6224 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
6225 } else if (gameMode == MachinePlaysWhite) {
\r
6226 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
6227 } else if (gameMode == TwoMachinesPlay) {
\r
6228 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
6234 DisplayTitle(char *str)
\r
6236 char title[MSG_SIZ], *host;
\r
6237 if (str[0] != NULLCHAR) {
\r
6238 strcpy(title, str);
\r
6239 } else if (appData.icsActive) {
\r
6240 if (appData.icsCommPort[0] != NULLCHAR)
\r
6243 host = appData.icsHost;
\r
6244 sprintf(title, "%s: %s", szTitle, host);
\r
6245 } else if (appData.noChessProgram) {
\r
6246 strcpy(title, szTitle);
\r
6248 strcpy(title, szTitle);
\r
6249 strcat(title, ": ");
\r
6250 strcat(title, first.tidy);
\r
6252 SetWindowText(hwndMain, title);
\r
6257 DisplayMessage(char *str1, char *str2)
\r
6261 int remain = MESSAGE_TEXT_MAX - 1;
\r
6264 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
6265 messageText[0] = NULLCHAR;
\r
6267 len = strlen(str1);
\r
6268 if (len > remain) len = remain;
\r
6269 strncpy(messageText, str1, len);
\r
6270 messageText[len] = NULLCHAR;
\r
6273 if (*str2 && remain >= 2) {
\r
6275 strcat(messageText, " ");
\r
6278 len = strlen(str2);
\r
6279 if (len > remain) len = remain;
\r
6280 strncat(messageText, str2, len);
\r
6282 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
6284 if (IsIconic(hwndMain)) return;
\r
6285 hdc = GetDC(hwndMain);
\r
6286 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
6287 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
6288 &messageRect, messageText, strlen(messageText), NULL);
\r
6289 (void) SelectObject(hdc, oldFont);
\r
6290 (void) ReleaseDC(hwndMain, hdc);
\r
6294 DisplayError(char *str, int error)
\r
6297 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
6304 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
6305 NULL, error, LANG_NEUTRAL,
\r
6306 (LPSTR) buf2, MSG_SIZ, NULL);
\r
6308 sprintf(buf, "%s:\n%s", str, buf2);
\r
6310 ErrorMap *em = errmap;
\r
6311 while (em->err != 0 && em->err != error) em++;
\r
6312 if (em->err != 0) {
\r
6313 sprintf(buf, "%s:\n%s", str, em->msg);
\r
6315 sprintf(buf, "%s:\nError code %d", str, error);
\r
6323 if (hwndMain != NULL /*!!?*/) {
\r
6336 if (hwndMain == NULL) {
\r
6337 MessageBox(NULL, errorMessage, "Error", MB_OK|MB_ICONEXCLAMATION);
\r
6339 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6340 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6341 hwndMain, (DLGPROC)lpProc);
\r
6342 FreeProcInstance(lpProc);
\r
6348 DisplayMoveError(char *str)
\r
6350 fromX = fromY = -1;
\r
6351 ClearHighlights();
\r
6352 DrawPosition(FALSE, NULL);
\r
6353 if (appData.popupMoveErrors) {
\r
6354 DisplayError(str, 0);
\r
6356 DisplayMessage(str, "");
\r
6357 moveErrorMessageUp = TRUE;
\r
6362 DisplayFatalError(char *str, int error, int exitStatus)
\r
6364 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
6366 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
6369 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
6370 NULL, error, LANG_NEUTRAL,
\r
6371 (LPSTR) buf2, MSG_SIZ, NULL);
\r
6373 sprintf(buf, "%s:\n%s", str, buf2);
\r
6375 ErrorMap *em = errmap;
\r
6376 while (em->err != 0 && em->err != error) em++;
\r
6377 if (em->err != 0) {
\r
6378 sprintf(buf, "%s:\n%s", str, em->msg);
\r
6380 sprintf(buf, "%s:\nError code %d", str, error);
\r
6385 if (appData.debugMode) {
\r
6386 fprintf(debugFP, "%s: %s\n", label, str);
\r
6388 if (appData.popupExitMessage) {
\r
6389 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
6390 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
6392 ExitEvent(exitStatus);
\r
6397 DisplayInformation(char *str)
\r
6399 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
6404 char *title, *question, *replyPrefix;
\r
6409 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6411 static QuestionParams *qp;
\r
6412 char reply[MSG_SIZ];
\r
6415 switch (message) {
\r
6416 case WM_INITDIALOG:
\r
6417 qp = (QuestionParams *) lParam;
\r
6418 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
6419 SetWindowText(hDlg, qp->title);
\r
6420 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
6421 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
6425 switch (LOWORD(wParam)) {
\r
6427 strcpy(reply, qp->replyPrefix);
\r
6428 if (*reply) strcat(reply, " ");
\r
6429 len = strlen(reply);
\r
6430 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
6431 strcat(reply, "\n");
\r
6432 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
6433 EndDialog(hDlg, TRUE);
\r
6434 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
6437 EndDialog(hDlg, FALSE);
\r
6448 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
6450 QuestionParams qp;
\r
6454 qp.question = question;
\r
6455 qp.replyPrefix = replyPrefix;
\r
6457 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
6458 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
6459 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
6460 FreeProcInstance(lpProc);
\r
6465 DisplayIcsInteractionTitle(char *str)
\r
6467 char consoleTitle[MSG_SIZ];
\r
6469 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
6470 SetWindowText(hwndConsole, consoleTitle);
\r
6474 DrawPosition(int fullRedraw, Board board)
\r
6476 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
6483 fromX = fromY = -1;
\r
6484 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
6485 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
6486 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
6487 dragInfo.lastpos = dragInfo.pos;
\r
6488 dragInfo.start.x = dragInfo.start.y = -1;
\r
6489 dragInfo.from = dragInfo.start;
\r
6491 DrawPosition(TRUE, NULL);
\r
6497 CommentPopUp(char *title, char *str)
\r
6499 HWND hwnd = GetActiveWindow();
\r
6500 EitherCommentPopUp(0, title, str, FALSE);
\r
6501 SetActiveWindow(hwnd);
\r
6505 CommentPopDown(void)
\r
6507 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
6508 if (commentDialog) {
\r
6509 ShowWindow(commentDialog, SW_HIDE);
\r
6511 commentDialogUp = FALSE;
\r
6515 EditCommentPopUp(int index, char *title, char *str)
\r
6517 EitherCommentPopUp(index, title, str, TRUE);
\r
6524 MyPlaySound(&sounds[(int)SoundMove]);
\r
6527 VOID PlayIcsWinSound()
\r
6529 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
6532 VOID PlayIcsLossSound()
\r
6534 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
6537 VOID PlayIcsDrawSound()
\r
6539 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
6542 VOID PlayIcsUnfinishedSound()
\r
6544 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
6550 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
6558 consoleEcho = TRUE;
\r
6559 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6560 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
6561 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6570 consoleEcho = FALSE;
\r
6571 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6572 /* This works OK: set text and background both to the same color */
\r
6574 cf.crTextColor = COLOR_ECHOOFF;
\r
6575 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6576 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
6579 /* No Raw()...? */
\r
6581 void Colorize(ColorClass cc, int continuation)
\r
6583 currentColorClass = cc;
\r
6584 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6585 consoleCF.crTextColor = textAttribs[cc].color;
\r
6586 consoleCF.dwEffects = textAttribs[cc].effects;
\r
6587 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
6593 static char buf[MSG_SIZ];
\r
6594 DWORD bufsiz = MSG_SIZ;
\r
6596 if (!GetUserName(buf, &bufsiz)) {
\r
6597 /*DisplayError("Error getting user name", GetLastError());*/
\r
6598 strcpy(buf, "User");
\r
6606 static char buf[MSG_SIZ];
\r
6607 DWORD bufsiz = MSG_SIZ;
\r
6609 if (!GetComputerName(buf, &bufsiz)) {
\r
6610 /*DisplayError("Error getting host name", GetLastError());*/
\r
6611 strcpy(buf, "Unknown");
\r
6618 ClockTimerRunning()
\r
6620 return clockTimerEvent != 0;
\r
6626 if (clockTimerEvent == 0) return FALSE;
\r
6627 KillTimer(hwndMain, clockTimerEvent);
\r
6628 clockTimerEvent = 0;
\r
6633 StartClockTimer(long millisec)
\r
6635 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
6636 (UINT) millisec, NULL);
\r
6640 DisplayWhiteClock(long timeRemaining, int highlight)
\r
6643 hdc = GetDC(hwndMain);
\r
6644 if (!IsIconic(hwndMain)) {
\r
6645 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");
\r
6647 if (highlight && iconCurrent == iconBlack) {
\r
6648 iconCurrent = iconWhite;
\r
6649 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6650 if (IsIconic(hwndMain)) {
\r
6651 DrawIcon(hdc, 2, 2, iconCurrent);
\r
6654 (void) ReleaseDC(hwndMain, hdc);
\r
6656 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6660 DisplayBlackClock(long timeRemaining, int highlight)
\r
6663 hdc = GetDC(hwndMain);
\r
6664 if (!IsIconic(hwndMain)) {
\r
6665 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");
\r
6667 if (highlight && iconCurrent == iconWhite) {
\r
6668 iconCurrent = iconBlack;
\r
6669 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6670 if (IsIconic(hwndMain)) {
\r
6671 DrawIcon(hdc, 2, 2, iconCurrent);
\r
6674 (void) ReleaseDC(hwndMain, hdc);
\r
6676 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6681 LoadGameTimerRunning()
\r
6683 return loadGameTimerEvent != 0;
\r
6687 StopLoadGameTimer()
\r
6689 if (loadGameTimerEvent == 0) return FALSE;
\r
6690 KillTimer(hwndMain, loadGameTimerEvent);
\r
6691 loadGameTimerEvent = 0;
\r
6696 StartLoadGameTimer(long millisec)
\r
6698 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
6699 (UINT) millisec, NULL);
\r
6707 char fileTitle[MSG_SIZ];
\r
6709 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
6710 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
6711 appData.oldSaveStyle ? "gam" : "pgn",
\r
6713 "Save Game to File", NULL, fileTitle, NULL);
\r
6715 SaveGame(f, 0, "");
\r
6722 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
6724 if (delayedTimerEvent != 0) {
\r
6725 if (appData.debugMode) {
\r
6726 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
6728 KillTimer(hwndMain, delayedTimerEvent);
\r
6729 delayedTimerEvent = 0;
\r
6730 delayedTimerCallback();
\r
6732 delayedTimerCallback = cb;
\r
6733 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
6734 (UINT) millisec, NULL);
\r
6737 DelayedEventCallback
\r
6740 if (delayedTimerEvent) {
\r
6741 return delayedTimerCallback;
\r
6748 CancelDelayedEvent()
\r
6750 if (delayedTimerEvent) {
\r
6751 KillTimer(hwndMain, delayedTimerEvent);
\r
6752 delayedTimerEvent = 0;
\r
6756 /* Start a child process running the given program.
\r
6757 The process's standard output can be read from "from", and its
\r
6758 standard input can be written to "to".
\r
6759 Exit with fatal error if anything goes wrong.
\r
6760 Returns an opaque pointer that can be used to destroy the process
\r
6764 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
6766 #define BUFSIZE 4096
\r
6768 HANDLE hChildStdinRd, hChildStdinWr,
\r
6769 hChildStdoutRd, hChildStdoutWr;
\r
6770 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
6771 SECURITY_ATTRIBUTES saAttr;
\r
6773 PROCESS_INFORMATION piProcInfo;
\r
6774 STARTUPINFO siStartInfo;
\r
6776 char buf[MSG_SIZ];
\r
6779 if (appData.debugMode) {
\r
6780 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
6785 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
6786 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
6787 saAttr.bInheritHandle = TRUE;
\r
6788 saAttr.lpSecurityDescriptor = NULL;
\r
6791 * The steps for redirecting child's STDOUT:
\r
6792 * 1. Create anonymous pipe to be STDOUT for child.
\r
6793 * 2. Create a noninheritable duplicate of read handle,
\r
6794 * and close the inheritable read handle.
\r
6797 /* Create a pipe for the child's STDOUT. */
\r
6798 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
6799 return GetLastError();
\r
6802 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
6803 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
6804 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
6805 FALSE, /* not inherited */
\r
6806 DUPLICATE_SAME_ACCESS);
\r
6808 return GetLastError();
\r
6810 CloseHandle(hChildStdoutRd);
\r
6813 * The steps for redirecting child's STDIN:
\r
6814 * 1. Create anonymous pipe to be STDIN for child.
\r
6815 * 2. Create a noninheritable duplicate of write handle,
\r
6816 * and close the inheritable write handle.
\r
6819 /* Create a pipe for the child's STDIN. */
\r
6820 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
6821 return GetLastError();
\r
6824 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
6825 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
6826 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
6827 FALSE, /* not inherited */
\r
6828 DUPLICATE_SAME_ACCESS);
\r
6830 return GetLastError();
\r
6832 CloseHandle(hChildStdinWr);
\r
6834 /* Arrange to (1) look in dir for the child .exe file, and
\r
6835 * (2) have dir be the child's working directory. Interpret
\r
6836 * dir relative to the directory WinBoard loaded from. */
\r
6837 GetCurrentDirectory(MSG_SIZ, buf);
\r
6838 SetCurrentDirectory(installDir);
\r
6839 SetCurrentDirectory(dir);
\r
6841 /* Now create the child process. */
\r
6843 siStartInfo.cb = sizeof(STARTUPINFO);
\r
6844 siStartInfo.lpReserved = NULL;
\r
6845 siStartInfo.lpDesktop = NULL;
\r
6846 siStartInfo.lpTitle = NULL;
\r
6847 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
6848 siStartInfo.cbReserved2 = 0;
\r
6849 siStartInfo.lpReserved2 = NULL;
\r
6850 siStartInfo.hStdInput = hChildStdinRd;
\r
6851 siStartInfo.hStdOutput = hChildStdoutWr;
\r
6852 siStartInfo.hStdError = hChildStdoutWr;
\r
6854 fSuccess = CreateProcess(NULL,
\r
6855 cmdLine, /* command line */
\r
6856 NULL, /* process security attributes */
\r
6857 NULL, /* primary thread security attrs */
\r
6858 TRUE, /* handles are inherited */
\r
6859 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
6860 NULL, /* use parent's environment */
\r
6862 &siStartInfo, /* STARTUPINFO pointer */
\r
6863 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
6865 err = GetLastError();
\r
6866 SetCurrentDirectory(buf); /* return to prev directory */
\r
6871 /* Close the handles we don't need in the parent */
\r
6872 CloseHandle(piProcInfo.hThread);
\r
6873 CloseHandle(hChildStdinRd);
\r
6874 CloseHandle(hChildStdoutWr);
\r
6876 /* Prepare return value */
\r
6877 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
6878 cp->kind = CPReal;
\r
6879 cp->hProcess = piProcInfo.hProcess;
\r
6880 cp->pid = piProcInfo.dwProcessId;
\r
6881 cp->hFrom = hChildStdoutRdDup;
\r
6882 cp->hTo = hChildStdinWrDup;
\r
6884 *pr = (void *) cp;
\r
6886 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
6887 2000 where engines sometimes don't see the initial command(s)
\r
6888 from WinBoard and hang. I don't understand how that can happen,
\r
6889 but the Sleep is harmless, so I've put it in. Others have also
\r
6890 reported what may be the same problem, so hopefully this will fix
\r
6891 it for them too. */
\r
6899 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
6903 cp = (ChildProc *) pr;
\r
6904 if (cp == NULL) return;
\r
6906 switch (cp->kind) {
\r
6908 /* TerminateProcess is considered harmful, so... */
\r
6909 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
6910 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
6911 /* The following doesn't work because the chess program
\r
6912 doesn't "have the same console" as WinBoard. Maybe
\r
6913 we could arrange for this even though neither WinBoard
\r
6914 nor the chess program uses a console for stdio? */
\r
6915 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
6916 CloseHandle(cp->hProcess);
\r
6920 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
6924 closesocket(cp->sock);
\r
6929 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
6930 closesocket(cp->sock);
\r
6931 closesocket(cp->sock2);
\r
6939 InterruptChildProcess(ProcRef pr)
\r
6943 cp = (ChildProc *) pr;
\r
6944 if (cp == NULL) return;
\r
6945 switch (cp->kind) {
\r
6947 /* The following doesn't work because the chess program
\r
6948 doesn't "have the same console" as WinBoard. Maybe
\r
6949 we could arrange for this even though neither WinBoard
\r
6950 nor the chess program uses a console for stdio */
\r
6951 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
6956 /* Can't interrupt */
\r
6960 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
6967 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
6969 char cmdLine[MSG_SIZ];
\r
6971 if (port[0] == NULLCHAR) {
\r
6972 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
6974 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
6976 return StartChildProcess(cmdLine, "", pr);
\r
6980 /* Code to open TCP sockets */
\r
6983 OpenTCP(char *host, char *port, ProcRef *pr)
\r
6988 struct sockaddr_in sa, mysa;
\r
6989 struct hostent FAR *hp;
\r
6990 unsigned short uport;
\r
6991 WORD wVersionRequested;
\r
6994 /* Initialize socket DLL */
\r
6995 wVersionRequested = MAKEWORD(1, 1);
\r
6996 err = WSAStartup(wVersionRequested, &wsaData);
\r
6997 if (err != 0) return err;
\r
7000 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7001 err = WSAGetLastError();
\r
7006 /* Bind local address using (mostly) don't-care values.
\r
7008 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7009 mysa.sin_family = AF_INET;
\r
7010 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7011 uport = (unsigned short) 0;
\r
7012 mysa.sin_port = htons(uport);
\r
7013 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7014 == SOCKET_ERROR) {
\r
7015 err = WSAGetLastError();
\r
7020 /* Resolve remote host name */
\r
7021 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7022 if (!(hp = gethostbyname(host))) {
\r
7023 unsigned int b0, b1, b2, b3;
\r
7025 err = WSAGetLastError();
\r
7027 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7028 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7029 hp->h_addrtype = AF_INET;
\r
7031 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7032 hp->h_addr_list[0] = (char *) malloc(4);
\r
7033 hp->h_addr_list[0][0] = (char) b0;
\r
7034 hp->h_addr_list[0][1] = (char) b1;
\r
7035 hp->h_addr_list[0][2] = (char) b2;
\r
7036 hp->h_addr_list[0][3] = (char) b3;
\r
7042 sa.sin_family = hp->h_addrtype;
\r
7043 uport = (unsigned short) atoi(port);
\r
7044 sa.sin_port = htons(uport);
\r
7045 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7047 /* Make connection */
\r
7048 if (connect(s, (struct sockaddr *) &sa,
\r
7049 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7050 err = WSAGetLastError();
\r
7055 /* Prepare return value */
\r
7056 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7057 cp->kind = CPSock;
\r
7059 *pr = (ProcRef *) cp;
\r
7065 OpenCommPort(char *name, ProcRef *pr)
\r
7070 char fullname[MSG_SIZ];
\r
7072 if (*name != '\\')
\r
7073 sprintf(fullname, "\\\\.\\%s", name);
\r
7075 strcpy(fullname, name);
\r
7077 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
7078 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
7079 if (h == (HANDLE) -1) {
\r
7080 return GetLastError();
\r
7084 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
7086 /* Accumulate characters until a 100ms pause, then parse */
\r
7087 ct.ReadIntervalTimeout = 100;
\r
7088 ct.ReadTotalTimeoutMultiplier = 0;
\r
7089 ct.ReadTotalTimeoutConstant = 0;
\r
7090 ct.WriteTotalTimeoutMultiplier = 0;
\r
7091 ct.WriteTotalTimeoutConstant = 0;
\r
7092 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
7094 /* Prepare return value */
\r
7095 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7096 cp->kind = CPComm;
\r
7099 *pr = (ProcRef *) cp;
\r
7105 OpenLoopback(ProcRef *pr)
\r
7107 DisplayFatalError("Not implemented", 0, 1);
\r
7113 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
7118 struct sockaddr_in sa, mysa;
\r
7119 struct hostent FAR *hp;
\r
7120 unsigned short uport;
\r
7121 WORD wVersionRequested;
\r
7124 char stderrPortStr[MSG_SIZ];
\r
7126 /* Initialize socket DLL */
\r
7127 wVersionRequested = MAKEWORD(1, 1);
\r
7128 err = WSAStartup(wVersionRequested, &wsaData);
\r
7129 if (err != 0) return err;
\r
7131 /* Resolve remote host name */
\r
7132 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7133 if (!(hp = gethostbyname(host))) {
\r
7134 unsigned int b0, b1, b2, b3;
\r
7136 err = WSAGetLastError();
\r
7138 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7139 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7140 hp->h_addrtype = AF_INET;
\r
7142 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7143 hp->h_addr_list[0] = (char *) malloc(4);
\r
7144 hp->h_addr_list[0][0] = (char) b0;
\r
7145 hp->h_addr_list[0][1] = (char) b1;
\r
7146 hp->h_addr_list[0][2] = (char) b2;
\r
7147 hp->h_addr_list[0][3] = (char) b3;
\r
7153 sa.sin_family = hp->h_addrtype;
\r
7154 uport = (unsigned short) 514;
\r
7155 sa.sin_port = htons(uport);
\r
7156 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7158 /* Bind local socket to unused "privileged" port address
\r
7160 s = INVALID_SOCKET;
\r
7161 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7162 mysa.sin_family = AF_INET;
\r
7163 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7164 for (fromPort = 1023;; fromPort--) {
\r
7165 if (fromPort < 0) {
\r
7167 return WSAEADDRINUSE;
\r
7169 if (s == INVALID_SOCKET) {
\r
7170 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7171 err = WSAGetLastError();
\r
7176 uport = (unsigned short) fromPort;
\r
7177 mysa.sin_port = htons(uport);
\r
7178 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7179 == SOCKET_ERROR) {
\r
7180 err = WSAGetLastError();
\r
7181 if (err == WSAEADDRINUSE) continue;
\r
7185 if (connect(s, (struct sockaddr *) &sa,
\r
7186 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7187 err = WSAGetLastError();
\r
7188 if (err == WSAEADDRINUSE) {
\r
7199 /* Bind stderr local socket to unused "privileged" port address
\r
7201 s2 = INVALID_SOCKET;
\r
7202 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7203 mysa.sin_family = AF_INET;
\r
7204 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7205 for (fromPort = 1023;; fromPort--) {
\r
7206 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
7207 if (fromPort < 0) {
\r
7208 (void) closesocket(s);
\r
7210 return WSAEADDRINUSE;
\r
7212 if (s2 == INVALID_SOCKET) {
\r
7213 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7214 err = WSAGetLastError();
\r
7220 uport = (unsigned short) fromPort;
\r
7221 mysa.sin_port = htons(uport);
\r
7222 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7223 == SOCKET_ERROR) {
\r
7224 err = WSAGetLastError();
\r
7225 if (err == WSAEADDRINUSE) continue;
\r
7226 (void) closesocket(s);
\r
7230 if (listen(s2, 1) == SOCKET_ERROR) {
\r
7231 err = WSAGetLastError();
\r
7232 if (err == WSAEADDRINUSE) {
\r
7234 s2 = INVALID_SOCKET;
\r
7237 (void) closesocket(s);
\r
7238 (void) closesocket(s2);
\r
7244 prevStderrPort = fromPort; // remember port used
\r
7245 sprintf(stderrPortStr, "%d", fromPort);
\r
7247 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
7248 err = WSAGetLastError();
\r
7249 (void) closesocket(s);
\r
7250 (void) closesocket(s2);
\r
7255 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
7256 err = WSAGetLastError();
\r
7257 (void) closesocket(s);
\r
7258 (void) closesocket(s2);
\r
7262 if (*user == NULLCHAR) user = UserName();
\r
7263 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
7264 err = WSAGetLastError();
\r
7265 (void) closesocket(s);
\r
7266 (void) closesocket(s2);
\r
7270 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
7271 err = WSAGetLastError();
\r
7272 (void) closesocket(s);
\r
7273 (void) closesocket(s2);
\r
7278 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
7279 err = WSAGetLastError();
\r
7280 (void) closesocket(s);
\r
7281 (void) closesocket(s2);
\r
7285 (void) closesocket(s2); /* Stop listening */
\r
7287 /* Prepare return value */
\r
7288 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7289 cp->kind = CPRcmd;
\r
7292 *pr = (ProcRef *) cp;
\r
7299 AddInputSource(ProcRef pr, int lineByLine,
\r
7300 InputCallback func, VOIDSTAR closure)
\r
7302 InputSource *is, *is2;
\r
7303 ChildProc *cp = (ChildProc *) pr;
\r
7305 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
7306 is->lineByLine = lineByLine;
\r
7308 is->closure = closure;
\r
7309 is->second = NULL;
\r
7310 is->next = is->buf;
\r
7311 if (pr == NoProc) {
\r
7312 is->kind = CPReal;
\r
7313 consoleInputSource = is;
\r
7315 is->kind = cp->kind;
\r
7316 switch (cp->kind) {
\r
7318 is->hFile = cp->hFrom;
\r
7319 cp->hFrom = NULL; /* now owned by InputThread */
\r
7321 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
7322 (LPVOID) is, 0, &is->id);
\r
7326 is->hFile = cp->hFrom;
\r
7327 cp->hFrom = NULL; /* now owned by InputThread */
\r
7329 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
7330 (LPVOID) is, 0, &is->id);
\r
7334 is->sock = cp->sock;
\r
7336 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7337 (LPVOID) is, 0, &is->id);
\r
7341 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
7343 is->sock = cp->sock;
\r
7345 is2->sock = cp->sock2;
\r
7346 is2->second = is2;
\r
7348 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7349 (LPVOID) is, 0, &is->id);
\r
7351 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7352 (LPVOID) is2, 0, &is2->id);
\r
7356 return (InputSourceRef) is;
\r
7360 RemoveInputSource(InputSourceRef isr)
\r
7364 is = (InputSource *) isr;
\r
7365 is->hThread = NULL; /* tell thread to stop */
\r
7366 CloseHandle(is->hThread);
\r
7367 if (is->second != NULL) {
\r
7368 is->second->hThread = NULL;
\r
7369 CloseHandle(is->second->hThread);
\r
7375 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
7378 int outCount = SOCKET_ERROR;
\r
7379 ChildProc *cp = (ChildProc *) pr;
\r
7380 static OVERLAPPED ovl;
\r
7382 if (pr == NoProc) {
\r
7383 ConsoleOutput(message, count, FALSE);
\r
7387 if (ovl.hEvent == NULL) {
\r
7388 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7390 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7392 switch (cp->kind) {
\r
7395 outCount = send(cp->sock, message, count, 0);
\r
7396 if (outCount == SOCKET_ERROR) {
\r
7397 *outError = WSAGetLastError();
\r
7399 *outError = NO_ERROR;
\r
7404 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
7405 &dOutCount, NULL)) {
\r
7406 *outError = NO_ERROR;
\r
7407 outCount = (int) dOutCount;
\r
7409 *outError = GetLastError();
\r
7414 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
7415 &dOutCount, &ovl);
\r
7416 if (*outError == NO_ERROR) {
\r
7417 outCount = (int) dOutCount;
\r
7425 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
7428 /* Ignore delay, not implemented for WinBoard */
\r
7429 return OutputToProcess(pr, message, count, outError);
\r
7434 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
7435 char *buf, int count, int error)
\r
7437 DisplayFatalError("Not implemented", 0, 1);
\r
7440 /* see wgamelist.c for Game List functions */
\r
7441 /* see wedittags.c for Edit Tags functions */
\r
7448 char buf[MSG_SIZ];
\r
7451 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
7452 f = fopen(buf, "r");
\r
7454 ProcessICSInitScript(f);
\r
7462 StartAnalysisClock()
\r
7464 if (analysisTimerEvent) return;
\r
7465 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
7466 (UINT) 2000, NULL);
\r
7470 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7472 static HANDLE hwndText;
\r
7474 static int sizeX, sizeY;
\r
7475 int newSizeX, newSizeY, flags;
\r
7478 switch (message) {
\r
7479 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7480 /* Initialize the dialog items */
\r
7481 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
7482 SetWindowText(hDlg, analysisTitle);
\r
7483 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
7484 /* Size and position the dialog */
\r
7485 if (!analysisDialog) {
\r
7486 analysisDialog = hDlg;
\r
7487 flags = SWP_NOZORDER;
\r
7488 GetClientRect(hDlg, &rect);
\r
7489 sizeX = rect.right;
\r
7490 sizeY = rect.bottom;
\r
7491 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
7492 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
7493 WINDOWPLACEMENT wp;
\r
7494 EnsureOnScreen(&analysisX, &analysisY);
\r
7495 wp.length = sizeof(WINDOWPLACEMENT);
\r
7497 wp.showCmd = SW_SHOW;
\r
7498 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7499 wp.rcNormalPosition.left = analysisX;
\r
7500 wp.rcNormalPosition.right = analysisX + analysisW;
\r
7501 wp.rcNormalPosition.top = analysisY;
\r
7502 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
7503 SetWindowPlacement(hDlg, &wp);
\r
7505 GetClientRect(hDlg, &rect);
\r
7506 newSizeX = rect.right;
\r
7507 newSizeY = rect.bottom;
\r
7508 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7509 newSizeX, newSizeY);
\r
7516 case WM_COMMAND: /* message: received a command */
\r
7517 switch (LOWORD(wParam)) {
\r
7527 newSizeX = LOWORD(lParam);
\r
7528 newSizeY = HIWORD(lParam);
\r
7529 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7534 case WM_GETMINMAXINFO:
\r
7535 /* Prevent resizing window too small */
\r
7536 mmi = (MINMAXINFO *) lParam;
\r
7537 mmi->ptMinTrackSize.x = 100;
\r
7538 mmi->ptMinTrackSize.y = 100;
\r
7545 AnalysisPopUp(char* title, char* str)
\r
7550 if (str == NULL) str = "";
\r
7551 p = (char *) malloc(2 * strlen(str) + 2);
\r
7554 if (*str == '\n') *q++ = '\r';
\r
7558 if (analysisText != NULL) free(analysisText);
\r
7561 if (analysisDialog) {
\r
7562 SetWindowText(analysisDialog, title);
\r
7563 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
7564 ShowWindow(analysisDialog, SW_SHOW);
\r
7566 analysisTitle = title;
\r
7567 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
7568 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
7569 hwndMain, (DLGPROC)lpProc);
\r
7570 FreeProcInstance(lpProc);
\r
7572 analysisDialogUp = TRUE;
\r
7578 if (analysisDialog) {
\r
7579 ShowWindow(analysisDialog, SW_HIDE);
\r
7581 analysisDialogUp = FALSE;
\r
7586 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
7588 highlightInfo.sq[0].x = fromX;
\r
7589 highlightInfo.sq[0].y = fromY;
\r
7590 highlightInfo.sq[1].x = toX;
\r
7591 highlightInfo.sq[1].y = toY;
\r
7597 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
7598 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
7602 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
7604 premoveHighlightInfo.sq[0].x = fromX;
\r
7605 premoveHighlightInfo.sq[0].y = fromY;
\r
7606 premoveHighlightInfo.sq[1].x = toX;
\r
7607 premoveHighlightInfo.sq[1].y = toY;
\r
7611 ClearPremoveHighlights()
\r
7613 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
7614 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
7618 ShutDownFrontEnd()
\r
7620 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
7621 DeleteClipboardTempFiles();
\r
7627 if (IsIconic(hwndMain))
\r
7628 ShowWindow(hwndMain, SW_RESTORE);
\r
7630 SetActiveWindow(hwndMain);
\r
7634 * Prototypes for animation support routines
\r
7636 static void ScreenSquare(int column, int row, POINT * pt);
\r
7637 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
7638 POINT frames[], int * nFrames);
\r
7644 AnimateMove(board, fromX, fromY, toX, toY)
\r
7651 ChessSquare piece;
\r
7652 POINT start, finish, mid;
\r
7653 POINT frames[kFactor * 2 + 1];
\r
7656 if (!appData.animate) return;
\r
7657 if (doingSizing) return;
\r
7658 if (fromY < 0 || fromX < 0) return;
\r
7659 piece = board[fromY][fromX];
\r
7660 if (piece >= EmptySquare) return;
\r
7662 ScreenSquare(fromX, fromY, &start);
\r
7663 ScreenSquare(toX, toY, &finish);
\r
7665 /* All pieces except knights move in straight line */
\r
7666 if (piece != WhiteKnight && piece != BlackKnight) {
\r
7667 mid.x = start.x + (finish.x - start.x) / 2;
\r
7668 mid.y = start.y + (finish.y - start.y) / 2;
\r
7670 /* Knight: make diagonal movement then straight */
\r
7671 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
7672 mid.x = start.x + (finish.x - start.x) / 2;
\r
7676 mid.y = start.y + (finish.y - start.y) / 2;
\r
7680 /* Don't use as many frames for very short moves */
\r
7681 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
7682 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
7684 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
7686 animInfo.from.x = fromX;
\r
7687 animInfo.from.y = fromY;
\r
7688 animInfo.to.x = toX;
\r
7689 animInfo.to.y = toY;
\r
7690 animInfo.lastpos = start;
\r
7691 animInfo.piece = piece;
\r
7692 for (n = 0; n < nFrames; n++) {
\r
7693 animInfo.pos = frames[n];
\r
7694 DrawPosition(FALSE, NULL);
\r
7695 animInfo.lastpos = animInfo.pos;
\r
7696 Sleep(appData.animSpeed);
\r
7698 animInfo.pos = finish;
\r
7699 DrawPosition(FALSE, NULL);
\r
7700 animInfo.piece = EmptySquare;
\r
7703 /* Convert board position to corner of screen rect and color */
\r
7706 ScreenSquare(column, row, pt)
\r
7707 int column; int row; POINT * pt;
\r
7710 pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
7711 pt->y = lineGap + row * (squareSize + lineGap);
\r
7713 pt->x = lineGap + column * (squareSize + lineGap);
\r
7714 pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
7718 /* Generate a series of frame coords from start->mid->finish.
\r
7719 The movement rate doubles until the half way point is
\r
7720 reached, then halves back down to the final destination,
\r
7721 which gives a nice slow in/out effect. The algorithmn
\r
7722 may seem to generate too many intermediates for short
\r
7723 moves, but remember that the purpose is to attract the
\r
7724 viewers attention to the piece about to be moved and
\r
7725 then to where it ends up. Too few frames would be less
\r
7729 Tween(start, mid, finish, factor, frames, nFrames)
\r
7730 POINT * start; POINT * mid;
\r
7731 POINT * finish; int factor;
\r
7732 POINT frames[]; int * nFrames;
\r
7734 int n, fraction = 1, count = 0;
\r
7736 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
7737 for (n = 0; n < factor; n++)
\r
7739 for (n = 0; n < factor; n++) {
\r
7740 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
7741 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
7743 fraction = fraction / 2;
\r
7747 frames[count] = *mid;
\r
7750 /* Slow out, stepping 1/2, then 1/4, ... */
\r
7752 for (n = 0; n < factor; n++) {
\r
7753 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
7754 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
7756 fraction = fraction * 2;
\r
7762 HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current)
\r
7764 /* Currently not implemented in WinBoard */
\r