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 errorTitle[MSG_SIZ];
\r
341 char errorMessage[2*MSG_SIZ];
\r
342 HWND errorDialog = NULL;
\r
343 BOOLEAN moveErrorMessageUp = FALSE;
\r
344 BOOLEAN consoleEcho = TRUE;
\r
345 CHARFORMAT consoleCF;
\r
346 COLORREF consoleBackgroundColor;
\r
348 char *programVersion;
\r
354 typedef int CPKind;
\r
363 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
366 #define INPUT_SOURCE_BUF_SIZE 4096
\r
368 typedef struct _InputSource {
\r
375 char buf[INPUT_SOURCE_BUF_SIZE];
\r
379 InputCallback func;
\r
380 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
384 InputSource *consoleInputSource;
\r
389 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
390 VOID ConsoleCreate();
\r
392 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
393 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
394 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
395 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
397 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
398 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
399 void ParseIcsTextMenu(char *icsTextMenuString);
\r
400 VOID PopUpMoveDialog(char firstchar);
\r
401 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
404 * Setting "frozen" should disable all user input other than deleting
\r
405 * the window. We do this while engines are initializing themselves.
\r
407 static int frozen = 0;
\r
408 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
414 if (frozen) return;
\r
416 hmenu = GetMenu(hwndMain);
\r
417 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
418 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
420 DrawMenuBar(hwndMain);
\r
423 /* Undo a FreezeUI */
\r
429 if (!frozen) return;
\r
431 hmenu = GetMenu(hwndMain);
\r
432 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
433 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
435 DrawMenuBar(hwndMain);
\r
438 /*---------------------------------------------------------------------------*\
\r
442 \*---------------------------------------------------------------------------*/
\r
445 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
446 LPSTR lpCmdLine, int nCmdShow)
\r
449 HANDLE hAccelMain, hAccelNoAlt;
\r
453 LoadLibrary("RICHED32.DLL");
\r
454 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
456 if (!InitApplication(hInstance)) {
\r
459 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
463 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
464 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
466 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
468 while (GetMessage(&msg, /* message structure */
\r
469 NULL, /* handle of window receiving the message */
\r
470 0, /* lowest message to examine */
\r
471 0)) /* highest message to examine */
\r
473 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
474 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
475 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
476 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
477 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
478 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
479 TranslateMessage(&msg); /* Translates virtual key codes */
\r
480 DispatchMessage(&msg); /* Dispatches message to window */
\r
485 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
488 /*---------------------------------------------------------------------------*\
\r
490 * Initialization functions
\r
492 \*---------------------------------------------------------------------------*/
\r
495 InitApplication(HINSTANCE hInstance)
\r
499 /* Fill in window class structure with parameters that describe the */
\r
502 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
503 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
504 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
505 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
506 wc.hInstance = hInstance; /* Owner of this class */
\r
507 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
508 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
509 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
510 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
511 wc.lpszClassName = szAppName; /* Name to register as */
\r
513 /* Register the window class and return success/failure code. */
\r
514 if (!RegisterClass(&wc)) return FALSE;
\r
516 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
517 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
519 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
520 wc.hInstance = hInstance;
\r
521 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
522 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
523 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
524 wc.lpszMenuName = NULL;
\r
525 wc.lpszClassName = szConsoleName;
\r
527 if (!RegisterClass(&wc)) return FALSE;
\r
532 /* Set by InitInstance, used by EnsureOnScreen */
\r
533 int screenHeight, screenWidth;
\r
536 EnsureOnScreen(int *x, int *y)
\r
538 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
539 if (*x > screenWidth - 32) *x = 0;
\r
540 if (*y > screenHeight - 32) *y = 0;
\r
544 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
546 HWND hwnd; /* Main window handle. */
\r
548 WINDOWPLACEMENT wp;
\r
551 hInst = hInstance; /* Store instance handle in our global variable */
\r
553 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
554 *filepart = NULLCHAR;
\r
556 GetCurrentDirectory(MSG_SIZ, installDir);
\r
558 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
559 if (appData.debugMode) {
\r
560 debugFP = fopen("winboard.debug", "w");
\r
561 setbuf(debugFP, NULL);
\r
566 /* Create a main window for this application instance. */
\r
567 hwnd = CreateWindow(szAppName, szTitle,
\r
568 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
569 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
570 NULL, NULL, hInstance, NULL);
\r
573 /* If window could not be created, return "failure" */
\r
578 iconWhite = LoadIcon(hInstance, "icon_white");
\r
579 iconBlack = LoadIcon(hInstance, "icon_black");
\r
580 iconCurrent = iconWhite;
\r
581 InitDrawingColors();
\r
582 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
583 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
584 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
585 /* Compute window size for each board size, and use the largest
\r
586 size that fits on this screen as the default. */
\r
587 InitDrawingSizes((BoardSize)ibs, 0);
\r
588 if (boardSize == (BoardSize)-1 &&
\r
589 winHeight <= screenHeight && winWidth <= screenWidth) {
\r
590 boardSize = (BoardSize)ibs;
\r
593 InitDrawingSizes(boardSize, 0);
\r
595 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
597 /* Make a console window if needed */
\r
598 if (appData.icsActive) {
\r
604 /* Make the window visible; update its client area; and return "success" */
\r
605 EnsureOnScreen(&boardX, &boardY);
\r
606 wp.length = sizeof(WINDOWPLACEMENT);
\r
608 wp.showCmd = nCmdShow;
\r
609 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
610 wp.rcNormalPosition.left = boardX;
\r
611 wp.rcNormalPosition.right = boardX + winWidth;
\r
612 wp.rcNormalPosition.top = boardY;
\r
613 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
614 SetWindowPlacement(hwndMain, &wp);
\r
616 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
617 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
620 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
621 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
623 ShowWindow(hwndConsole, nCmdShow);
\r
625 UpdateWindow(hwnd);
\r
633 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
634 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
635 ArgSettingsFilename
\r
643 String *pString; // ArgString
\r
644 int *pInt; // ArgInt
\r
645 float *pFloat; // ArgFloat
\r
646 Boolean *pBoolean; // ArgBoolean
\r
647 COLORREF *pColor; // ArgColor
\r
648 ColorClass cc; // ArgAttribs
\r
649 String *pFilename; // ArgFilename
\r
650 BoardSize *pBoardSize; // ArgBoardSize
\r
651 int whichFont; // ArgFont
\r
652 DCB *pDCB; // ArgCommSettings
\r
653 String *pFilename; // ArgSettingsFilename
\r
661 ArgDescriptor argDescriptors[] = {
\r
662 /* positional arguments */
\r
663 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
664 { "", ArgNone, NULL },
\r
665 /* keyword arguments */
\r
666 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
667 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
668 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
669 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
670 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
671 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
672 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
673 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
674 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
675 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
676 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
677 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
678 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
679 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
680 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
681 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
682 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
683 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
685 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
687 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
689 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
690 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
692 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
693 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
694 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
695 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
696 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
697 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
698 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
699 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
700 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
701 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
702 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
703 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
704 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
705 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
706 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
707 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
708 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
709 /*!!bitmapDirectory?*/
\r
710 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
711 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
712 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
713 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
714 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
715 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
716 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
717 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
718 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
719 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
720 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
721 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
722 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
723 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
724 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
725 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
726 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
727 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
728 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
729 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
730 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
731 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
732 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
733 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
734 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
735 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
736 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
737 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
738 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
739 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
740 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
741 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
742 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
743 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
744 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
745 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
746 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
747 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
748 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
749 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
750 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
751 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
752 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
753 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
754 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
755 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
756 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
757 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
758 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
759 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
760 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
761 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
762 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
763 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
764 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
765 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
766 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
767 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
768 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
769 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
770 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
771 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
772 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
773 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
774 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
775 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
776 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
777 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
778 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
779 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
780 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
781 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
782 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
783 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
784 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
785 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
786 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
787 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
788 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
789 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
790 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
791 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
792 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
793 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
794 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
795 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
796 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
797 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
798 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
799 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
800 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
801 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
802 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
803 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
804 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
805 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
806 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
807 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
808 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
809 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
810 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
811 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
812 TRUE }, /* must come after all fonts */
\r
813 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
814 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
815 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
816 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
817 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
818 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
819 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
820 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
821 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
822 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
823 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
824 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
825 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
826 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
827 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
828 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
829 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
830 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
831 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
832 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
833 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
834 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
835 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
836 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
837 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
838 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
839 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
840 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
841 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
842 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
843 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
845 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
846 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
848 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
849 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
850 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
851 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
852 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
853 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
854 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
855 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
856 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
857 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
858 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
859 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
860 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
861 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
862 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
863 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
864 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
865 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
866 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
867 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
868 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
869 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
870 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
871 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
872 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
873 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
874 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
875 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
876 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
877 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
878 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
879 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
880 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
881 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
882 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
883 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
884 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
885 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
886 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
887 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
888 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
889 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
890 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
891 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
892 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
893 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
894 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
895 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
896 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
897 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
898 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
899 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
900 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
901 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
902 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
903 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
904 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
905 { "highlightLastMove", ArgBoolean,
\r
906 (LPVOID) &appData.highlightLastMove, TRUE },
\r
907 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
908 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
909 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
910 { "highlightDragging", ArgBoolean,
\r
911 (LPVOID) &appData.highlightDragging, TRUE },
\r
912 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
913 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
914 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
915 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
916 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
917 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
918 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
919 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
920 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
921 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
922 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
923 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
924 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
925 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
926 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
927 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
928 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
929 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
930 { "soundShout", ArgFilename,
\r
931 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
932 { "soundSShout", ArgFilename,
\r
933 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
934 { "soundChannel1", ArgFilename,
\r
935 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
936 { "soundChannel", ArgFilename,
\r
937 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
938 { "soundKibitz", ArgFilename,
\r
939 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
940 { "soundTell", ArgFilename,
\r
941 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
942 { "soundChallenge", ArgFilename,
\r
943 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
944 { "soundRequest", ArgFilename,
\r
945 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
946 { "soundSeek", ArgFilename,
\r
947 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
948 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
949 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
950 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
951 { "soundIcsLoss", ArgFilename,
\r
952 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
953 { "soundIcsDraw", ArgFilename,
\r
954 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
955 { "soundIcsUnfinished", ArgFilename,
\r
956 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
957 { "soundIcsAlarm", ArgFilename,
\r
958 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
959 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
960 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
961 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
962 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
963 { "reuseChessPrograms", ArgBoolean,
\r
964 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
965 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
966 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
967 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
968 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
969 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
970 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
971 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
972 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
973 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
974 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
975 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
976 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
977 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
978 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
979 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
980 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
981 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
982 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
983 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
984 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
985 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
986 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
987 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
988 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
989 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
990 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
991 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
992 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
993 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
994 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
995 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
996 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
997 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
998 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
999 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1000 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1001 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1003 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1005 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1006 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1007 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1008 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion,
\r
1010 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,
\r
1012 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1013 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1014 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1015 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1017 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1018 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1019 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1020 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1021 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1022 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1023 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1024 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1025 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1026 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1027 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1028 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1029 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1031 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1032 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1033 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1034 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1035 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1036 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1037 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1039 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1040 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1041 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1042 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1043 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1044 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1045 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1046 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1047 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1048 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1049 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1050 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1051 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1052 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1053 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1054 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1055 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1056 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1058 { NULL, ArgNone, NULL, FALSE }
\r
1062 /* Kludge for indirection files on command line */
\r
1063 char* lastIndirectionFilename;
\r
1064 ArgDescriptor argDescriptorIndirection =
\r
1065 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1069 ExitArgError(char *msg, char *badArg)
\r
1071 char buf[MSG_SIZ];
\r
1073 sprintf(buf, "%s %s", msg, badArg);
\r
1074 DisplayFatalError(buf, 0, 2);
\r
1078 /* Command line font name parser. NULL name means do nothing.
\r
1079 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1080 For backward compatibility, syntax without the colon is also
\r
1081 accepted, but font names with digits in them won't work in that case.
\r
1084 ParseFontName(char *name, MyFontParams *mfp)
\r
1087 if (name == NULL) return;
\r
1089 q = strchr(p, ':');
\r
1091 if (q - p >= sizeof(mfp->faceName))
\r
1092 ExitArgError("Font name too long:", name);
\r
1093 memcpy(mfp->faceName, p, q - p);
\r
1094 mfp->faceName[q - p] = NULLCHAR;
\r
1097 q = mfp->faceName;
\r
1098 while (*p && !isdigit(*p)) {
\r
1100 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1101 ExitArgError("Font name too long:", name);
\r
1103 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1106 if (!*p) ExitArgError("Font point size missing:", name);
\r
1107 mfp->pointSize = (float) atof(p);
\r
1108 mfp->bold = (strchr(p, 'b') != NULL);
\r
1109 mfp->italic = (strchr(p, 'i') != NULL);
\r
1110 mfp->underline = (strchr(p, 'u') != NULL);
\r
1111 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1114 /* Color name parser.
\r
1115 X version accepts X color names, but this one
\r
1116 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1118 ParseColorName(char *name)
\r
1120 int red, green, blue, count;
\r
1121 char buf[MSG_SIZ];
\r
1123 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1125 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1126 &red, &green, &blue);
\r
1129 sprintf(buf, "Can't parse color name %s", name);
\r
1130 DisplayError(buf, 0);
\r
1131 return RGB(0, 0, 0);
\r
1133 return PALETTERGB(red, green, blue);
\r
1137 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1139 char *e = argValue;
\r
1143 if (*e == 'b') eff |= CFE_BOLD;
\r
1144 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1145 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1146 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1147 else if (*e == '#' || isdigit(*e)) break;
\r
1151 *color = ParseColorName(e);
\r
1156 ParseBoardSize(char *name)
\r
1158 BoardSize bs = SizeTiny;
\r
1159 while (sizeInfo[bs].name != NULL) {
\r
1160 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1163 ExitArgError("Unrecognized board size value", name);
\r
1164 return bs; /* not reached */
\r
1169 StringGet(void *getClosure)
\r
1171 char **p = (char **) getClosure;
\r
1176 FileGet(void *getClosure)
\r
1179 FILE* f = (FILE*) getClosure;
\r
1188 /* Parse settings file named "name". If file found, return the
\r
1189 full name in fullname and return TRUE; else return FALSE */
\r
1191 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1196 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1197 f = fopen(fullname, "r");
\r
1199 ParseArgs(FileGet, f);
\r
1208 ParseArgs(GetFunc get, void *cl)
\r
1210 char argName[ARG_MAX];
\r
1211 char argValue[ARG_MAX];
\r
1212 ArgDescriptor *ad;
\r
1221 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1222 if (ch == NULLCHAR) break;
\r
1224 /* Comment to end of line */
\r
1226 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1228 } else if (ch == '/' || ch == '-') {
\r
1231 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1232 ch != '\n' && ch != '\t') {
\r
1238 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1239 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1241 if (ad->argName == NULL)
\r
1242 ExitArgError("Unrecognized argument", argName);
\r
1244 } else if (ch == '@') {
\r
1245 /* Indirection file */
\r
1246 ad = &argDescriptorIndirection;
\r
1249 /* Positional argument */
\r
1250 ad = &argDescriptors[posarg++];
\r
1251 strcpy(argName, ad->argName);
\r
1254 if (ad->argType == ArgTrue) {
\r
1255 *(Boolean *) ad->argLoc = TRUE;
\r
1258 if (ad->argType == ArgFalse) {
\r
1259 *(Boolean *) ad->argLoc = FALSE;
\r
1263 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1264 if (ch == NULLCHAR || ch == '\n') {
\r
1265 ExitArgError("No value provided for argument", argName);
\r
1269 // Quoting with { }. No characters have to (or can) be escaped.
\r
1270 // Thus the string cannot contain a '}' character.
\r
1290 } else if (ch == '\'' || ch == '"') {
\r
1291 // Quoting with ' ' or " ", with \ as escape character.
\r
1292 // Inconvenient for long strings that may contain Windows filenames.
\r
1309 if (ch == start) {
\r
1318 if (ad->argType == ArgFilename
\r
1319 || ad->argType == ArgSettingsFilename) {
\r
1325 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1349 for (i = 0; i < 3; i++) {
\r
1350 if (ch >= '0' && ch <= '7') {
\r
1351 octval = octval*8 + (ch - '0');
\r
1358 *q++ = (char) octval;
\r
1369 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1376 switch (ad->argType) {
\r
1378 *(int *) ad->argLoc = atoi(argValue);
\r
1382 *(float *) ad->argLoc = (float) atof(argValue);
\r
1387 *(char **) ad->argLoc = strdup(argValue);
\r
1390 case ArgSettingsFilename:
\r
1392 char fullname[MSG_SIZ];
\r
1393 if (ParseSettingsFile(argValue, fullname)) {
\r
1394 if (ad->argLoc != NULL) {
\r
1395 *(char **) ad->argLoc = strdup(fullname);
\r
1398 if (ad->argLoc != NULL) {
\r
1400 ExitArgError("Failed to open indirection file", argValue);
\r
1407 switch (argValue[0]) {
\r
1410 *(Boolean *) ad->argLoc = TRUE;
\r
1414 *(Boolean *) ad->argLoc = FALSE;
\r
1417 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1423 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1426 case ArgAttribs: {
\r
1427 ColorClass cc = (ColorClass)ad->argLoc;
\r
1428 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1432 case ArgBoardSize:
\r
1433 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1437 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1440 case ArgCommSettings:
\r
1441 ParseCommSettings(argValue, &dcb);
\r
1445 ExitArgError("Unrecognized argument", argValue);
\r
1452 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1454 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1455 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1458 lf->lfEscapement = 0;
\r
1459 lf->lfOrientation = 0;
\r
1460 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1461 lf->lfItalic = mfp->italic;
\r
1462 lf->lfUnderline = mfp->underline;
\r
1463 lf->lfStrikeOut = mfp->strikeout;
\r
1464 lf->lfCharSet = DEFAULT_CHARSET;
\r
1465 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1466 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1467 lf->lfQuality = DEFAULT_QUALITY;
\r
1468 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1469 strcpy(lf->lfFaceName, mfp->faceName);
\r
1473 CreateFontInMF(MyFont *mf)
\r
1475 LFfromMFP(&mf->lf, &mf->mfp);
\r
1476 if (mf->hf) DeleteObject(mf->hf);
\r
1477 mf->hf = CreateFontIndirect(&mf->lf);
\r
1481 SetDefaultTextAttribs()
\r
1484 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1485 ParseAttribs(&textAttribs[cc].color,
\r
1486 &textAttribs[cc].effects,
\r
1487 defaultTextAttribs[cc]);
\r
1492 SetDefaultSounds()
\r
1496 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1497 textAttribs[cc].sound.name = strdup("");
\r
1498 textAttribs[cc].sound.data = NULL;
\r
1500 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1501 sounds[sc].name = strdup("");
\r
1502 sounds[sc].data = NULL;
\r
1504 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1512 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1513 MyLoadSound(&textAttribs[cc].sound);
\r
1515 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1516 MyLoadSound(&sounds[sc]);
\r
1521 InitAppData(LPSTR lpCmdLine)
\r
1524 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1527 programName = szAppName;
\r
1529 /* Initialize to defaults */
\r
1530 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1531 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1532 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1533 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1534 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1535 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1536 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1537 SetDefaultTextAttribs();
\r
1538 SetDefaultSounds();
\r
1539 appData.movesPerSession = MOVES_PER_SESSION;
\r
1540 appData.initString = INIT_STRING;
\r
1541 appData.secondInitString = INIT_STRING;
\r
1542 appData.firstComputerString = COMPUTER_STRING;
\r
1543 appData.secondComputerString = COMPUTER_STRING;
\r
1544 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1545 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1546 appData.firstPlaysBlack = FALSE;
\r
1547 appData.noChessProgram = FALSE;
\r
1548 chessProgram = FALSE;
\r
1549 appData.firstHost = FIRST_HOST;
\r
1550 appData.secondHost = SECOND_HOST;
\r
1551 appData.firstDirectory = FIRST_DIRECTORY;
\r
1552 appData.secondDirectory = SECOND_DIRECTORY;
\r
1553 appData.bitmapDirectory = "";
\r
1554 appData.remoteShell = REMOTE_SHELL;
\r
1555 appData.remoteUser = "";
\r
1556 appData.timeDelay = TIME_DELAY;
\r
1557 appData.timeControl = TIME_CONTROL;
\r
1558 appData.timeIncrement = TIME_INCREMENT;
\r
1559 appData.icsActive = FALSE;
\r
1560 appData.icsHost = "";
\r
1561 appData.icsPort = ICS_PORT;
\r
1562 appData.icsCommPort = ICS_COMM_PORT;
\r
1563 appData.icsLogon = ICS_LOGON;
\r
1564 appData.icsHelper = "";
\r
1565 appData.useTelnet = FALSE;
\r
1566 appData.telnetProgram = TELNET_PROGRAM;
\r
1567 appData.gateway = "";
\r
1568 appData.loadGameFile = "";
\r
1569 appData.loadGameIndex = 0;
\r
1570 appData.saveGameFile = "";
\r
1571 appData.autoSaveGames = FALSE;
\r
1572 appData.loadPositionFile = "";
\r
1573 appData.loadPositionIndex = 1;
\r
1574 appData.savePositionFile = "";
\r
1575 appData.matchMode = FALSE;
\r
1576 appData.matchGames = 0;
\r
1577 appData.monoMode = FALSE;
\r
1578 appData.debugMode = FALSE;
\r
1579 appData.clockMode = TRUE;
\r
1580 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1581 appData.Iconic = FALSE; /*unused*/
\r
1582 appData.searchTime = "";
\r
1583 appData.searchDepth = 0;
\r
1584 appData.showCoords = FALSE;
\r
1585 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1586 appData.autoCallFlag = FALSE;
\r
1587 appData.flipView = FALSE;
\r
1588 appData.autoFlipView = TRUE;
\r
1589 appData.cmailGameName = "";
\r
1590 appData.alwaysPromoteToQueen = FALSE;
\r
1591 appData.oldSaveStyle = FALSE;
\r
1592 appData.quietPlay = FALSE;
\r
1593 appData.showThinking = FALSE;
\r
1594 appData.ponderNextMove = TRUE;
\r
1595 appData.periodicUpdates = TRUE;
\r
1596 appData.popupExitMessage = TRUE;
\r
1597 appData.popupMoveErrors = FALSE;
\r
1598 appData.autoObserve = FALSE;
\r
1599 appData.autoComment = FALSE;
\r
1600 appData.animate = TRUE;
\r
1601 appData.animSpeed = 10;
\r
1602 appData.animateDragging = TRUE;
\r
1603 appData.highlightLastMove = TRUE;
\r
1604 appData.getMoveList = TRUE;
\r
1605 appData.testLegality = TRUE;
\r
1606 appData.premove = TRUE;
\r
1607 appData.premoveWhite = FALSE;
\r
1608 appData.premoveWhiteText = "";
\r
1609 appData.premoveBlack = FALSE;
\r
1610 appData.premoveBlackText = "";
\r
1611 appData.icsAlarm = TRUE;
\r
1612 appData.icsAlarmTime = 5000;
\r
1613 appData.autoRaiseBoard = TRUE;
\r
1614 appData.localLineEditing = TRUE;
\r
1615 appData.colorize = TRUE;
\r
1616 appData.reuseFirst = TRUE;
\r
1617 appData.reuseSecond = TRUE;
\r
1618 appData.blindfold = FALSE;
\r
1619 dcb.DCBlength = sizeof(DCB);
\r
1620 dcb.BaudRate = 9600;
\r
1621 dcb.fBinary = TRUE;
\r
1622 dcb.fParity = FALSE;
\r
1623 dcb.fOutxCtsFlow = FALSE;
\r
1624 dcb.fOutxDsrFlow = FALSE;
\r
1625 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1626 dcb.fDsrSensitivity = FALSE;
\r
1627 dcb.fTXContinueOnXoff = TRUE;
\r
1628 dcb.fOutX = FALSE;
\r
1630 dcb.fNull = FALSE;
\r
1631 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1632 dcb.fAbortOnError = FALSE;
\r
1633 dcb.wReserved = 0;
\r
1635 dcb.Parity = SPACEPARITY;
\r
1636 dcb.StopBits = ONESTOPBIT;
\r
1637 settingsFileName = SETTINGS_FILE;
\r
1638 saveSettingsOnExit = TRUE;
\r
1639 boardX = CW_USEDEFAULT;
\r
1640 boardY = CW_USEDEFAULT;
\r
1641 consoleX = CW_USEDEFAULT;
\r
1642 consoleY = CW_USEDEFAULT;
\r
1643 consoleW = CW_USEDEFAULT;
\r
1644 consoleH = CW_USEDEFAULT;
\r
1645 analysisX = CW_USEDEFAULT;
\r
1646 analysisY = CW_USEDEFAULT;
\r
1647 analysisW = CW_USEDEFAULT;
\r
1648 analysisH = CW_USEDEFAULT;
\r
1649 commentX = CW_USEDEFAULT;
\r
1650 commentY = CW_USEDEFAULT;
\r
1651 commentW = CW_USEDEFAULT;
\r
1652 commentH = CW_USEDEFAULT;
\r
1653 editTagsX = CW_USEDEFAULT;
\r
1654 editTagsY = CW_USEDEFAULT;
\r
1655 editTagsW = CW_USEDEFAULT;
\r
1656 editTagsH = CW_USEDEFAULT;
\r
1657 gameListX = CW_USEDEFAULT;
\r
1658 gameListY = CW_USEDEFAULT;
\r
1659 gameListW = CW_USEDEFAULT;
\r
1660 gameListH = CW_USEDEFAULT;
\r
1661 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1662 icsNames = ICS_NAMES;
\r
1663 firstChessProgramNames = FCP_NAMES;
\r
1664 secondChessProgramNames = SCP_NAMES;
\r
1665 appData.initialMode = "";
\r
1666 appData.variant = "normal";
\r
1667 appData.firstProtocolVersion = PROTOVER;
\r
1668 appData.secondProtocolVersion = PROTOVER;
\r
1669 appData.showButtonBar = TRUE;
\r
1671 appData.zippyTalk = ZIPPY_TALK;
\r
1672 appData.zippyPlay = ZIPPY_PLAY;
\r
1673 appData.zippyLines = ZIPPY_LINES;
\r
1674 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1675 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1676 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1677 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1678 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1679 appData.zippyUseI = ZIPPY_USE_I;
\r
1680 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1681 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1682 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1683 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1684 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1685 appData.zippyAbort = ZIPPY_ABORT;
\r
1686 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1687 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1688 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1691 /* Point font array elements to structures and
\r
1692 parse default font names */
\r
1693 for (i=0; i<NUM_FONTS; i++) {
\r
1694 for (j=0; j<NUM_SIZES; j++) {
\r
1695 font[j][i] = &fontRec[j][i];
\r
1696 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1700 /* Parse default settings file if any */
\r
1701 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1702 settingsFileName = strdup(buf);
\r
1705 /* Parse command line */
\r
1706 ParseArgs(StringGet, &lpCmdLine);
\r
1708 /* Propagate options that affect others */
\r
1709 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1710 if (appData.icsActive || appData.noChessProgram) {
\r
1711 chessProgram = FALSE; /* not local chess program mode */
\r
1714 /* Open startup dialog if needed */
\r
1715 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1716 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1717 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1718 *appData.secondChessProgram == NULLCHAR))) {
\r
1721 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1722 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1723 FreeProcInstance(lpProc);
\r
1726 /* Make sure save files land in the right (?) directory */
\r
1727 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1728 appData.saveGameFile = strdup(buf);
\r
1730 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1731 appData.savePositionFile = strdup(buf);
\r
1734 /* Finish initialization for fonts and sounds */
\r
1735 for (i=0; i<NUM_FONTS; i++) {
\r
1736 for (j=0; j<NUM_SIZES; j++) {
\r
1737 CreateFontInMF(font[j][i]);
\r
1740 /* xboard, and older WinBoards, controlled the move sound with the
\r
1741 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1742 always turn the option on (so that the backend will call us),
\r
1743 then let the user turn the sound off by setting it to silence if
\r
1744 desired. To accommodate old winboard.ini files saved by old
\r
1745 versions of WinBoard, we also turn off the sound if the option
\r
1746 was initially set to false. */
\r
1747 if (!appData.ringBellAfterMoves) {
\r
1748 sounds[(int)SoundMove].name = strdup("");
\r
1749 appData.ringBellAfterMoves = TRUE;
\r
1751 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1752 SetCurrentDirectory(installDir);
\r
1754 SetCurrentDirectory(currDir);
\r
1756 p = icsTextMenuString;
\r
1757 if (p[0] == '@') {
\r
1758 FILE* f = fopen(p + 1, "r");
\r
1760 DisplayFatalError(p + 1, errno, 2);
\r
1763 i = fread(buf, 1, sizeof(buf)-1, f);
\r
1765 buf[i] = NULLCHAR;
\r
1768 ParseIcsTextMenu(strdup(p));
\r
1775 HMENU hmenu = GetMenu(hwndMain);
\r
1777 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1778 MF_BYCOMMAND|((appData.icsActive &&
\r
1779 *appData.icsCommPort != NULLCHAR) ?
\r
1780 MF_ENABLED : MF_GRAYED));
\r
1781 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1782 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1783 MF_CHECKED : MF_UNCHECKED));
\r
1788 SaveSettings(char* name)
\r
1791 ArgDescriptor *ad;
\r
1792 WINDOWPLACEMENT wp;
\r
1793 char dir[MSG_SIZ];
\r
1795 if (!hwndMain) return;
\r
1797 GetCurrentDirectory(MSG_SIZ, dir);
\r
1798 SetCurrentDirectory(installDir);
\r
1799 f = fopen(name, "w");
\r
1800 SetCurrentDirectory(dir);
\r
1802 DisplayError(name, errno);
\r
1805 fprintf(f, ";\n");
\r
1806 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
1807 fprintf(f, ";\n");
\r
1808 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
1809 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
1810 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
1811 fprintf(f, ";\n");
\r
1813 wp.length = sizeof(WINDOWPLACEMENT);
\r
1814 GetWindowPlacement(hwndMain, &wp);
\r
1815 boardX = wp.rcNormalPosition.left;
\r
1816 boardY = wp.rcNormalPosition.top;
\r
1818 if (hwndConsole) {
\r
1819 GetWindowPlacement(hwndConsole, &wp);
\r
1820 consoleX = wp.rcNormalPosition.left;
\r
1821 consoleY = wp.rcNormalPosition.top;
\r
1822 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1823 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1826 if (analysisDialog) {
\r
1827 GetWindowPlacement(analysisDialog, &wp);
\r
1828 analysisX = wp.rcNormalPosition.left;
\r
1829 analysisY = wp.rcNormalPosition.top;
\r
1830 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1831 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1834 if (commentDialog) {
\r
1835 GetWindowPlacement(commentDialog, &wp);
\r
1836 commentX = wp.rcNormalPosition.left;
\r
1837 commentY = wp.rcNormalPosition.top;
\r
1838 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1839 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1842 if (editTagsDialog) {
\r
1843 GetWindowPlacement(editTagsDialog, &wp);
\r
1844 editTagsX = wp.rcNormalPosition.left;
\r
1845 editTagsY = wp.rcNormalPosition.top;
\r
1846 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1847 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1850 if (gameListDialog) {
\r
1851 GetWindowPlacement(gameListDialog, &wp);
\r
1852 gameListX = wp.rcNormalPosition.left;
\r
1853 gameListY = wp.rcNormalPosition.top;
\r
1854 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1855 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1858 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
1859 if (!ad->save) continue;
\r
1860 switch (ad->argType) {
\r
1863 char *p = *(char **)ad->argLoc;
\r
1864 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
1865 /* Quote multiline values or \-containing values
\r
1866 with { } if possible */
\r
1867 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
1869 /* Else quote with " " */
\r
1870 fprintf(f, "/%s=\"", ad->argName);
\r
1872 if (*p == '\n') fprintf(f, "\n");
\r
1873 else if (*p == '\r') fprintf(f, "\\r");
\r
1874 else if (*p == '\t') fprintf(f, "\\t");
\r
1875 else if (*p == '\b') fprintf(f, "\\b");
\r
1876 else if (*p == '\f') fprintf(f, "\\f");
\r
1877 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
1878 else if (*p == '\"') fprintf(f, "\\\"");
\r
1879 else if (*p == '\\') fprintf(f, "\\\\");
\r
1883 fprintf(f, "\"\n");
\r
1888 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
1891 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
1894 fprintf(f, "/%s=%s\n", ad->argName,
\r
1895 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
1898 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1901 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1905 COLORREF color = *(COLORREF *)ad->argLoc;
\r
1906 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
1907 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1912 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1913 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
1914 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1915 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1916 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1917 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1918 (ta->effects) ? " " : "",
\r
1919 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1923 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
1924 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
1926 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
1929 case ArgBoardSize:
\r
1930 fprintf(f, "/%s=%s\n", ad->argName,
\r
1931 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
1936 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1937 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1938 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1939 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
1940 ad->argName, mfp->faceName, mfp->pointSize,
\r
1941 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1942 mfp->bold ? "b" : "",
\r
1943 mfp->italic ? "i" : "",
\r
1944 mfp->underline ? "u" : "",
\r
1945 mfp->strikeout ? "s" : "");
\r
1949 case ArgCommSettings:
\r
1950 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
1958 /*---------------------------------------------------------------------------*\
\r
1960 * GDI board drawing routines
\r
1962 \*---------------------------------------------------------------------------*/
\r
1965 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
1969 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
1970 if (gameInfo.event &&
\r
1971 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
1972 strcmp(name, "k80s") == 0) {
\r
1973 strcpy(name, "tim");
\r
1975 return LoadBitmap(hinst, name);
\r
1979 /* Insert a color into the program's logical palette
\r
1980 structure. This code assumes the given color is
\r
1981 the result of the RGB or PALETTERGB macro, and it
\r
1982 knows how those macros work (which is documented).
\r
1985 InsertInPalette(COLORREF color)
\r
1987 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
1989 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
1990 DisplayFatalError("Too many colors", 0, 1);
\r
1991 pLogPal->palNumEntries--;
\r
1995 pe->peFlags = (char) 0;
\r
1996 pe->peRed = (char) (0xFF & color);
\r
1997 pe->peGreen = (char) (0xFF & (color >> 8));
\r
1998 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2004 InitDrawingColors()
\r
2006 if (pLogPal == NULL) {
\r
2007 /* Allocate enough memory for a logical palette with
\r
2008 * PALETTESIZE entries and set the size and version fields
\r
2009 * of the logical palette structure.
\r
2011 pLogPal = (NPLOGPALETTE)
\r
2012 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2013 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2014 pLogPal->palVersion = 0x300;
\r
2016 pLogPal->palNumEntries = 0;
\r
2018 InsertInPalette(lightSquareColor);
\r
2019 InsertInPalette(darkSquareColor);
\r
2020 InsertInPalette(whitePieceColor);
\r
2021 InsertInPalette(blackPieceColor);
\r
2022 InsertInPalette(highlightSquareColor);
\r
2023 InsertInPalette(premoveHighlightColor);
\r
2025 /* create a logical color palette according the information
\r
2026 * in the LOGPALETTE structure.
\r
2028 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2030 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2031 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2032 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2033 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2034 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2039 BoardWidth(int boardSize)
\r
2041 return (BOARD_SIZE + 1) * sizeInfo[boardSize].lineGap +
\r
2042 BOARD_SIZE * sizeInfo[boardSize].squareSize;
\r
2045 /* Respond to board resize by dragging edge */
\r
2047 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2049 BoardSize newSize = NUM_SIZES - 1;
\r
2050 static int recurse = 0;
\r
2051 if (IsIconic(hwndMain)) return;
\r
2052 if (recurse > 0) return;
\r
2054 while (newSize > 0 &&
\r
2055 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2056 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2059 boardSize = newSize;
\r
2060 InitDrawingSizes(boardSize, flags);
\r
2067 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2069 int i, boardWidth;
\r
2070 ChessSquare piece;
\r
2071 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2073 SIZE clockSize, messageSize;
\r
2075 char buf[MSG_SIZ];
\r
2077 HMENU hmenu = GetMenu(hwndMain);
\r
2078 RECT crect, wrect;
\r
2080 LOGBRUSH logbrush;
\r
2082 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2083 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2084 squareSize = sizeInfo[boardSize].squareSize;
\r
2085 lineGap = sizeInfo[boardSize].lineGap;
\r
2087 if (tinyLayout != oldTinyLayout) {
\r
2088 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2090 style &= ~WS_SYSMENU;
\r
2091 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2092 "&Minimize\tCtrl+F4");
\r
2094 style |= WS_SYSMENU;
\r
2095 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2097 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2099 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2100 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2101 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2103 DrawMenuBar(hwndMain);
\r
2106 boardWidth = BoardWidth(boardSize);
\r
2108 /* Get text area sizes */
\r
2109 hdc = GetDC(hwndMain);
\r
2110 if (appData.clockMode) {
\r
2111 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2113 sprintf(buf, "White");
\r
2115 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2116 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2117 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2118 str = "We only care about the height here";
\r
2119 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2120 SelectObject(hdc, oldFont);
\r
2121 ReleaseDC(hwndMain, hdc);
\r
2123 /* Compute where everything goes */
\r
2124 whiteRect.left = OUTER_MARGIN;
\r
2125 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2126 whiteRect.top = OUTER_MARGIN;
\r
2127 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2129 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2130 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2131 blackRect.top = whiteRect.top;
\r
2132 blackRect.bottom = whiteRect.bottom;
\r
2134 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2135 if (appData.showButtonBar) {
\r
2136 messageRect.right = blackRect.right
\r
2137 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2139 messageRect.right = blackRect.right;
\r
2141 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2142 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2144 boardRect.left = whiteRect.left;
\r
2145 boardRect.right = boardRect.left + boardWidth;
\r
2146 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2147 boardRect.bottom = boardRect.top + boardWidth;
\r
2149 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2150 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2151 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2152 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2153 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2154 GetWindowRect(hwndMain, &wrect);
\r
2155 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2156 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2157 /* compensate if menu bar wrapped */
\r
2158 GetClientRect(hwndMain, &crect);
\r
2159 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2160 winHeight += offby;
\r
2162 case WMSZ_TOPLEFT:
\r
2163 SetWindowPos(hwndMain, NULL,
\r
2164 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2165 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2168 case WMSZ_TOPRIGHT:
\r
2170 SetWindowPos(hwndMain, NULL,
\r
2171 wrect.left, wrect.bottom - winHeight,
\r
2172 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2175 case WMSZ_BOTTOMLEFT:
\r
2177 SetWindowPos(hwndMain, NULL,
\r
2178 wrect.right - winWidth, wrect.top,
\r
2179 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2182 case WMSZ_BOTTOMRIGHT:
\r
2186 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2187 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2192 for (i = 0; i < N_BUTTONS; i++) {
\r
2193 if (buttonDesc[i].hwnd != NULL) {
\r
2194 DestroyWindow(buttonDesc[i].hwnd);
\r
2195 buttonDesc[i].hwnd = NULL;
\r
2197 if (appData.showButtonBar) {
\r
2198 buttonDesc[i].hwnd =
\r
2199 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2200 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2201 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2202 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2203 (HMENU) buttonDesc[i].id,
\r
2204 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2206 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2207 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2208 MAKELPARAM(FALSE, 0));
\r
2210 if (buttonDesc[i].id == IDM_Pause)
\r
2211 hwndPause = buttonDesc[i].hwnd;
\r
2212 buttonDesc[i].wndproc = (WNDPROC)
\r
2213 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2216 if (gridPen != NULL) DeleteObject(gridPen);
\r
2217 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2218 if (premovePen != NULL) DeleteObject(premovePen);
\r
2219 if (lineGap != 0) {
\r
2220 logbrush.lbStyle = BS_SOLID;
\r
2221 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2223 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2224 lineGap, &logbrush, 0, NULL);
\r
2225 logbrush.lbColor = highlightSquareColor;
\r
2227 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2228 lineGap, &logbrush, 0, NULL);
\r
2230 logbrush.lbColor = premoveHighlightColor;
\r
2232 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2233 lineGap, &logbrush, 0, NULL);
\r
2235 for (i = 0; i < BOARD_SIZE + 1; i++) {
\r
2236 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2237 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2;
\r
2238 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2239 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2240 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2241 BOARD_SIZE * (squareSize + lineGap);
\r
2242 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x =
\r
2243 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left +
\r
2244 lineGap / 2 + (i * (squareSize + lineGap));
\r
2245 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y =
\r
2246 boardRect.top + BOARD_SIZE * (squareSize + lineGap);
\r
2247 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2251 if (boardSize == oldBoardSize) return;
\r
2252 oldBoardSize = boardSize;
\r
2253 oldTinyLayout = tinyLayout;
\r
2255 /* Load piece bitmaps for this board size */
\r
2256 for (i=0; i<=2; i++) {
\r
2257 for (piece = WhitePawn;
\r
2258 (int) piece <= (int) WhiteKing;
\r
2259 piece = (ChessSquare) ((int) piece + 1)) {
\r
2260 if (pieceBitmap[i][piece] != NULL)
\r
2261 DeleteObject(pieceBitmap[i][piece]);
\r
2265 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2266 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2267 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2268 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2269 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2270 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2271 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2272 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2273 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2274 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2275 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2276 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2277 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2278 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2279 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2280 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2281 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2282 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2287 PieceBitmap(ChessSquare p, int kind)
\r
2289 if ((int) p >= (int) BlackPawn)
\r
2290 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2292 return pieceBitmap[kind][(int) p];
\r
2295 /***************************************************************/
\r
2297 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2298 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2300 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2301 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2305 SquareToPos(int row, int column, int * x, int * y)
\r
2308 *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
2309 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2311 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2312 *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
2317 DrawCoordsOnDC(HDC hdc)
\r
2319 static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'};
\r
2320 static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'};
\r
2321 char str[2] = { NULLCHAR, NULLCHAR };
\r
2322 int oldMode, oldAlign, x, y, start, i;
\r
2326 if (!appData.showCoords)
\r
2329 start = flipView ? 0 : 8;
\r
2331 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2332 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2333 oldAlign = GetTextAlign(hdc);
\r
2334 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2336 y = boardRect.top + lineGap;
\r
2337 x = boardRect.left + lineGap;
\r
2339 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2340 for (i = 0; i < 8; i++) {
\r
2341 str[0] = files[start + i];
\r
2342 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2343 y += squareSize + lineGap;
\r
2346 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2347 for (i = 0; i < 8; i++) {
\r
2348 str[0] = ranks[start + i];
\r
2349 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2350 x += squareSize + lineGap;
\r
2353 SelectObject(hdc, oldBrush);
\r
2354 SetBkMode(hdc, oldMode);
\r
2355 SetTextAlign(hdc, oldAlign);
\r
2356 SelectObject(hdc, oldFont);
\r
2360 DrawGridOnDC(HDC hdc)
\r
2364 if (lineGap != 0) {
\r
2365 oldPen = SelectObject(hdc, gridPen);
\r
2366 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2);
\r
2367 SelectObject(hdc, oldPen);
\r
2371 #define HIGHLIGHT_PEN 0
\r
2372 #define PREMOVE_PEN 1
\r
2375 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2378 HPEN oldPen, hPen;
\r
2379 if (lineGap == 0) return;
\r
2381 x1 = boardRect.left +
\r
2382 lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap);
\r
2383 y1 = boardRect.top +
\r
2384 lineGap/2 + y * (squareSize + lineGap);
\r
2386 x1 = boardRect.left +
\r
2387 lineGap/2 + x * (squareSize + lineGap);
\r
2388 y1 = boardRect.top +
\r
2389 lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap);
\r
2391 hPen = pen ? premovePen : highlightPen;
\r
2392 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2393 MoveToEx(hdc, x1, y1, NULL);
\r
2394 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2395 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2396 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2397 LineTo(hdc, x1, y1);
\r
2398 SelectObject(hdc, oldPen);
\r
2402 DrawHighlightsOnDC(HDC hdc)
\r
2405 for (i=0; i<2; i++) {
\r
2406 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
2407 DrawHighlightOnDC(hdc, TRUE,
\r
2408 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
2411 for (i=0; i<2; i++) {
\r
2412 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2413 premoveHighlightInfo.sq[i].y >= 0) {
\r
2414 DrawHighlightOnDC(hdc, TRUE,
\r
2415 premoveHighlightInfo.sq[i].x,
\r
2416 premoveHighlightInfo.sq[i].y,
\r
2422 /* Note: sqcolor is used only in monoMode */
\r
2423 /* Note that this code is largely duplicated in woptions.c,
\r
2424 function DrawSampleSquare, so that needs to be updated too */
\r
2426 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2428 HBITMAP oldBitmap;
\r
2431 if (appData.blindfold) return;
\r
2433 if (appData.monoMode) {
\r
2434 SelectObject(tmphdc, PieceBitmap(piece,
\r
2435 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2436 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2437 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2440 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2441 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2442 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2444 /* Use black piece color for outline of white pieces */
\r
2445 /* Not sure this looks really good (though xboard does it).
\r
2446 Maybe better to have another selectable color, default black */
\r
2447 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
2448 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2449 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2451 /* Use black for outline of white pieces */
\r
2452 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2453 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
2457 /* Use white piece color for details of black pieces */
\r
2458 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
2459 WHITE_PIECE ones aren't always the right shape. */
\r
2460 /* Not sure this looks really good (though xboard does it).
\r
2461 Maybe better to have another selectable color, default medium gray? */
\r
2462 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
2463 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
2464 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2465 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2466 SelectObject(hdc, blackPieceBrush);
\r
2467 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2469 /* Use square color for details of black pieces */
\r
2470 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2471 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2472 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2475 SelectObject(hdc, oldBrush);
\r
2476 SelectObject(tmphdc, oldBitmap);
\r
2481 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
2483 int row, column, x, y, square_color, piece_color;
\r
2484 ChessSquare piece;
\r
2487 for (row = 0; row < BOARD_SIZE; row++) {
\r
2488 for (column = 0; column < BOARD_SIZE; column++) {
\r
2490 SquareToPos(row, column, &x, &y);
\r
2492 piece = board[row][column];
\r
2494 square_color = ((column + row) % 2) == 1;
\r
2495 piece_color = (int) piece < (int) BlackPawn;
\r
2497 if (appData.monoMode) {
\r
2498 if (piece == EmptySquare) {
\r
2499 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
2500 square_color ? WHITENESS : BLACKNESS);
\r
2502 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
2505 oldBrush = SelectObject(hdc, square_color ?
\r
2506 lightSquareBrush : darkSquareBrush);
\r
2507 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
2508 SelectObject(hdc, oldBrush);
\r
2509 if (piece != EmptySquare)
\r
2510 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
2516 #define MAX_CLIPS 200 /* more than enough */
\r
2519 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
2521 static Board lastReq, lastDrawn;
\r
2522 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
2523 static int lastDrawnFlipView = 0;
\r
2524 static int lastReqValid = 0, lastDrawnValid = 0;
\r
2525 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
2528 HBITMAP bufferBitmap;
\r
2529 HBITMAP oldBitmap;
\r
2531 HRGN clips[MAX_CLIPS];
\r
2532 ChessSquare dragged_piece = EmptySquare;
\r
2534 /* I'm undecided on this - this function figures out whether a full
\r
2535 * repaint is necessary on its own, so there's no real reason to have the
\r
2536 * caller tell it that. I think this can safely be set to FALSE - but
\r
2537 * if we trust the callers not to request full repaints unnessesarily, then
\r
2538 * we could skip some clipping work. In other words, only request a full
\r
2539 * redraw when the majority of pieces have changed positions (ie. flip,
\r
2540 * gamestart and similar) --Hawk
\r
2542 Boolean fullrepaint = repaint;
\r
2544 if (board == NULL) {
\r
2545 if (!lastReqValid) {
\r
2550 CopyBoard(lastReq, board);
\r
2554 if (doingSizing) {
\r
2558 if (IsIconic(hwndMain)) {
\r
2562 if (hdc == NULL) {
\r
2563 hdc = GetDC(hwndMain);
\r
2564 if (!appData.monoMode) {
\r
2565 SelectPalette(hdc, hPal, FALSE);
\r
2566 RealizePalette(hdc);
\r
2570 releaseDC = FALSE;
\r
2574 fprintf(debugFP, "*******************************\n"
\r
2576 "dragInfo.from (%d,%d)\n"
\r
2577 "dragInfo.start (%d,%d)\n"
\r
2578 "dragInfo.pos (%d,%d)\n"
\r
2579 "dragInfo.lastpos (%d,%d)\n",
\r
2580 repaint ? "TRUE" : "FALSE",
\r
2581 dragInfo.from.x, dragInfo.from.y,
\r
2582 dragInfo.start.x, dragInfo.start.y,
\r
2583 dragInfo.pos.x, dragInfo.pos.y,
\r
2584 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
2585 fprintf(debugFP, "prev: ");
\r
2586 for (row = 0; row < 8; row++) {
\r
2587 for (column = 0; column < 8; column++) {
\r
2588 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
2591 fprintf(debugFP, "\n");
\r
2592 fprintf(debugFP, "board: ");
\r
2593 for (row = 0; row < 8; row++) {
\r
2594 for (column = 0; column < 8; column++) {
\r
2595 fprintf(debugFP, "%d ", board[row][column]);
\r
2598 fprintf(debugFP, "\n");
\r
2602 /* Create some work-DCs */
\r
2603 hdcmem = CreateCompatibleDC(hdc);
\r
2604 tmphdc = CreateCompatibleDC(hdc);
\r
2606 /* Figure out which squares need updating by comparing the
\r
2607 * newest board with the last drawn board and checking if
\r
2608 * flipping has changed.
\r
2610 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
2611 for (row = 0; row < 8; row++) {
\r
2612 for (column = 0; column < 8; column++) {
\r
2613 if (lastDrawn[row][column] != board[row][column]) {
\r
2614 SquareToPos(row, column, &x, &y);
\r
2615 clips[num_clips++] =
\r
2616 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
2620 for (i=0; i<2; i++) {
\r
2621 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
2622 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
2623 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
2624 lastDrawnHighlight.sq[i].y >= 0) {
\r
2625 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
2626 lastDrawnHighlight.sq[i].x, &x, &y);
\r
2627 clips[num_clips++] =
\r
2628 CreateRectRgn(x - lineGap, y - lineGap,
\r
2629 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2631 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
2632 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
2633 clips[num_clips++] =
\r
2634 CreateRectRgn(x - lineGap, y - lineGap,
\r
2635 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2639 for (i=0; i<2; i++) {
\r
2640 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
2641 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
2642 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
2643 lastDrawnPremove.sq[i].y >= 0) {
\r
2644 SquareToPos(lastDrawnPremove.sq[i].y,
\r
2645 lastDrawnPremove.sq[i].x, &x, &y);
\r
2646 clips[num_clips++] =
\r
2647 CreateRectRgn(x - lineGap, y - lineGap,
\r
2648 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2650 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2651 premoveHighlightInfo.sq[i].y >= 0) {
\r
2652 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
2653 premoveHighlightInfo.sq[i].x, &x, &y);
\r
2654 clips[num_clips++] =
\r
2655 CreateRectRgn(x - lineGap, y - lineGap,
\r
2656 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2661 fullrepaint = TRUE;
\r
2664 /* Create a buffer bitmap - this is the actual bitmap
\r
2665 * being written to. When all the work is done, we can
\r
2666 * copy it to the real DC (the screen). This avoids
\r
2667 * the problems with flickering.
\r
2669 GetClientRect(hwndMain, &Rect);
\r
2670 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
2671 Rect.bottom-Rect.top+1);
\r
2672 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
2673 if (!appData.monoMode) {
\r
2674 SelectPalette(hdcmem, hPal, FALSE);
\r
2677 /* Create clips for dragging */
\r
2678 if (!fullrepaint) {
\r
2679 if (dragInfo.from.x >= 0) {
\r
2680 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
2681 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2683 if (dragInfo.start.x >= 0) {
\r
2684 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
2685 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2687 if (dragInfo.pos.x >= 0) {
\r
2688 x = dragInfo.pos.x - squareSize / 2;
\r
2689 y = dragInfo.pos.y - squareSize / 2;
\r
2690 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2692 if (dragInfo.lastpos.x >= 0) {
\r
2693 x = dragInfo.lastpos.x - squareSize / 2;
\r
2694 y = dragInfo.lastpos.y - squareSize / 2;
\r
2695 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2699 /* If dragging is in progress, we temporarely remove the piece */
\r
2700 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
2701 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
2702 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
2705 /* Are we animating a move?
\r
2707 * - remove the piece from the board (temporarely)
\r
2708 * - calculate the clipping region
\r
2710 if (!fullrepaint) {
\r
2711 if (animInfo.piece != EmptySquare) {
\r
2712 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
2713 x = boardRect.left + animInfo.lastpos.x;
\r
2714 y = boardRect.top + animInfo.lastpos.y;
\r
2715 x2 = boardRect.left + animInfo.pos.x;
\r
2716 y2 = boardRect.top + animInfo.pos.y;
\r
2717 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
2718 /* Slight kludge. The real problem is that after AnimateMove is
\r
2719 done, the position on the screen does not match lastDrawn.
\r
2720 This currently causes trouble only on e.p. captures in
\r
2721 atomic, where the piece moves to an empty square and then
\r
2722 explodes. The old and new positions both had an empty square
\r
2723 at the destination, but animation has drawn a piece there and
\r
2724 we have to remember to erase it. */
\r
2725 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
2729 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
2730 if (num_clips == 0)
\r
2731 fullrepaint = TRUE;
\r
2733 /* Set clipping on the memory DC */
\r
2734 if (!fullrepaint) {
\r
2735 SelectClipRgn(hdcmem, clips[0]);
\r
2736 for (x = 1; x < num_clips; x++) {
\r
2737 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
2738 abort(); // this should never ever happen!
\r
2742 /* Do all the drawing to the memory DC */
\r
2743 DrawGridOnDC(hdcmem);
\r
2744 DrawHighlightsOnDC(hdcmem);
\r
2745 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
2746 DrawCoordsOnDC(hdcmem);
\r
2748 /* Put the dragged piece back into place and draw it */
\r
2749 if (dragged_piece != EmptySquare) {
\r
2750 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
2751 x = dragInfo.pos.x - squareSize / 2;
\r
2752 y = dragInfo.pos.y - squareSize / 2;
\r
2753 DrawPieceOnDC(hdcmem, dragged_piece,
\r
2754 ((int) dragged_piece < (int) BlackPawn),
\r
2755 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
2758 /* Put the animated piece back into place and draw it */
\r
2759 if (animInfo.piece != EmptySquare) {
\r
2760 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
2761 x = boardRect.left + animInfo.pos.x;
\r
2762 y = boardRect.top + animInfo.pos.y;
\r
2763 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
2764 ((int) animInfo.piece < (int) BlackPawn),
\r
2765 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
2768 /* Release the bufferBitmap by selecting in the old bitmap
\r
2769 * and delete the memory DC
\r
2771 SelectObject(hdcmem, oldBitmap);
\r
2774 /* Set clipping on the target DC */
\r
2775 if (!fullrepaint) {
\r
2776 SelectClipRgn(hdc, clips[0]);
\r
2777 for (x = 1; x < num_clips; x++) {
\r
2778 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
2779 abort(); // this should never ever happen!
\r
2783 /* Copy the new bitmap onto the screen in one go.
\r
2784 * This way we avoid any flickering
\r
2786 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
2787 BitBlt(hdc, boardRect.left, boardRect.top,
\r
2788 boardRect.right - boardRect.left,
\r
2789 boardRect.bottom - boardRect.top,
\r
2790 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
2791 SelectObject(tmphdc, oldBitmap);
\r
2793 /* Massive cleanup */
\r
2794 for (x = 0; x < num_clips; x++)
\r
2795 DeleteObject(clips[x]);
\r
2798 DeleteObject(bufferBitmap);
\r
2801 ReleaseDC(hwndMain, hdc);
\r
2803 if (lastDrawnFlipView != flipView) {
\r
2805 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
2807 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
2810 CopyBoard(lastDrawn, board);
\r
2811 lastDrawnHighlight = highlightInfo;
\r
2812 lastDrawnPremove = premoveHighlightInfo;
\r
2813 lastDrawnFlipView = flipView;
\r
2814 lastDrawnValid = 1;
\r
2818 /*---------------------------------------------------------------------------*\
\r
2819 | CLIENT PAINT PROCEDURE
\r
2820 | This is the main event-handler for the WM_PAINT message.
\r
2822 \*---------------------------------------------------------------------------*/
\r
2824 PaintProc(HWND hwnd)
\r
2830 if(hdc = BeginPaint(hwnd, &ps)) {
\r
2831 if (IsIconic(hwnd)) {
\r
2832 DrawIcon(hdc, 2, 2, iconCurrent);
\r
2834 if (!appData.monoMode) {
\r
2835 SelectPalette(hdc, hPal, FALSE);
\r
2836 RealizePalette(hdc);
\r
2838 HDCDrawPosition(hdc, 1, NULL);
\r
2840 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2841 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
2842 ETO_CLIPPED|ETO_OPAQUE,
\r
2843 &messageRect, messageText, strlen(messageText), NULL);
\r
2844 SelectObject(hdc, oldFont);
\r
2845 DisplayBothClocks();
\r
2847 EndPaint(hwnd,&ps);
\r
2855 * If the user selects on a border boundary, return -1; if off the board,
\r
2856 * return -2. Otherwise map the event coordinate to the square.
\r
2857 * The offset boardRect.left or boardRect.top must already have been
\r
2858 * subtracted from x.
\r
2861 EventToSquare(int x)
\r
2868 if ((x % (squareSize + lineGap)) >= squareSize)
\r
2870 x /= (squareSize + lineGap);
\r
2871 if (x >= BOARD_SIZE)
\r
2882 DropEnable dropEnables[] = {
\r
2883 { 'P', DP_Pawn, "Pawn" },
\r
2884 { 'N', DP_Knight, "Knight" },
\r
2885 { 'B', DP_Bishop, "Bishop" },
\r
2886 { 'R', DP_Rook, "Rook" },
\r
2887 { 'Q', DP_Queen, "Queen" },
\r
2891 SetupDropMenu(HMENU hmenu)
\r
2893 int i, count, enable;
\r
2895 extern char white_holding[], black_holding[];
\r
2896 char item[MSG_SIZ];
\r
2898 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
2899 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
2900 dropEnables[i].piece);
\r
2902 while (p && *p++ == dropEnables[i].piece) count++;
\r
2903 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
2904 enable = count > 0 || !appData.testLegality
\r
2905 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
2906 && !appData.icsActive);
\r
2907 ModifyMenu(hmenu, dropEnables[i].command,
\r
2908 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
2909 dropEnables[i].command, item);
\r
2913 static int fromX = -1, fromY = -1, toX, toY;
\r
2915 /* Event handler for mouse messages */
\r
2917 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
2921 static int recursive = 0;
\r
2923 BOOLEAN saveAnimate;
\r
2924 static BOOLEAN sameAgain = FALSE;
\r
2927 if (message == WM_MBUTTONUP) {
\r
2928 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
2929 to the middle button: we simulate pressing the left button too!
\r
2931 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
2932 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
2938 pt.x = LOWORD(lParam);
\r
2939 pt.y = HIWORD(lParam);
\r
2940 x = EventToSquare(pt.x - boardRect.left);
\r
2941 y = EventToSquare(pt.y - boardRect.top);
\r
2942 if (!flipView && y >= 0) {
\r
2943 y = BOARD_SIZE - 1 - y;
\r
2945 if (flipView && x >= 0) {
\r
2946 x = BOARD_SIZE - 1 - x;
\r
2949 switch (message) {
\r
2950 case WM_LBUTTONDOWN:
\r
2952 sameAgain = FALSE;
\r
2954 /* Downclick vertically off board; check if on clock */
\r
2955 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
2956 if (gameMode == EditPosition) {
\r
2957 SetWhiteToPlayEvent();
\r
2958 } else if (gameMode == IcsPlayingBlack ||
\r
2959 gameMode == MachinePlaysWhite) {
\r
2962 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
2963 if (gameMode == EditPosition) {
\r
2964 SetBlackToPlayEvent();
\r
2965 } else if (gameMode == IcsPlayingWhite ||
\r
2966 gameMode == MachinePlaysBlack) {
\r
2970 if (!appData.highlightLastMove) {
\r
2971 ClearHighlights();
\r
2972 DrawPosition(FALSE, NULL);
\r
2974 fromX = fromY = -1;
\r
2975 dragInfo.start.x = dragInfo.start.y = -1;
\r
2976 dragInfo.from = dragInfo.start;
\r
2978 } else if (x < 0 || y < 0) {
\r
2980 } else if (fromX == x && fromY == y) {
\r
2981 /* Downclick on same square again */
\r
2982 ClearHighlights();
\r
2983 DrawPosition(FALSE, NULL);
\r
2984 sameAgain = TRUE;
\r
2985 } else if (fromX != -1) {
\r
2986 /* Downclick on different square */
\r
2987 ChessSquare pdown, pup;
\r
2988 pdown = boards[currentMove][fromY][fromX];
\r
2989 pup = boards[currentMove][y][x];
\r
2990 if (gameMode == EditPosition ||
\r
2991 !((WhitePawn <= pdown && pdown <= WhiteKing &&
\r
2992 WhitePawn <= pup && pup <= WhiteKing) ||
\r
2993 (BlackPawn <= pdown && pdown <= BlackKing &&
\r
2994 BlackPawn <= pup && pup <= BlackKing))) {
\r
2995 /* EditPosition, empty square, or different color piece;
\r
2996 click-click move is possible */
\r
2999 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
3000 if (appData.alwaysPromoteToQueen) {
\r
3001 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3002 if (!appData.highlightLastMove) {
\r
3003 ClearHighlights();
\r
3004 DrawPosition(FALSE, NULL);
\r
3007 SetHighlights(fromX, fromY, toX, toY);
\r
3008 DrawPosition(FALSE, NULL);
\r
3009 PromotionPopup(hwnd);
\r
3011 } else { /* not a promotion */
\r
3012 if (appData.animate || appData.highlightLastMove) {
\r
3013 SetHighlights(fromX, fromY, toX, toY);
\r
3015 ClearHighlights();
\r
3017 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3018 if (appData.animate && !appData.highlightLastMove) {
\r
3019 ClearHighlights();
\r
3020 DrawPosition(FALSE, NULL);
\r
3023 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3024 fromX = fromY = -1;
\r
3027 ClearHighlights();
\r
3028 DrawPosition(FALSE, NULL);
\r
3030 /* First downclick, or restart on a square with same color piece */
\r
3031 if (!frozen && OKToStartUserMove(x, y)) {
\r
3034 dragInfo.lastpos = pt;
\r
3035 dragInfo.from.x = fromX;
\r
3036 dragInfo.from.y = fromY;
\r
3037 dragInfo.start = dragInfo.from;
\r
3038 SetCapture(hwndMain);
\r
3040 fromX = fromY = -1;
\r
3041 dragInfo.start.x = dragInfo.start.y = -1;
\r
3042 dragInfo.from = dragInfo.start;
\r
3046 case WM_LBUTTONUP:
\r
3048 if (fromX == -1) break;
\r
3049 if (x == fromX && y == fromY) {
\r
3050 dragInfo.from.x = dragInfo.from.y = -1;
\r
3051 /* Upclick on same square */
\r
3053 /* Clicked same square twice: abort click-click move */
\r
3054 fromX = fromY = -1;
\r
3056 ClearPremoveHighlights();
\r
3058 /* First square clicked: start click-click move */
\r
3059 SetHighlights(fromX, fromY, -1, -1);
\r
3061 DrawPosition(FALSE, NULL);
\r
3062 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
3063 /* Errant click; ignore */
\r
3066 /* Finish drag move */
\r
3067 dragInfo.from.x = dragInfo.from.y = -1;
\r
3070 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
3071 appData.animate = appData.animate && !appData.animateDragging;
\r
3072 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
3073 if (appData.alwaysPromoteToQueen) {
\r
3074 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3076 DrawPosition(FALSE, NULL);
\r
3077 PromotionPopup(hwnd);
\r
3080 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3082 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3083 appData.animate = saveAnimate;
\r
3084 fromX = fromY = -1;
\r
3085 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
3086 ClearHighlights();
\r
3088 if (appData.animate || appData.animateDragging ||
\r
3089 appData.highlightDragging || gotPremove) {
\r
3090 DrawPosition(FALSE, NULL);
\r
3093 dragInfo.start.x = dragInfo.start.y = -1;
\r
3094 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
3097 case WM_MOUSEMOVE:
\r
3098 if ((appData.animateDragging || appData.highlightDragging)
\r
3099 && (wParam & MK_LBUTTON)
\r
3100 && dragInfo.from.x >= 0) {
\r
3101 if (appData.animateDragging) {
\r
3102 dragInfo.pos = pt;
\r
3104 if (appData.highlightDragging) {
\r
3105 SetHighlights(fromX, fromY, x, y);
\r
3107 DrawPosition(FALSE, NULL);
\r
3108 dragInfo.lastpos = dragInfo.pos;
\r
3111 case WM_MOUSEWHEEL:
\r
3112 /* Mouse Wheel is being rolled forward
\r
3113 * Play moves forward
\r
3115 if ((short)HIWORD(wParam) > 0)
\r
3116 if (forwardMostMove > 0 && currentMove != forwardMostMove)
\r
3118 /* Mouse Wheel is being rolled backward
\r
3119 * Play moves backward
\r
3121 if ((short)HIWORD(wParam) < 0)
\r
3122 if (currentMove > 0) BackwardEvent();
\r
3124 case WM_MBUTTONDOWN:
\r
3125 case WM_RBUTTONDOWN:
\r
3128 fromX = fromY = -1;
\r
3129 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
3130 dragInfo.start.x = dragInfo.start.y = -1;
\r
3131 dragInfo.from = dragInfo.start;
\r
3132 dragInfo.lastpos = dragInfo.pos;
\r
3133 if (appData.highlightDragging) {
\r
3134 ClearHighlights();
\r
3136 DrawPosition(TRUE, NULL);
\r
3138 switch (gameMode) {
\r
3139 case EditPosition:
\r
3140 case IcsExamining:
\r
3141 if (x < 0 || y < 0) break;
\r
3144 if (message == WM_MBUTTONDOWN) {
\r
3145 buttonCount = 3; /* even if system didn't think so */
\r
3146 if (wParam & MK_SHIFT)
\r
3147 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3149 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3150 } else { /* message == WM_RBUTTONDOWN */
\r
3152 if (buttonCount == 3) {
\r
3153 if (wParam & MK_SHIFT)
\r
3154 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3156 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3158 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3161 /* Just have one menu, on the right button. Windows users don't
\r
3162 think to try the middle one, and sometimes other software steals
\r
3163 it, or it doesn't really exist. */
\r
3164 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3168 case IcsPlayingWhite:
\r
3169 case IcsPlayingBlack:
\r
3171 case MachinePlaysWhite:
\r
3172 case MachinePlaysBlack:
\r
3173 if (appData.testLegality &&
\r
3174 gameInfo.variant != VariantBughouse &&
\r
3175 gameInfo.variant != VariantCrazyhouse) break;
\r
3176 if (x < 0 || y < 0) break;
\r
3179 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
3180 SetupDropMenu(hmenu);
\r
3181 MenuPopup(hwnd, pt, hmenu, -1);
\r
3192 /* Preprocess messages for buttons in main window */
\r
3194 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3196 int id = GetWindowLong(hwnd, GWL_ID);
\r
3199 for (i=0; i<N_BUTTONS; i++) {
\r
3200 if (buttonDesc[i].id == id) break;
\r
3202 if (i == N_BUTTONS) return 0;
\r
3203 switch (message) {
\r
3208 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
3209 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
3216 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
3219 if (appData.icsActive) {
\r
3220 if (GetKeyState(VK_SHIFT) < 0) {
\r
3222 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3223 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3227 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3228 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3235 if (appData.icsActive) {
\r
3236 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3237 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3239 SendMessage(h, WM_CHAR, wParam, lParam);
\r
3241 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
3242 PopUpMoveDialog((char)wParam);
\r
3248 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
3251 /* Process messages for Promotion dialog box */
\r
3253 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
3257 switch (message) {
\r
3258 case WM_INITDIALOG: /* message: initialize dialog box */
\r
3259 /* Center the dialog over the application window */
\r
3260 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
3261 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
3262 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
3263 gameInfo.variant == VariantGiveaway) ?
\r
3264 SW_SHOW : SW_HIDE);
\r
3267 case WM_COMMAND: /* message: received a command */
\r
3268 switch (LOWORD(wParam)) {
\r
3270 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3271 ClearHighlights();
\r
3272 DrawPosition(FALSE, NULL);
\r
3292 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3293 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
3294 if (!appData.highlightLastMove) {
\r
3295 ClearHighlights();
\r
3296 DrawPosition(FALSE, NULL);
\r
3303 /* Pop up promotion dialog */
\r
3305 PromotionPopup(HWND hwnd)
\r
3309 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
3310 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
3311 hwnd, (DLGPROC)lpProc);
\r
3312 FreeProcInstance(lpProc);
\r
3315 /* Toggle ShowThinking */
\r
3317 ToggleShowThinking()
\r
3319 ShowThinkingEvent(!appData.showThinking);
\r
3323 LoadGameDialog(HWND hwnd, char* title)
\r
3327 char fileTitle[MSG_SIZ];
\r
3328 f = OpenFileDialog(hwnd, FALSE, "",
\r
3329 appData.oldSaveStyle ? "gam" : "pgn",
\r
3331 title, &number, fileTitle, NULL);
\r
3333 cmailMsgLoaded = FALSE;
\r
3334 if (number == 0) {
\r
3335 int error = GameListBuild(f);
\r
3337 DisplayError("Cannot build game list", error);
\r
3338 } else if (!ListEmpty(&gameList) &&
\r
3339 ((ListGame *) gameList.tailPred)->number > 1) {
\r
3340 GameListPopUp(f, fileTitle);
\r
3343 GameListDestroy();
\r
3346 LoadGame(f, number, fileTitle, FALSE);
\r
3351 ChangedConsoleFont()
\r
3354 CHARRANGE tmpsel, sel;
\r
3355 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
3356 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3357 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3360 cfmt.cbSize = sizeof(CHARFORMAT);
\r
3361 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
3362 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
3363 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
3364 * size. This was undocumented in the version of MSVC++ that I had
\r
3365 * when I wrote the code, but is apparently documented now.
\r
3367 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
3368 cfmt.bCharSet = f->lf.lfCharSet;
\r
3369 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
3370 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
3371 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
3372 /* Why are the following seemingly needed too? */
\r
3373 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
3374 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
3375 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
3377 tmpsel.cpMax = -1; /*999999?*/
\r
3378 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
3379 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
3380 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
3381 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
3383 paraf.cbSize = sizeof(paraf);
\r
3384 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
3385 paraf.dxStartIndent = 0;
\r
3386 paraf.dxOffset = WRAP_INDENT;
\r
3387 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
3388 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
3391 /*---------------------------------------------------------------------------*\
\r
3393 * Window Proc for main window
\r
3395 \*---------------------------------------------------------------------------*/
\r
3397 /* Process messages for main window, etc. */
\r
3399 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3402 int wmId, wmEvent;
\r
3406 char fileTitle[MSG_SIZ];
\r
3408 switch (message) {
\r
3410 case WM_PAINT: /* message: repaint portion of window */
\r
3414 case WM_ERASEBKGND:
\r
3415 if (IsIconic(hwnd)) {
\r
3416 /* Cheat; change the message */
\r
3417 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
3419 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
3423 case WM_LBUTTONDOWN:
\r
3424 case WM_MBUTTONDOWN:
\r
3425 case WM_RBUTTONDOWN:
\r
3426 case WM_LBUTTONUP:
\r
3427 case WM_MBUTTONUP:
\r
3428 case WM_RBUTTONUP:
\r
3429 case WM_MOUSEMOVE:
\r
3430 case WM_MOUSEWHEEL:
\r
3431 MouseEvent(hwnd, message, wParam, lParam);
\r
3436 if (appData.icsActive) {
\r
3437 if (wParam == '\t') {
\r
3438 if (GetKeyState(VK_SHIFT) < 0) {
\r
3440 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3441 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3445 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3446 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3450 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3451 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3453 SendMessage(h, message, wParam, lParam);
\r
3455 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
3456 PopUpMoveDialog((char)wParam);
\r
3460 case WM_PALETTECHANGED:
\r
3461 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
3463 HDC hdc = GetDC(hwndMain);
\r
3464 SelectPalette(hdc, hPal, TRUE);
\r
3465 nnew = RealizePalette(hdc);
\r
3467 paletteChanged = TRUE;
\r
3469 UpdateColors(hdc);
\r
3471 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
3474 ReleaseDC(hwnd, hdc);
\r
3478 case WM_QUERYNEWPALETTE:
\r
3479 if (!appData.monoMode /*&& paletteChanged*/) {
\r
3481 HDC hdc = GetDC(hwndMain);
\r
3482 paletteChanged = FALSE;
\r
3483 SelectPalette(hdc, hPal, FALSE);
\r
3484 nnew = RealizePalette(hdc);
\r
3486 InvalidateRect(hwnd, &boardRect, FALSE);
\r
3488 ReleaseDC(hwnd, hdc);
\r
3493 case WM_COMMAND: /* message: command from application menu */
\r
3494 wmId = LOWORD(wParam);
\r
3495 wmEvent = HIWORD(wParam);
\r
3500 AnalysisPopDown();
\r
3503 case IDM_LoadGame:
\r
3504 LoadGameDialog(hwnd, "Load Game from File");
\r
3507 case IDM_LoadNextGame:
\r
3511 case IDM_LoadPrevGame:
\r
3515 case IDM_ReloadGame:
\r
3519 case IDM_LoadPosition:
\r
3520 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
3521 Reset(FALSE, TRUE);
\r
3524 f = OpenFileDialog(hwnd, FALSE, "",
\r
3525 appData.oldSaveStyle ? "pos" : "fen",
\r
3527 "Load Position from File", &number, fileTitle, NULL);
\r
3529 LoadPosition(f, number, fileTitle);
\r
3533 case IDM_LoadNextPosition:
\r
3534 ReloadPosition(1);
\r
3537 case IDM_LoadPrevPosition:
\r
3538 ReloadPosition(-1);
\r
3541 case IDM_ReloadPosition:
\r
3542 ReloadPosition(0);
\r
3545 case IDM_SaveGame:
\r
3546 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
3547 f = OpenFileDialog(hwnd, TRUE, defName,
\r
3548 appData.oldSaveStyle ? "gam" : "pgn",
\r
3550 "Save Game to File", NULL, fileTitle, NULL);
\r
3552 SaveGame(f, 0, "");
\r
3556 case IDM_SavePosition:
\r
3557 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
3558 f = OpenFileDialog(hwnd, TRUE, defName,
\r
3559 appData.oldSaveStyle ? "pos" : "fen",
\r
3561 "Save Position to File", NULL, fileTitle, NULL);
\r
3563 SavePosition(f, 0, "");
\r
3567 case IDM_CopyGame:
\r
3568 CopyGameToClipboard();
\r
3571 case IDM_PasteGame:
\r
3572 PasteGameFromClipboard();
\r
3575 case IDM_CopyPosition:
\r
3576 CopyFENToClipboard();
\r
3579 case IDM_PastePosition:
\r
3580 PasteFENFromClipboard();
\r
3583 case IDM_MailMove:
\r
3587 case IDM_ReloadCMailMsg:
\r
3588 Reset(TRUE, TRUE);
\r
3589 ReloadCmailMsgEvent(FALSE);
\r
3592 case IDM_Minimize:
\r
3593 ShowWindow(hwnd, SW_MINIMIZE);
\r
3600 case IDM_MachineWhite:
\r
3601 MachineWhiteEvent();
\r
3603 * refresh the tags dialog only if it's visible
\r
3605 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
3607 tags = PGNTags(&gameInfo);
\r
3608 TagsPopUp(tags, CmailMsg());
\r
3613 case IDM_MachineBlack:
\r
3614 MachineBlackEvent();
\r
3616 * refresh the tags dialog only if it's visible
\r
3618 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
3620 tags = PGNTags(&gameInfo);
\r
3621 TagsPopUp(tags, CmailMsg());
\r
3626 case IDM_TwoMachines:
\r
3627 TwoMachinesEvent();
\r
3629 * refresh the tags dialog only if it's visible
\r
3631 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
3633 tags = PGNTags(&gameInfo);
\r
3634 TagsPopUp(tags, CmailMsg());
\r
3639 case IDM_AnalysisMode:
\r
3640 if (!first.analysisSupport) {
\r
3641 char buf[MSG_SIZ];
\r
3642 sprintf(buf, "%s does not support analysis", first.tidy);
\r
3643 DisplayError(buf, 0);
\r
3645 if (!appData.showThinking) ToggleShowThinking();
\r
3646 AnalyzeModeEvent();
\r
3650 case IDM_AnalyzeFile:
\r
3651 if (!first.analysisSupport) {
\r
3652 char buf[MSG_SIZ];
\r
3653 sprintf(buf, "%s does not support analysis", first.tidy);
\r
3654 DisplayError(buf, 0);
\r
3656 if (!appData.showThinking) ToggleShowThinking();
\r
3657 AnalyzeFileEvent();
\r
3658 LoadGameDialog(hwnd, "Analyze Game from File");
\r
3659 AnalysisPeriodicEvent(1);
\r
3663 case IDM_IcsClient:
\r
3667 case IDM_EditGame:
\r
3671 case IDM_EditPosition:
\r
3672 EditPositionEvent();
\r
3675 case IDM_Training:
\r
3679 case IDM_ShowGameList:
\r
3680 ShowGameListProc();
\r
3683 case IDM_EditTags:
\r
3687 case IDM_EditComment:
\r
3688 if (commentDialogUp && editComment) {
\r
3691 EditCommentEvent();
\r
3711 case IDM_CallFlag:
\r
3731 case IDM_StopObserving:
\r
3732 StopObservingEvent();
\r
3735 case IDM_StopExamining:
\r
3736 StopExaminingEvent();
\r
3739 case IDM_TypeInMove:
\r
3740 PopUpMoveDialog('\000');
\r
3743 case IDM_Backward:
\r
3745 SetFocus(hwndMain);
\r
3750 SetFocus(hwndMain);
\r
3755 SetFocus(hwndMain);
\r
3760 SetFocus(hwndMain);
\r
3767 case IDM_TruncateGame:
\r
3768 TruncateGameEvent();
\r
3775 case IDM_RetractMove:
\r
3776 RetractMoveEvent();
\r
3779 case IDM_FlipView:
\r
3780 flipView = !flipView;
\r
3781 DrawPosition(FALSE, NULL);
\r
3784 case IDM_GeneralOptions:
\r
3785 GeneralOptionsPopup(hwnd);
\r
3788 case IDM_BoardOptions:
\r
3789 BoardOptionsPopup(hwnd);
\r
3792 case IDM_IcsOptions:
\r
3793 IcsOptionsPopup(hwnd);
\r
3797 FontsOptionsPopup(hwnd);
\r
3801 SoundOptionsPopup(hwnd);
\r
3804 case IDM_CommPort:
\r
3805 CommPortOptionsPopup(hwnd);
\r
3808 case IDM_LoadOptions:
\r
3809 LoadOptionsPopup(hwnd);
\r
3812 case IDM_SaveOptions:
\r
3813 SaveOptionsPopup(hwnd);
\r
3816 case IDM_TimeControl:
\r
3817 TimeControlOptionsPopup(hwnd);
\r
3820 case IDM_SaveSettings:
\r
3821 SaveSettings(settingsFileName);
\r
3824 case IDM_SaveSettingsOnExit:
\r
3825 saveSettingsOnExit = !saveSettingsOnExit;
\r
3826 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
3827 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
3828 MF_CHECKED : MF_UNCHECKED));
\r
3839 case IDM_AboutGame:
\r
3844 appData.debugMode = !appData.debugMode;
\r
3845 if (appData.debugMode) {
\r
3846 char dir[MSG_SIZ];
\r
3847 GetCurrentDirectory(MSG_SIZ, dir);
\r
3848 SetCurrentDirectory(installDir);
\r
3849 debugFP = fopen("WinBoard.debug", "w");
\r
3850 SetCurrentDirectory(dir);
\r
3851 setbuf(debugFP, NULL);
\r
3858 case IDM_HELPCONTENTS:
\r
3859 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
3860 MessageBox (GetFocus(),
\r
3861 "Unable to activate help",
\r
3862 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3866 case IDM_HELPSEARCH:
\r
3867 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
3868 MessageBox (GetFocus(),
\r
3869 "Unable to activate help",
\r
3870 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3874 case IDM_HELPHELP:
\r
3875 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
3876 MessageBox (GetFocus(),
\r
3877 "Unable to activate help",
\r
3878 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3883 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
3885 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
3886 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
3887 FreeProcInstance(lpProc);
\r
3890 case IDM_DirectCommand1:
\r
3891 AskQuestionEvent("Direct Command",
\r
3892 "Send to chess program:", "", "1");
\r
3894 case IDM_DirectCommand2:
\r
3895 AskQuestionEvent("Direct Command",
\r
3896 "Send to second chess program:", "", "2");
\r
3899 case EP_WhitePawn:
\r
3900 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
3901 fromX = fromY = -1;
\r
3904 case EP_WhiteKnight:
\r
3905 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
3906 fromX = fromY = -1;
\r
3909 case EP_WhiteBishop:
\r
3910 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
3911 fromX = fromY = -1;
\r
3914 case EP_WhiteRook:
\r
3915 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
3916 fromX = fromY = -1;
\r
3919 case EP_WhiteQueen:
\r
3920 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
3921 fromX = fromY = -1;
\r
3924 case EP_WhiteKing:
\r
3925 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
3926 fromX = fromY = -1;
\r
3929 case EP_BlackPawn:
\r
3930 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
3931 fromX = fromY = -1;
\r
3934 case EP_BlackKnight:
\r
3935 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
3936 fromX = fromY = -1;
\r
3939 case EP_BlackBishop:
\r
3940 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
3941 fromX = fromY = -1;
\r
3944 case EP_BlackRook:
\r
3945 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
3946 fromX = fromY = -1;
\r
3949 case EP_BlackQueen:
\r
3950 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
3951 fromX = fromY = -1;
\r
3954 case EP_BlackKing:
\r
3955 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
3956 fromX = fromY = -1;
\r
3959 case EP_EmptySquare:
\r
3960 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
3961 fromX = fromY = -1;
\r
3964 case EP_ClearBoard:
\r
3965 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
3966 fromX = fromY = -1;
\r
3970 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
3971 fromX = fromY = -1;
\r
3975 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
3976 fromX = fromY = -1;
\r
3980 DropMenuEvent(WhitePawn, fromX, fromY);
\r
3981 fromX = fromY = -1;
\r
3985 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
3986 fromX = fromY = -1;
\r
3990 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
3991 fromX = fromY = -1;
\r
3995 DropMenuEvent(WhiteRook, fromX, fromY);
\r
3996 fromX = fromY = -1;
\r
4000 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
4001 fromX = fromY = -1;
\r
4005 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4011 case CLOCK_TIMER_ID:
\r
4012 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
4013 clockTimerEvent = 0;
\r
4014 DecrementClocks(); /* call into back end */
\r
4016 case LOAD_GAME_TIMER_ID:
\r
4017 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
4018 loadGameTimerEvent = 0;
\r
4019 AutoPlayGameLoop(); /* call into back end */
\r
4021 case ANALYSIS_TIMER_ID:
\r
4022 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
4023 appData.periodicUpdates) {
\r
4024 AnalysisPeriodicEvent(0);
\r
4026 KillTimer(hwnd, analysisTimerEvent);
\r
4027 analysisTimerEvent = 0;
\r
4030 case DELAYED_TIMER_ID:
\r
4031 KillTimer(hwnd, delayedTimerEvent);
\r
4032 delayedTimerEvent = 0;
\r
4033 delayedTimerCallback();
\r
4038 case WM_USER_Input:
\r
4039 InputEvent(hwnd, message, wParam, lParam);
\r
4042 case WM_ENTERSIZEMOVE:
\r
4043 if (hwnd == hwndMain) {
\r
4044 doingSizing = TRUE;
\r
4050 if (hwnd == hwndMain) {
\r
4051 lastSizing = wParam;
\r
4055 case WM_EXITSIZEMOVE:
\r
4056 if (hwnd == hwndMain) {
\r
4058 doingSizing = FALSE;
\r
4059 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4060 GetClientRect(hwnd, &client);
\r
4061 ResizeBoard(client.right, client.bottom, lastSizing);
\r
4066 case WM_DESTROY: /* message: window being destroyed */
\r
4067 PostQuitMessage(0);
\r
4071 if (hwnd == hwndMain) {
\r
4076 default: /* Passes it on if unprocessed */
\r
4077 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4082 /*---------------------------------------------------------------------------*\
\r
4084 * Misc utility routines
\r
4086 \*---------------------------------------------------------------------------*/
\r
4089 * Decent random number generator, at least not as bad as Windows
\r
4090 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
4092 unsigned int randstate;
\r
4097 randstate = randstate * 1664525 + 1013904223;
\r
4098 return (int) randstate & 0x7fffffff;
\r
4102 mysrandom(unsigned int seed)
\r
4109 * returns TRUE if user selects a different color, FALSE otherwise
\r
4113 ChangeColor(HWND hwnd, COLORREF *which)
\r
4115 static BOOL firstTime = TRUE;
\r
4116 static DWORD customColors[16];
\r
4118 COLORREF newcolor;
\r
4123 /* Make initial colors in use available as custom colors */
\r
4124 /* Should we put the compiled-in defaults here instead? */
\r
4126 customColors[i++] = lightSquareColor & 0xffffff;
\r
4127 customColors[i++] = darkSquareColor & 0xffffff;
\r
4128 customColors[i++] = whitePieceColor & 0xffffff;
\r
4129 customColors[i++] = blackPieceColor & 0xffffff;
\r
4130 customColors[i++] = highlightSquareColor & 0xffffff;
\r
4131 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
4133 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
4134 customColors[i++] = textAttribs[ccl].color;
\r
4136 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
4137 firstTime = FALSE;
\r
4140 cc.lStructSize = sizeof(cc);
\r
4141 cc.hwndOwner = hwnd;
\r
4142 cc.hInstance = NULL;
\r
4143 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
4144 cc.lpCustColors = (LPDWORD) customColors;
\r
4145 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
4147 if (!ChooseColor(&cc)) return FALSE;
\r
4149 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
4150 if (newcolor == *which) return FALSE;
\r
4151 *which = newcolor;
\r
4155 InitDrawingColors();
\r
4156 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4161 MyLoadSound(MySound *ms)
\r
4167 if (ms->data) free(ms->data);
\r
4170 switch (ms->name[0]) {
\r
4176 /* System sound from Control Panel. Don't preload here. */
\r
4180 if (ms->name[1] == NULLCHAR) {
\r
4181 /* "!" alone = silence */
\r
4184 /* Builtin wave resource. Error if not found. */
\r
4185 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
4186 if (h == NULL) break;
\r
4187 ms->data = (void *)LoadResource(hInst, h);
\r
4188 if (h == NULL) break;
\r
4193 /* .wav file. Error if not found. */
\r
4194 f = fopen(ms->name, "rb");
\r
4195 if (f == NULL) break;
\r
4196 if (fstat(fileno(f), &st) < 0) break;
\r
4197 ms->data = malloc(st.st_size);
\r
4198 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
4204 char buf[MSG_SIZ];
\r
4205 sprintf(buf, "Error loading sound %s", ms->name);
\r
4206 DisplayError(buf, GetLastError());
\r
4212 MyPlaySound(MySound *ms)
\r
4214 BOOLEAN ok = FALSE;
\r
4215 switch (ms->name[0]) {
\r
4221 /* System sound from Control Panel (deprecated feature).
\r
4222 "$" alone or an unset sound name gets default beep (still in use). */
\r
4223 if (ms->name[1]) {
\r
4224 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
4226 if (!ok) ok = MessageBeep(MB_OK);
\r
4229 /* Builtin wave resource, or "!" alone for silence */
\r
4230 if (ms->name[1]) {
\r
4231 if (ms->data == NULL) return FALSE;
\r
4232 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4238 /* .wav file. Error if not found. */
\r
4239 if (ms->data == NULL) return FALSE;
\r
4240 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4243 /* Don't print an error: this can happen innocently if the sound driver
\r
4244 is busy; for instance, if another instance of WinBoard is playing
\r
4245 a sound at about the same time. */
\r
4248 char buf[MSG_SIZ];
\r
4249 sprintf(buf, "Error playing sound %s", ms->name);
\r
4250 DisplayError(buf, GetLastError());
\r
4258 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4261 OPENFILENAME *ofn;
\r
4262 static UINT *number; /* gross that this is static */
\r
4264 switch (message) {
\r
4265 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4266 /* Center the dialog over the application window */
\r
4267 ofn = (OPENFILENAME *) lParam;
\r
4268 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
4269 number = (UINT *) ofn->lCustData;
\r
4270 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
4274 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4275 return FALSE; /* Allow for further processing */
\r
4278 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
4279 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
4281 return FALSE; /* Allow for further processing */
\r
4287 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
4289 static UINT *number;
\r
4290 OPENFILENAME *ofname;
\r
4293 case WM_INITDIALOG:
\r
4294 ofname = (OPENFILENAME *)lParam;
\r
4295 number = (UINT *)(ofname->lCustData);
\r
4298 ofnot = (OFNOTIFY *)lParam;
\r
4299 if (ofnot->hdr.code == CDN_FILEOK) {
\r
4300 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
4309 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
4310 char *nameFilt, char *dlgTitle, UINT *number,
\r
4311 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
4313 OPENFILENAME openFileName;
\r
4314 char buf1[MSG_SIZ];
\r
4317 if (fileName == NULL) fileName = buf1;
\r
4318 if (defName == NULL) {
\r
4319 strcpy(fileName, "*.");
\r
4320 strcat(fileName, defExt);
\r
4322 strcpy(fileName, defName);
\r
4324 if (fileTitle) strcpy(fileTitle, "");
\r
4325 if (number) *number = 0;
\r
4327 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
4328 openFileName.hwndOwner = hwnd;
\r
4329 openFileName.hInstance = (HANDLE) hInst;
\r
4330 openFileName.lpstrFilter = nameFilt;
\r
4331 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
4332 openFileName.nMaxCustFilter = 0L;
\r
4333 openFileName.nFilterIndex = 1L;
\r
4334 openFileName.lpstrFile = fileName;
\r
4335 openFileName.nMaxFile = MSG_SIZ;
\r
4336 openFileName.lpstrFileTitle = fileTitle;
\r
4337 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
4338 openFileName.lpstrInitialDir = NULL;
\r
4339 openFileName.lpstrTitle = dlgTitle;
\r
4340 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
4341 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
4342 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
4343 | (oldDialog ? 0 : OFN_EXPLORER);
\r
4344 openFileName.nFileOffset = 0;
\r
4345 openFileName.nFileExtension = 0;
\r
4346 openFileName.lpstrDefExt = defExt;
\r
4347 openFileName.lCustData = (LONG) number;
\r
4348 openFileName.lpfnHook = oldDialog ?
\r
4349 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
4350 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
4352 if (write ? GetSaveFileName(&openFileName) :
\r
4353 GetOpenFileName(&openFileName)) {
\r
4354 /* open the file */
\r
4355 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
4357 MessageBox(hwnd, "File open failed", NULL,
\r
4358 MB_OK|MB_ICONEXCLAMATION);
\r
4362 int err = CommDlgExtendedError();
\r
4363 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
4372 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
4374 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
4377 * Get the first pop-up menu in the menu template. This is the
\r
4378 * menu that TrackPopupMenu displays.
\r
4380 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
4382 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
4385 * TrackPopup uses screen coordinates, so convert the
\r
4386 * coordinates of the mouse click to screen coordinates.
\r
4388 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
4390 /* Draw and track the floating pop-up menu. */
\r
4391 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
4392 pt.x, pt.y, 0, hwnd, NULL);
\r
4394 /* Destroy the menu.*/
\r
4395 DestroyMenu(hmenu);
\r
4400 int sizeX, sizeY, newSizeX, newSizeY;
\r
4402 } ResizeEditPlusButtonsClosure;
\r
4405 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
4407 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
4411 if (hChild == cl->hText) return TRUE;
\r
4412 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
4413 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
4414 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
4415 ScreenToClient(cl->hDlg, &pt);
\r
4416 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
4417 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
4421 /* Resize a dialog that has a (rich) edit field filling most of
\r
4422 the top, with a row of buttons below */
\r
4424 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
4427 int newTextHeight, newTextWidth;
\r
4428 ResizeEditPlusButtonsClosure cl;
\r
4430 /*if (IsIconic(hDlg)) return;*/
\r
4431 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
4433 cl.hdwp = BeginDeferWindowPos(8);
\r
4435 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
4436 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
4437 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
4438 if (newTextHeight < 0) {
\r
4439 newSizeY += -newTextHeight;
\r
4440 newTextHeight = 0;
\r
4442 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
4443 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
4449 cl.newSizeX = newSizeX;
\r
4450 cl.newSizeY = newSizeY;
\r
4451 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
4453 EndDeferWindowPos(cl.hdwp);
\r
4456 /* Center one window over another */
\r
4457 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
4459 RECT rChild, rParent;
\r
4460 int wChild, hChild, wParent, hParent;
\r
4461 int wScreen, hScreen, xNew, yNew;
\r
4464 /* Get the Height and Width of the child window */
\r
4465 GetWindowRect (hwndChild, &rChild);
\r
4466 wChild = rChild.right - rChild.left;
\r
4467 hChild = rChild.bottom - rChild.top;
\r
4469 /* Get the Height and Width of the parent window */
\r
4470 GetWindowRect (hwndParent, &rParent);
\r
4471 wParent = rParent.right - rParent.left;
\r
4472 hParent = rParent.bottom - rParent.top;
\r
4474 /* Get the display limits */
\r
4475 hdc = GetDC (hwndChild);
\r
4476 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
4477 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
4478 ReleaseDC(hwndChild, hdc);
\r
4480 /* Calculate new X position, then adjust for screen */
\r
4481 xNew = rParent.left + ((wParent - wChild) /2);
\r
4484 } else if ((xNew+wChild) > wScreen) {
\r
4485 xNew = wScreen - wChild;
\r
4488 /* Calculate new Y position, then adjust for screen */
\r
4489 yNew = rParent.top + ((hParent - hChild) /2);
\r
4492 } else if ((yNew+hChild) > hScreen) {
\r
4493 yNew = hScreen - hChild;
\r
4496 /* Set it, and return */
\r
4497 return SetWindowPos (hwndChild, NULL,
\r
4498 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
4501 /*---------------------------------------------------------------------------*\
\r
4503 * Startup Dialog functions
\r
4505 \*---------------------------------------------------------------------------*/
\r
4507 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
4509 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
4511 while (*cd != NULL) {
\r
4512 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
4518 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
4520 char buf1[ARG_MAX];
\r
4523 if (str[0] == '@') {
\r
4524 FILE* f = fopen(str + 1, "r");
\r
4526 DisplayFatalError(str + 1, errno, 2);
\r
4529 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
4531 buf1[len] = NULLCHAR;
\r
4535 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
4538 char buf[MSG_SIZ];
\r
4539 char *end = strchr(str, '\n');
\r
4540 if (end == NULL) return;
\r
4541 memcpy(buf, str, end - str);
\r
4542 buf[end - str] = NULLCHAR;
\r
4543 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
4549 SetStartupDialogEnables(HWND hDlg)
\r
4551 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
4552 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
4553 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
4554 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
4555 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
4556 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
4557 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
4558 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
4559 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
4560 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
4561 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
4562 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
4563 IsDlgButtonChecked(hDlg, OPT_View));
\r
4567 QuoteForFilename(char *filename)
\r
4569 int dquote, space;
\r
4570 dquote = strchr(filename, '"') != NULL;
\r
4571 space = strchr(filename, ' ') != NULL;
\r
4572 if (dquote || space) {
\r
4584 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
4586 char buf[MSG_SIZ];
\r
4589 InitComboStringsFromOption(hwndCombo, nthnames);
\r
4590 q = QuoteForFilename(nthcp);
\r
4591 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
4592 if (*nthdir != NULLCHAR) {
\r
4593 q = QuoteForFilename(nthdir);
\r
4594 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
4596 if (*nthcp == NULLCHAR) {
\r
4597 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\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
4605 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4607 char buf[MSG_SIZ];
\r
4611 switch (message) {
\r
4612 case WM_INITDIALOG:
\r
4613 /* Center the dialog */
\r
4614 CenterWindow (hDlg, GetDesktopWindow());
\r
4615 /* Initialize the dialog items */
\r
4616 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
4617 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
4618 firstChessProgramNames);
\r
4619 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
4620 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
4621 secondChessProgramNames);
\r
4622 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
4623 InitComboStringsFromOption(hwndCombo, icsNames);
\r
4624 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
4625 if (*appData.icsHelper != NULLCHAR) {
\r
4626 char *q = QuoteForFilename(appData.icsHelper);
\r
4627 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
4629 if (*appData.icsHost == NULLCHAR) {
\r
4630 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
4631 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
4632 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
4633 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
4634 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
4636 if (chessProgram) {
\r
4637 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
4638 } else if (appData.icsActive) {
\r
4639 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
4640 } else if (appData.noChessProgram) {
\r
4641 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
4643 SetStartupDialogEnables(hDlg);
\r
4647 switch (LOWORD(wParam)) {
\r
4649 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
4650 strcpy(buf, "/fcp=");
\r
4651 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4653 ParseArgs(StringGet, &p);
\r
4654 strcpy(buf, "/scp=");
\r
4655 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4657 ParseArgs(StringGet, &p);
\r
4658 appData.noChessProgram = FALSE;
\r
4659 appData.icsActive = FALSE;
\r
4660 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
4661 strcpy(buf, "/ics /icshost=");
\r
4662 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4664 ParseArgs(StringGet, &p);
\r
4665 if (appData.zippyPlay) {
\r
4666 strcpy(buf, "/fcp=");
\r
4667 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4669 ParseArgs(StringGet, &p);
\r
4671 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
4672 appData.noChessProgram = TRUE;
\r
4673 appData.icsActive = FALSE;
\r
4675 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
4676 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
4679 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
4680 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
4682 ParseArgs(StringGet, &p);
\r
4684 EndDialog(hDlg, TRUE);
\r
4691 case IDM_HELPCONTENTS:
\r
4692 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
4693 MessageBox (GetFocus(),
\r
4694 "Unable to activate help",
\r
4695 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4700 SetStartupDialogEnables(hDlg);
\r
4708 /*---------------------------------------------------------------------------*\
\r
4710 * About box dialog functions
\r
4712 \*---------------------------------------------------------------------------*/
\r
4714 /* Process messages for "About" dialog box */
\r
4716 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4718 switch (message) {
\r
4719 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4720 /* Center the dialog over the application window */
\r
4721 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4722 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
4725 case WM_COMMAND: /* message: received a command */
\r
4726 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
4727 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
4728 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4736 /*---------------------------------------------------------------------------*\
\r
4738 * Comment Dialog functions
\r
4740 \*---------------------------------------------------------------------------*/
\r
4743 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4745 static HANDLE hwndText = NULL;
\r
4746 int len, newSizeX, newSizeY, flags;
\r
4747 static int sizeX, sizeY;
\r
4752 switch (message) {
\r
4753 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4754 /* Initialize the dialog items */
\r
4755 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
4756 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
4757 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
4758 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
4759 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
4760 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
4761 SetWindowText(hDlg, commentTitle);
\r
4762 if (editComment) {
\r
4763 SetFocus(hwndText);
\r
4765 SetFocus(GetDlgItem(hDlg, IDOK));
\r
4767 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
4768 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
4769 MAKELPARAM(FALSE, 0));
\r
4770 /* Size and position the dialog */
\r
4771 if (!commentDialog) {
\r
4772 commentDialog = hDlg;
\r
4773 flags = SWP_NOZORDER;
\r
4774 GetClientRect(hDlg, &rect);
\r
4775 sizeX = rect.right;
\r
4776 sizeY = rect.bottom;
\r
4777 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
4778 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
4779 WINDOWPLACEMENT wp;
\r
4780 EnsureOnScreen(&commentX, &commentY);
\r
4781 wp.length = sizeof(WINDOWPLACEMENT);
\r
4783 wp.showCmd = SW_SHOW;
\r
4784 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
4785 wp.rcNormalPosition.left = commentX;
\r
4786 wp.rcNormalPosition.right = commentX + commentW;
\r
4787 wp.rcNormalPosition.top = commentY;
\r
4788 wp.rcNormalPosition.bottom = commentY + commentH;
\r
4789 SetWindowPlacement(hDlg, &wp);
\r
4791 GetClientRect(hDlg, &rect);
\r
4792 newSizeX = rect.right;
\r
4793 newSizeY = rect.bottom;
\r
4794 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
4795 newSizeX, newSizeY);
\r
4802 case WM_COMMAND: /* message: received a command */
\r
4803 switch (LOWORD(wParam)) {
\r
4805 if (editComment) {
\r
4807 /* Read changed options from the dialog box */
\r
4808 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
4809 len = GetWindowTextLength(hwndText);
\r
4810 str = (char *) malloc(len + 1);
\r
4811 GetWindowText(hwndText, str, len + 1);
\r
4820 ReplaceComment(commentIndex, str);
\r
4827 case OPT_CancelComment:
\r
4831 case OPT_ClearComment:
\r
4832 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
4835 case OPT_EditComment:
\r
4836 EditCommentEvent();
\r
4845 newSizeX = LOWORD(lParam);
\r
4846 newSizeY = HIWORD(lParam);
\r
4847 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
4852 case WM_GETMINMAXINFO:
\r
4853 /* Prevent resizing window too small */
\r
4854 mmi = (MINMAXINFO *) lParam;
\r
4855 mmi->ptMinTrackSize.x = 100;
\r
4856 mmi->ptMinTrackSize.y = 100;
\r
4863 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
4868 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
4870 if (str == NULL) str = "";
\r
4871 p = (char *) malloc(2 * strlen(str) + 2);
\r
4874 if (*str == '\n') *q++ = '\r';
\r
4878 if (commentText != NULL) free(commentText);
\r
4880 commentIndex = index;
\r
4881 commentTitle = title;
\r
4883 editComment = edit;
\r
4885 if (commentDialog) {
\r
4886 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
4887 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
4889 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
4890 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
4891 hwndMain, (DLGPROC)lpProc);
\r
4892 FreeProcInstance(lpProc);
\r
4894 commentDialogUp = TRUE;
\r
4898 /*---------------------------------------------------------------------------*\
\r
4900 * Type-in move dialog functions
\r
4902 \*---------------------------------------------------------------------------*/
\r
4905 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4907 char move[MSG_SIZ];
\r
4909 ChessMove moveType;
\r
4910 int fromX, fromY, toX, toY;
\r
4913 switch (message) {
\r
4914 case WM_INITDIALOG:
\r
4915 move[0] = (char) lParam;
\r
4916 move[1] = NULLCHAR;
\r
4917 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4918 hInput = GetDlgItem(hDlg, OPT_Move);
\r
4919 SetWindowText(hInput, move);
\r
4921 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
4925 switch (LOWORD(wParam)) {
\r
4927 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
4928 gameMode != Training) {
\r
4929 DisplayMoveError("Displayed move is not current");
\r
4931 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
4932 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
4933 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
4934 if (gameMode != Training)
\r
4935 forwardMostMove = currentMove;
\r
4936 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4938 DisplayMoveError("Could not parse move");
\r
4941 EndDialog(hDlg, TRUE);
\r
4944 EndDialog(hDlg, FALSE);
\r
4955 PopUpMoveDialog(char firstchar)
\r
4959 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
4960 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
4961 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
4962 gameMode == EditPosition || gameMode == IcsExamining ||
\r
4963 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
4964 gameMode == Training) {
\r
4965 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
4966 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
4967 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
4968 FreeProcInstance(lpProc);
\r
4972 /*---------------------------------------------------------------------------*\
\r
4976 \*---------------------------------------------------------------------------*/
\r
4978 /* Nonmodal error box */
\r
4979 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
4980 WPARAM wParam, LPARAM lParam);
\r
4983 ErrorPopUp(char *title, char *content)
\r
4987 BOOLEAN modal = hwndMain == NULL;
\r
5005 strncpy(errorTitle, title, sizeof(errorTitle));
\r
5006 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
5009 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
5011 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
5012 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
5013 hwndMain, (DLGPROC)lpProc);
\r
5014 FreeProcInstance(lpProc);
\r
5021 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
5022 if (errorDialog == NULL) return;
\r
5023 DestroyWindow(errorDialog);
\r
5024 errorDialog = NULL;
\r
5028 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5033 switch (message) {
\r
5034 case WM_INITDIALOG:
\r
5035 GetWindowRect(hDlg, &rChild);
\r
5036 SetWindowPos(hDlg, NULL, rChild.left,
\r
5037 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
5038 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
5039 errorDialog = hDlg;
\r
5040 SetWindowText(hDlg, errorTitle);
\r
5041 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
5042 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
5046 switch (LOWORD(wParam)) {
\r
5049 if (errorDialog == hDlg) errorDialog = NULL;
\r
5050 DestroyWindow(hDlg);
\r
5061 /*---------------------------------------------------------------------------*\
\r
5063 * Ics Interaction console functions
\r
5065 \*---------------------------------------------------------------------------*/
\r
5067 #define HISTORY_SIZE 64
\r
5068 static char *history[HISTORY_SIZE];
\r
5069 int histIn = 0, histP = 0;
\r
5072 SaveInHistory(char *cmd)
\r
5074 if (history[histIn] != NULL) {
\r
5075 free(history[histIn]);
\r
5076 history[histIn] = NULL;
\r
5078 if (*cmd == NULLCHAR) return;
\r
5079 history[histIn] = StrSave(cmd);
\r
5080 histIn = (histIn + 1) % HISTORY_SIZE;
\r
5081 if (history[histIn] != NULL) {
\r
5082 free(history[histIn]);
\r
5083 history[histIn] = NULL;
\r
5089 PrevInHistory(char *cmd)
\r
5092 if (histP == histIn) {
\r
5093 if (history[histIn] != NULL) free(history[histIn]);
\r
5094 history[histIn] = StrSave(cmd);
\r
5096 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
5097 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
5099 return history[histP];
\r
5105 if (histP == histIn) return NULL;
\r
5106 histP = (histP + 1) % HISTORY_SIZE;
\r
5107 return history[histP];
\r
5114 BOOLEAN immediate;
\r
5115 } IcsTextMenuEntry;
\r
5116 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
5117 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
5120 ParseIcsTextMenu(char *icsTextMenuString)
\r
5123 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
5124 char *p = icsTextMenuString;
\r
5125 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5128 if (e->command != NULL) {
\r
5130 e->command = NULL;
\r
5134 e = icsTextMenuEntry;
\r
5135 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5136 if (*p == ';' || *p == '\n') {
\r
5137 e->item = strdup("-");
\r
5138 e->command = NULL;
\r
5140 } else if (*p == '-') {
\r
5141 e->item = strdup("-");
\r
5142 e->command = NULL;
\r
5146 char *q, *r, *s, *t;
\r
5148 q = strchr(p, ',');
\r
5149 if (q == NULL) break;
\r
5151 r = strchr(q + 1, ',');
\r
5152 if (r == NULL) break;
\r
5154 s = strchr(r + 1, ',');
\r
5155 if (s == NULL) break;
\r
5158 t = strchr(s + 1, c);
\r
5161 t = strchr(s + 1, c);
\r
5163 if (t != NULL) *t = NULLCHAR;
\r
5164 e->item = strdup(p);
\r
5165 e->command = strdup(q + 1);
\r
5166 e->getname = *(r + 1) != '0';
\r
5167 e->immediate = *(s + 1) != '0';
\r
5171 if (t == NULL) break;
\r
5180 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
5184 hmenu = LoadMenu(hInst, "TextMenu");
\r
5185 h = GetSubMenu(hmenu, 0);
\r
5187 if (strcmp(e->item, "-") == 0) {
\r
5188 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
5190 if (e->item[0] == '|') {
\r
5191 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
5192 IDM_CommandX + i, &e->item[1]);
\r
5194 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
5203 WNDPROC consoleTextWindowProc;
\r
5206 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
5208 char buf[MSG_SIZ], name[MSG_SIZ];
\r
5209 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5213 SetWindowText(hInput, command);
\r
5215 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5217 sel.cpMin = 999999;
\r
5218 sel.cpMax = 999999;
\r
5219 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5224 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5225 if (sel.cpMin == sel.cpMax) {
\r
5226 /* Expand to surrounding word */
\r
5229 tr.chrg.cpMax = sel.cpMin;
\r
5230 tr.chrg.cpMin = --sel.cpMin;
\r
5231 if (sel.cpMin < 0) break;
\r
5232 tr.lpstrText = name;
\r
5233 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5234 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5238 tr.chrg.cpMin = sel.cpMax;
\r
5239 tr.chrg.cpMax = ++sel.cpMax;
\r
5240 tr.lpstrText = name;
\r
5241 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
5242 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5245 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5246 MessageBeep(MB_ICONEXCLAMATION);
\r
5250 tr.lpstrText = name;
\r
5251 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5253 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5254 MessageBeep(MB_ICONEXCLAMATION);
\r
5257 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
5260 sprintf(buf, "%s %s", command, name);
\r
5261 SetWindowText(hInput, buf);
\r
5262 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5264 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
5265 SetWindowText(hInput, buf);
\r
5266 sel.cpMin = 999999;
\r
5267 sel.cpMax = 999999;
\r
5268 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5274 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5279 switch (message) {
\r
5281 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5284 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
5287 sel.cpMin = 999999;
\r
5288 sel.cpMax = 999999;
\r
5289 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5290 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
5295 if (wParam == '\t') {
\r
5296 if (GetKeyState(VK_SHIFT) < 0) {
\r
5298 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5299 if (buttonDesc[0].hwnd) {
\r
5300 SetFocus(buttonDesc[0].hwnd);
\r
5302 SetFocus(hwndMain);
\r
5306 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
5309 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5311 SendMessage(hInput, message, wParam, lParam);
\r
5315 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5317 return SendMessage(hInput, message, wParam, lParam);
\r
5318 case WM_MBUTTONDOWN:
\r
5319 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5320 case WM_RBUTTONDOWN:
\r
5321 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
5322 /* Move selection here if it was empty */
\r
5324 pt.x = LOWORD(lParam);
\r
5325 pt.y = HIWORD(lParam);
\r
5326 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5327 if (sel.cpMin == sel.cpMax) {
\r
5328 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
5329 sel.cpMax = sel.cpMin;
\r
5330 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5332 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
5335 case WM_RBUTTONUP:
\r
5336 if (GetKeyState(VK_SHIFT) & ~1) {
\r
5337 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5338 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5341 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
5342 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5343 if (sel.cpMin == sel.cpMax) {
\r
5344 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
5345 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
5347 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
5348 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
5350 pt.x = LOWORD(lParam);
\r
5351 pt.y = HIWORD(lParam);
\r
5352 MenuPopup(hwnd, pt, hmenu, -1);
\r
5356 switch (LOWORD(wParam)) {
\r
5357 case IDM_QuickPaste:
\r
5359 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5360 if (sel.cpMin == sel.cpMax) {
\r
5361 MessageBeep(MB_ICONEXCLAMATION);
\r
5364 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5365 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5366 SendMessage(hInput, WM_PASTE, 0, 0);
\r
5371 SendMessage(hwnd, WM_CUT, 0, 0);
\r
5374 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
5377 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5381 int i = LOWORD(wParam) - IDM_CommandX;
\r
5382 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
5383 icsTextMenuEntry[i].command != NULL) {
\r
5384 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
5385 icsTextMenuEntry[i].getname,
\r
5386 icsTextMenuEntry[i].immediate);
\r
5394 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
5397 WNDPROC consoleInputWindowProc;
\r
5400 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5402 char buf[MSG_SIZ];
\r
5404 static BOOL sendNextChar = FALSE;
\r
5405 static BOOL quoteNextChar = FALSE;
\r
5406 InputSource *is = consoleInputSource;
\r
5410 switch (message) {
\r
5412 if (!appData.localLineEditing || sendNextChar) {
\r
5413 is->buf[0] = (CHAR) wParam;
\r
5415 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5416 sendNextChar = FALSE;
\r
5419 if (quoteNextChar) {
\r
5420 buf[0] = (char) wParam;
\r
5421 buf[1] = NULLCHAR;
\r
5422 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
5423 quoteNextChar = FALSE;
\r
5427 case '\r': /* Enter key */
\r
5428 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
5429 if (consoleEcho) SaveInHistory(is->buf);
\r
5430 is->buf[is->count++] = '\n';
\r
5431 is->buf[is->count] = NULLCHAR;
\r
5432 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5433 if (consoleEcho) {
\r
5434 ConsoleOutput(is->buf, is->count, TRUE);
\r
5435 } else if (appData.localLineEditing) {
\r
5436 ConsoleOutput("\n", 1, TRUE);
\r
5439 case '\033': /* Escape key */
\r
5440 SetWindowText(hwnd, "");
\r
5441 cf.cbSize = sizeof(CHARFORMAT);
\r
5442 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
5443 if (consoleEcho) {
\r
5444 cf.crTextColor = textAttribs[ColorNormal].color;
\r
5446 cf.crTextColor = COLOR_ECHOOFF;
\r
5448 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
5449 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
5451 case '\t': /* Tab key */
\r
5452 if (GetKeyState(VK_SHIFT) < 0) {
\r
5454 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
5457 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5458 if (buttonDesc[0].hwnd) {
\r
5459 SetFocus(buttonDesc[0].hwnd);
\r
5461 SetFocus(hwndMain);
\r
5465 case '\023': /* Ctrl+S */
\r
5466 sendNextChar = TRUE;
\r
5468 case '\021': /* Ctrl+Q */
\r
5469 quoteNextChar = TRUE;
\r
5478 GetWindowText(hwnd, buf, MSG_SIZ);
\r
5479 p = PrevInHistory(buf);
\r
5481 SetWindowText(hwnd, p);
\r
5482 sel.cpMin = 999999;
\r
5483 sel.cpMax = 999999;
\r
5484 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5489 p = NextInHistory();
\r
5491 SetWindowText(hwnd, p);
\r
5492 sel.cpMin = 999999;
\r
5493 sel.cpMax = 999999;
\r
5494 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5500 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5504 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
5508 case WM_MBUTTONDOWN:
\r
5509 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5510 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5512 case WM_RBUTTONUP:
\r
5513 if (GetKeyState(VK_SHIFT) & ~1) {
\r
5514 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5515 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5519 hmenu = LoadMenu(hInst, "InputMenu");
\r
5520 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5521 if (sel.cpMin == sel.cpMax) {
\r
5522 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
5523 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
5525 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
5526 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
5528 pt.x = LOWORD(lParam);
\r
5529 pt.y = HIWORD(lParam);
\r
5530 MenuPopup(hwnd, pt, hmenu, -1);
\r
5534 switch (LOWORD(wParam)) {
\r
5536 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
5538 case IDM_SelectAll:
\r
5540 sel.cpMax = -1; /*999999?*/
\r
5541 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5544 SendMessage(hwnd, WM_CUT, 0, 0);
\r
5547 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
5550 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5555 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
5558 #define CO_MAX 100000
\r
5559 #define CO_TRIM 1000
\r
5562 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5564 static HWND hText, hInput, hFocus;
\r
5565 InputSource *is = consoleInputSource;
\r
5567 static int sizeX, sizeY;
\r
5568 int newSizeX, newSizeY;
\r
5571 switch (message) {
\r
5572 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5573 hwndConsole = hDlg;
\r
5574 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
5575 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
5577 consoleTextWindowProc = (WNDPROC)
\r
5578 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
5579 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
5580 consoleInputWindowProc = (WNDPROC)
\r
5581 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
5582 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
5583 Colorize(ColorNormal, TRUE);
\r
5584 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
5585 ChangedConsoleFont();
\r
5586 GetClientRect(hDlg, &rect);
\r
5587 sizeX = rect.right;
\r
5588 sizeY = rect.bottom;
\r
5589 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
5590 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
5591 WINDOWPLACEMENT wp;
\r
5592 EnsureOnScreen(&consoleX, &consoleY);
\r
5593 wp.length = sizeof(WINDOWPLACEMENT);
\r
5595 wp.showCmd = SW_SHOW;
\r
5596 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
5597 wp.rcNormalPosition.left = consoleX;
\r
5598 wp.rcNormalPosition.right = consoleX + consoleW;
\r
5599 wp.rcNormalPosition.top = consoleY;
\r
5600 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
5601 SetWindowPlacement(hDlg, &wp);
\r
5615 if (IsIconic(hDlg)) break;
\r
5616 newSizeX = LOWORD(lParam);
\r
5617 newSizeY = HIWORD(lParam);
\r
5618 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
5619 RECT rectText, rectInput;
\r
5621 int newTextHeight, newTextWidth;
\r
5622 GetWindowRect(hText, &rectText);
\r
5623 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5624 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5625 if (newTextHeight < 0) {
\r
5626 newSizeY += -newTextHeight;
\r
5627 newTextHeight = 0;
\r
5629 SetWindowPos(hText, NULL, 0, 0,
\r
5630 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5631 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
5632 pt.x = rectInput.left;
\r
5633 pt.y = rectInput.top + newSizeY - sizeY;
\r
5634 ScreenToClient(hDlg, &pt);
\r
5635 SetWindowPos(hInput, NULL,
\r
5636 pt.x, pt.y, /* needs client coords */
\r
5637 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
5638 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
5644 case WM_GETMINMAXINFO:
\r
5645 /* Prevent resizing window too small */
\r
5646 mmi = (MINMAXINFO *) lParam;
\r
5647 mmi->ptMinTrackSize.x = 100;
\r
5648 mmi->ptMinTrackSize.y = 100;
\r
5651 return DefWindowProc(hDlg, message, wParam, lParam);
\r
5659 if (hwndConsole) return;
\r
5660 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
5661 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
5666 ConsoleOutput(char* data, int length, int forceVisible)
\r
5671 char buf[CO_MAX+1];
\r
5674 static int delayLF = 0;
\r
5675 CHARRANGE savesel, sel;
\r
5677 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
5685 while (length--) {
\r
5693 } else if (*p == '\007') {
\r
5694 MyPlaySound(&sounds[(int)SoundBell]);
\r
5701 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5702 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
5703 /* Save current selection */
\r
5704 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
5705 exlen = GetWindowTextLength(hText);
\r
5706 /* Find out whether current end of text is visible */
\r
5707 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
5708 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
5709 /* Trim existing text if it's too long */
\r
5710 if (exlen + (q - buf) > CO_MAX) {
\r
5711 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
5714 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5715 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
5717 savesel.cpMin -= trim;
\r
5718 savesel.cpMax -= trim;
\r
5719 if (exlen < 0) exlen = 0;
\r
5720 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
5721 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
5723 /* Append the new text */
\r
5724 sel.cpMin = exlen;
\r
5725 sel.cpMax = exlen;
\r
5726 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5727 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
5728 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
5729 if (forceVisible || exlen == 0 ||
\r
5730 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
5731 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
5732 /* Scroll to make new end of text visible if old end of text
\r
5733 was visible or new text is an echo of user typein */
\r
5734 sel.cpMin = 9999999;
\r
5735 sel.cpMax = 9999999;
\r
5736 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5737 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
5738 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
5739 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
5741 if (savesel.cpMax == exlen || forceVisible) {
\r
5742 /* Move insert point to new end of text if it was at the old
\r
5743 end of text or if the new text is an echo of user typein */
\r
5744 sel.cpMin = 9999999;
\r
5745 sel.cpMax = 9999999;
\r
5746 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5748 /* Restore previous selection */
\r
5749 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
5751 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
5758 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
5759 RECT *rect, char *color)
\r
5763 COLORREF oldFg, oldBg;
\r
5766 if (appData.clockMode) {
\r
5768 sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));
\r
5770 sprintf(buf, "%s: %s", color, TimeString(timeRemaining));
\r
5777 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
5778 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
5780 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
5781 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
5783 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
5785 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
5786 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
5787 rect, str, strlen(str), NULL);
\r
5789 (void) SetTextColor(hdc, oldFg);
\r
5790 (void) SetBkColor(hdc, oldBg);
\r
5791 (void) SelectObject(hdc, oldFont);
\r
5796 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
5801 ResetEvent(ovl->hEvent);
\r
5802 ovl->Offset = ovl->OffsetHigh = 0;
\r
5803 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
5807 err = GetLastError();
\r
5808 if (err == ERROR_IO_PENDING) {
\r
5809 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
5813 err = GetLastError();
\r
5820 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
5825 ResetEvent(ovl->hEvent);
\r
5826 ovl->Offset = ovl->OffsetHigh = 0;
\r
5827 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
5831 err = GetLastError();
\r
5832 if (err == ERROR_IO_PENDING) {
\r
5833 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
5837 err = GetLastError();
\r
5845 InputThread(LPVOID arg)
\r
5850 is = (InputSource *) arg;
\r
5851 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
5852 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
5853 while (is->hThread != NULL) {
\r
5854 is->error = DoReadFile(is->hFile, is->next,
\r
5855 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
5856 &is->count, &ovl);
\r
5857 if (is->error == NO_ERROR) {
\r
5858 is->next += is->count;
\r
5860 if (is->error == ERROR_BROKEN_PIPE) {
\r
5861 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
5864 is->count = (DWORD) -1;
\r
5867 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5868 if (is->count <= 0) break; /* Quit on EOF or error */
\r
5870 CloseHandle(ovl.hEvent);
\r
5871 CloseHandle(is->hFile);
\r
5876 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
5878 NonOvlInputThread(LPVOID arg)
\r
5885 is = (InputSource *) arg;
\r
5886 while (is->hThread != NULL) {
\r
5887 is->error = ReadFile(is->hFile, is->next,
\r
5888 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
5889 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
5890 if (is->error == NO_ERROR) {
\r
5891 /* Change CRLF to LF */
\r
5892 if (is->next > is->buf) {
\r
5894 i = is->count + 1;
\r
5902 if (prev == '\r' && *p == '\n') {
\r
5914 if (is->error == ERROR_BROKEN_PIPE) {
\r
5915 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
5918 is->count = (DWORD) -1;
\r
5921 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5922 if (is->count < 0) break; /* Quit on error */
\r
5924 CloseHandle(is->hFile);
\r
5929 SocketInputThread(LPVOID arg)
\r
5933 is = (InputSource *) arg;
\r
5934 while (is->hThread != NULL) {
\r
5935 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
5936 if ((int)is->count == SOCKET_ERROR) {
\r
5937 is->count = (DWORD) -1;
\r
5938 is->error = WSAGetLastError();
\r
5940 is->error = NO_ERROR;
\r
5941 is->next += is->count;
\r
5942 if (is->count == 0 && is->second == is) {
\r
5943 /* End of file on stderr; quit with no message */
\r
5947 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5948 if (is->count <= 0) break; /* Quit on EOF or error */
\r
5954 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5958 is = (InputSource *) lParam;
\r
5959 if (is->lineByLine) {
\r
5960 /* Feed in lines one by one */
\r
5961 char *p = is->buf;
\r
5963 while (q < is->next) {
\r
5964 if (*q++ == '\n') {
\r
5965 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
5969 /* Move any partial line to the start of the buffer */
\r
5971 while (p < is->next) {
\r
5975 if (is->error != NO_ERROR || is->count == 0) {
\r
5976 /* Notify backend of the error. Note: If there was a partial
\r
5977 line at the end, it is not flushed through. */
\r
5978 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
5981 /* Feed in the whole chunk of input at once */
\r
5982 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
5983 is->next = is->buf;
\r
5987 /*---------------------------------------------------------------------------*\
\r
5989 * Menu enables. Used when setting various modes.
\r
5991 \*---------------------------------------------------------------------------*/
\r
5999 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
6001 while (enab->item > 0) {
\r
6002 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
6007 Enables gnuEnables[] = {
\r
6008 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6009 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6010 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
6011 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
6012 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
6013 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
6014 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6015 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
6016 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
6017 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
6021 Enables icsEnables[] = {
\r
6022 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6023 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6024 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6025 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6026 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6027 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
6028 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
6029 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
6030 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6031 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
6032 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
6033 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
6038 Enables zippyEnables[] = {
\r
6039 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6040 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
6041 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
6046 Enables ncpEnables[] = {
\r
6047 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6048 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6049 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6050 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6051 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6052 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
6053 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
6054 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
6055 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
6056 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
6057 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6058 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6059 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
6060 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
6061 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
6065 Enables trainingOnEnables[] = {
\r
6066 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
6067 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
6068 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
6069 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
6070 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
6071 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
6072 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6073 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
6077 Enables trainingOffEnables[] = {
\r
6078 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
6079 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
6080 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
6081 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
6082 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
6083 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
6084 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6085 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
6089 /* These modify either ncpEnables or gnuEnables */
\r
6090 Enables cmailEnables[] = {
\r
6091 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
6092 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
6093 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
6094 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
6095 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
6096 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6097 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
6101 Enables machineThinkingEnables[] = {
\r
6102 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6103 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
6104 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
6105 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6106 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
6107 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6108 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6109 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6110 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6111 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
6112 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6113 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6114 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6115 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
6116 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6120 Enables userThinkingEnables[] = {
\r
6121 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6122 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
6123 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
6124 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6125 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
6126 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6127 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6128 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6129 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6130 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
6131 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
6132 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
6133 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
6134 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
6135 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
6139 /*---------------------------------------------------------------------------*\
\r
6141 * Front-end interface functions exported by XBoard.
\r
6142 * Functions appear in same order as prototypes in frontend.h.
\r
6144 \*---------------------------------------------------------------------------*/
\r
6148 static UINT prevChecked = 0;
\r
6149 static int prevPausing = 0;
\r
6152 if (pausing != prevPausing) {
\r
6153 prevPausing = pausing;
\r
6154 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
6155 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
6156 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
6159 switch (gameMode) {
\r
6160 case BeginningOfGame:
\r
6161 if (appData.icsActive)
\r
6162 nowChecked = IDM_IcsClient;
\r
6163 else if (appData.noChessProgram)
\r
6164 nowChecked = IDM_EditGame;
\r
6166 nowChecked = IDM_MachineBlack;
\r
6168 case MachinePlaysBlack:
\r
6169 nowChecked = IDM_MachineBlack;
\r
6171 case MachinePlaysWhite:
\r
6172 nowChecked = IDM_MachineWhite;
\r
6174 case TwoMachinesPlay:
\r
6175 nowChecked = IDM_TwoMachines;
\r
6178 nowChecked = IDM_AnalysisMode;
\r
6181 nowChecked = IDM_AnalyzeFile;
\r
6184 nowChecked = IDM_EditGame;
\r
6186 case PlayFromGameFile:
\r
6187 nowChecked = IDM_LoadGame;
\r
6189 case EditPosition:
\r
6190 nowChecked = IDM_EditPosition;
\r
6193 nowChecked = IDM_Training;
\r
6195 case IcsPlayingWhite:
\r
6196 case IcsPlayingBlack:
\r
6197 case IcsObserving:
\r
6199 nowChecked = IDM_IcsClient;
\r
6206 if (prevChecked != 0)
\r
6207 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6208 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
6209 if (nowChecked != 0)
\r
6210 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6211 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
6213 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
6214 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
6215 MF_BYCOMMAND|MF_ENABLED);
\r
6217 (void) EnableMenuItem(GetMenu(hwndMain),
\r
6218 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
6221 prevChecked = nowChecked;
\r
6227 HMENU hmenu = GetMenu(hwndMain);
\r
6228 SetMenuEnables(hmenu, icsEnables);
\r
6229 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
6230 MF_BYPOSITION|MF_ENABLED);
\r
6232 if (appData.zippyPlay) {
\r
6233 SetMenuEnables(hmenu, zippyEnables);
\r
6241 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
6247 HMENU hmenu = GetMenu(hwndMain);
\r
6248 SetMenuEnables(hmenu, ncpEnables);
\r
6249 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
6250 MF_BYPOSITION|MF_GRAYED);
\r
6251 DrawMenuBar(hwndMain);
\r
6257 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
6261 SetTrainingModeOn()
\r
6264 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
6265 for (i = 0; i < N_BUTTONS; i++) {
\r
6266 if (buttonDesc[i].hwnd != NULL)
\r
6267 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
6272 VOID SetTrainingModeOff()
\r
6275 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
6276 for (i = 0; i < N_BUTTONS; i++) {
\r
6277 if (buttonDesc[i].hwnd != NULL)
\r
6278 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
6284 SetUserThinkingEnables()
\r
6286 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
6290 SetMachineThinkingEnables()
\r
6292 HMENU hMenu = GetMenu(hwndMain);
\r
6293 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
6295 SetMenuEnables(hMenu, machineThinkingEnables);
\r
6297 if (gameMode == MachinePlaysBlack) {
\r
6298 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
6299 } else if (gameMode == MachinePlaysWhite) {
\r
6300 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
6301 } else if (gameMode == TwoMachinesPlay) {
\r
6302 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
6308 DisplayTitle(char *str)
\r
6310 char title[MSG_SIZ], *host;
\r
6311 if (str[0] != NULLCHAR) {
\r
6312 strcpy(title, str);
\r
6313 } else if (appData.icsActive) {
\r
6314 if (appData.icsCommPort[0] != NULLCHAR)
\r
6317 host = appData.icsHost;
\r
6318 sprintf(title, "%s: %s", szTitle, host);
\r
6319 } else if (appData.noChessProgram) {
\r
6320 strcpy(title, szTitle);
\r
6322 strcpy(title, szTitle);
\r
6323 strcat(title, ": ");
\r
6324 strcat(title, first.tidy);
\r
6326 SetWindowText(hwndMain, title);
\r
6331 DisplayMessage(char *str1, char *str2)
\r
6335 int remain = MESSAGE_TEXT_MAX - 1;
\r
6338 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
6339 messageText[0] = NULLCHAR;
\r
6341 len = strlen(str1);
\r
6342 if (len > remain) len = remain;
\r
6343 strncpy(messageText, str1, len);
\r
6344 messageText[len] = NULLCHAR;
\r
6347 if (*str2 && remain >= 2) {
\r
6349 strcat(messageText, " ");
\r
6352 len = strlen(str2);
\r
6353 if (len > remain) len = remain;
\r
6354 strncat(messageText, str2, len);
\r
6356 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
6358 if (IsIconic(hwndMain)) return;
\r
6359 hdc = GetDC(hwndMain);
\r
6360 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
6361 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
6362 &messageRect, messageText, strlen(messageText), NULL);
\r
6363 (void) SelectObject(hdc, oldFont);
\r
6364 (void) ReleaseDC(hwndMain, hdc);
\r
6368 DisplayError(char *str, int error)
\r
6370 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
6376 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
6377 NULL, error, LANG_NEUTRAL,
\r
6378 (LPSTR) buf2, MSG_SIZ, NULL);
\r
6380 sprintf(buf, "%s:\n%s", str, buf2);
\r
6382 ErrorMap *em = errmap;
\r
6383 while (em->err != 0 && em->err != error) em++;
\r
6384 if (em->err != 0) {
\r
6385 sprintf(buf, "%s:\n%s", str, em->msg);
\r
6387 sprintf(buf, "%s:\nError code %d", str, error);
\r
6392 ErrorPopUp("Error", buf);
\r
6397 DisplayMoveError(char *str)
\r
6399 fromX = fromY = -1;
\r
6400 ClearHighlights();
\r
6401 DrawPosition(FALSE, NULL);
\r
6402 if (appData.popupMoveErrors) {
\r
6403 ErrorPopUp("Error", str);
\r
6405 DisplayMessage(str, "");
\r
6406 moveErrorMessageUp = TRUE;
\r
6411 DisplayFatalError(char *str, int error, int exitStatus)
\r
6413 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
6415 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
6418 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
6419 NULL, error, LANG_NEUTRAL,
\r
6420 (LPSTR) buf2, MSG_SIZ, NULL);
\r
6422 sprintf(buf, "%s:\n%s", str, buf2);
\r
6424 ErrorMap *em = errmap;
\r
6425 while (em->err != 0 && em->err != error) em++;
\r
6426 if (em->err != 0) {
\r
6427 sprintf(buf, "%s:\n%s", str, em->msg);
\r
6429 sprintf(buf, "%s:\nError code %d", str, error);
\r
6434 if (appData.debugMode) {
\r
6435 fprintf(debugFP, "%s: %s\n", label, str);
\r
6437 if (appData.popupExitMessage) {
\r
6438 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
6439 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
6441 ExitEvent(exitStatus);
\r
6446 DisplayInformation(char *str)
\r
6448 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
6453 DisplayNote(char *str)
\r
6455 ErrorPopUp("Note", str);
\r
6460 char *title, *question, *replyPrefix;
\r
6465 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6467 static QuestionParams *qp;
\r
6468 char reply[MSG_SIZ];
\r
6471 switch (message) {
\r
6472 case WM_INITDIALOG:
\r
6473 qp = (QuestionParams *) lParam;
\r
6474 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
6475 SetWindowText(hDlg, qp->title);
\r
6476 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
6477 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
6481 switch (LOWORD(wParam)) {
\r
6483 strcpy(reply, qp->replyPrefix);
\r
6484 if (*reply) strcat(reply, " ");
\r
6485 len = strlen(reply);
\r
6486 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
6487 strcat(reply, "\n");
\r
6488 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
6489 EndDialog(hDlg, TRUE);
\r
6490 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
6493 EndDialog(hDlg, FALSE);
\r
6504 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
6506 QuestionParams qp;
\r
6510 qp.question = question;
\r
6511 qp.replyPrefix = replyPrefix;
\r
6513 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
6514 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
6515 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
6516 FreeProcInstance(lpProc);
\r
6521 DisplayIcsInteractionTitle(char *str)
\r
6523 char consoleTitle[MSG_SIZ];
\r
6525 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
6526 SetWindowText(hwndConsole, consoleTitle);
\r
6530 DrawPosition(int fullRedraw, Board board)
\r
6532 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
6539 fromX = fromY = -1;
\r
6540 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
6541 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
6542 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
6543 dragInfo.lastpos = dragInfo.pos;
\r
6544 dragInfo.start.x = dragInfo.start.y = -1;
\r
6545 dragInfo.from = dragInfo.start;
\r
6547 DrawPosition(TRUE, NULL);
\r
6553 CommentPopUp(char *title, char *str)
\r
6555 HWND hwnd = GetActiveWindow();
\r
6556 EitherCommentPopUp(0, title, str, FALSE);
\r
6557 SetActiveWindow(hwnd);
\r
6561 CommentPopDown(void)
\r
6563 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
6564 if (commentDialog) {
\r
6565 ShowWindow(commentDialog, SW_HIDE);
\r
6567 commentDialogUp = FALSE;
\r
6571 EditCommentPopUp(int index, char *title, char *str)
\r
6573 EitherCommentPopUp(index, title, str, TRUE);
\r
6580 MyPlaySound(&sounds[(int)SoundMove]);
\r
6583 VOID PlayIcsWinSound()
\r
6585 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
6588 VOID PlayIcsLossSound()
\r
6590 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
6593 VOID PlayIcsDrawSound()
\r
6595 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
6598 VOID PlayIcsUnfinishedSound()
\r
6600 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
6606 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
6614 consoleEcho = TRUE;
\r
6615 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6616 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
6617 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6626 consoleEcho = FALSE;
\r
6627 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6628 /* This works OK: set text and background both to the same color */
\r
6630 cf.crTextColor = COLOR_ECHOOFF;
\r
6631 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6632 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
6635 /* No Raw()...? */
\r
6637 void Colorize(ColorClass cc, int continuation)
\r
6639 currentColorClass = cc;
\r
6640 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6641 consoleCF.crTextColor = textAttribs[cc].color;
\r
6642 consoleCF.dwEffects = textAttribs[cc].effects;
\r
6643 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
6649 static char buf[MSG_SIZ];
\r
6650 DWORD bufsiz = MSG_SIZ;
\r
6652 if (!GetUserName(buf, &bufsiz)) {
\r
6653 /*DisplayError("Error getting user name", GetLastError());*/
\r
6654 strcpy(buf, "User");
\r
6662 static char buf[MSG_SIZ];
\r
6663 DWORD bufsiz = MSG_SIZ;
\r
6665 if (!GetComputerName(buf, &bufsiz)) {
\r
6666 /*DisplayError("Error getting host name", GetLastError());*/
\r
6667 strcpy(buf, "Unknown");
\r
6674 ClockTimerRunning()
\r
6676 return clockTimerEvent != 0;
\r
6682 if (clockTimerEvent == 0) return FALSE;
\r
6683 KillTimer(hwndMain, clockTimerEvent);
\r
6684 clockTimerEvent = 0;
\r
6689 StartClockTimer(long millisec)
\r
6691 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
6692 (UINT) millisec, NULL);
\r
6696 DisplayWhiteClock(long timeRemaining, int highlight)
\r
6699 hdc = GetDC(hwndMain);
\r
6700 if (!IsIconic(hwndMain)) {
\r
6701 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");
\r
6703 if (highlight && iconCurrent == iconBlack) {
\r
6704 iconCurrent = iconWhite;
\r
6705 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6706 if (IsIconic(hwndMain)) {
\r
6707 DrawIcon(hdc, 2, 2, iconCurrent);
\r
6710 (void) ReleaseDC(hwndMain, hdc);
\r
6712 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6716 DisplayBlackClock(long timeRemaining, int highlight)
\r
6719 hdc = GetDC(hwndMain);
\r
6720 if (!IsIconic(hwndMain)) {
\r
6721 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");
\r
6723 if (highlight && iconCurrent == iconWhite) {
\r
6724 iconCurrent = iconBlack;
\r
6725 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6726 if (IsIconic(hwndMain)) {
\r
6727 DrawIcon(hdc, 2, 2, iconCurrent);
\r
6730 (void) ReleaseDC(hwndMain, hdc);
\r
6732 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6737 LoadGameTimerRunning()
\r
6739 return loadGameTimerEvent != 0;
\r
6743 StopLoadGameTimer()
\r
6745 if (loadGameTimerEvent == 0) return FALSE;
\r
6746 KillTimer(hwndMain, loadGameTimerEvent);
\r
6747 loadGameTimerEvent = 0;
\r
6752 StartLoadGameTimer(long millisec)
\r
6754 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
6755 (UINT) millisec, NULL);
\r
6763 char fileTitle[MSG_SIZ];
\r
6765 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
6766 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
6767 appData.oldSaveStyle ? "gam" : "pgn",
\r
6769 "Save Game to File", NULL, fileTitle, NULL);
\r
6771 SaveGame(f, 0, "");
\r
6778 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
6780 if (delayedTimerEvent != 0) {
\r
6781 if (appData.debugMode) {
\r
6782 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
6784 KillTimer(hwndMain, delayedTimerEvent);
\r
6785 delayedTimerEvent = 0;
\r
6786 delayedTimerCallback();
\r
6788 delayedTimerCallback = cb;
\r
6789 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
6790 (UINT) millisec, NULL);
\r
6793 DelayedEventCallback
\r
6796 if (delayedTimerEvent) {
\r
6797 return delayedTimerCallback;
\r
6804 CancelDelayedEvent()
\r
6806 if (delayedTimerEvent) {
\r
6807 KillTimer(hwndMain, delayedTimerEvent);
\r
6808 delayedTimerEvent = 0;
\r
6812 /* Start a child process running the given program.
\r
6813 The process's standard output can be read from "from", and its
\r
6814 standard input can be written to "to".
\r
6815 Exit with fatal error if anything goes wrong.
\r
6816 Returns an opaque pointer that can be used to destroy the process
\r
6820 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
6822 #define BUFSIZE 4096
\r
6824 HANDLE hChildStdinRd, hChildStdinWr,
\r
6825 hChildStdoutRd, hChildStdoutWr;
\r
6826 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
6827 SECURITY_ATTRIBUTES saAttr;
\r
6829 PROCESS_INFORMATION piProcInfo;
\r
6830 STARTUPINFO siStartInfo;
\r
6832 char buf[MSG_SIZ];
\r
6835 if (appData.debugMode) {
\r
6836 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
6841 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
6842 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
6843 saAttr.bInheritHandle = TRUE;
\r
6844 saAttr.lpSecurityDescriptor = NULL;
\r
6847 * The steps for redirecting child's STDOUT:
\r
6848 * 1. Create anonymous pipe to be STDOUT for child.
\r
6849 * 2. Create a noninheritable duplicate of read handle,
\r
6850 * and close the inheritable read handle.
\r
6853 /* Create a pipe for the child's STDOUT. */
\r
6854 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
6855 return GetLastError();
\r
6858 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
6859 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
6860 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
6861 FALSE, /* not inherited */
\r
6862 DUPLICATE_SAME_ACCESS);
\r
6864 return GetLastError();
\r
6866 CloseHandle(hChildStdoutRd);
\r
6869 * The steps for redirecting child's STDIN:
\r
6870 * 1. Create anonymous pipe to be STDIN for child.
\r
6871 * 2. Create a noninheritable duplicate of write handle,
\r
6872 * and close the inheritable write handle.
\r
6875 /* Create a pipe for the child's STDIN. */
\r
6876 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
6877 return GetLastError();
\r
6880 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
6881 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
6882 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
6883 FALSE, /* not inherited */
\r
6884 DUPLICATE_SAME_ACCESS);
\r
6886 return GetLastError();
\r
6888 CloseHandle(hChildStdinWr);
\r
6890 /* Arrange to (1) look in dir for the child .exe file, and
\r
6891 * (2) have dir be the child's working directory. Interpret
\r
6892 * dir relative to the directory WinBoard loaded from. */
\r
6893 GetCurrentDirectory(MSG_SIZ, buf);
\r
6894 SetCurrentDirectory(installDir);
\r
6895 SetCurrentDirectory(dir);
\r
6897 /* Now create the child process. */
\r
6899 siStartInfo.cb = sizeof(STARTUPINFO);
\r
6900 siStartInfo.lpReserved = NULL;
\r
6901 siStartInfo.lpDesktop = NULL;
\r
6902 siStartInfo.lpTitle = NULL;
\r
6903 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
6904 siStartInfo.cbReserved2 = 0;
\r
6905 siStartInfo.lpReserved2 = NULL;
\r
6906 siStartInfo.hStdInput = hChildStdinRd;
\r
6907 siStartInfo.hStdOutput = hChildStdoutWr;
\r
6908 siStartInfo.hStdError = hChildStdoutWr;
\r
6910 fSuccess = CreateProcess(NULL,
\r
6911 cmdLine, /* command line */
\r
6912 NULL, /* process security attributes */
\r
6913 NULL, /* primary thread security attrs */
\r
6914 TRUE, /* handles are inherited */
\r
6915 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
6916 NULL, /* use parent's environment */
\r
6918 &siStartInfo, /* STARTUPINFO pointer */
\r
6919 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
6921 err = GetLastError();
\r
6922 SetCurrentDirectory(buf); /* return to prev directory */
\r
6927 /* Close the handles we don't need in the parent */
\r
6928 CloseHandle(piProcInfo.hThread);
\r
6929 CloseHandle(hChildStdinRd);
\r
6930 CloseHandle(hChildStdoutWr);
\r
6932 /* Prepare return value */
\r
6933 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
6934 cp->kind = CPReal;
\r
6935 cp->hProcess = piProcInfo.hProcess;
\r
6936 cp->pid = piProcInfo.dwProcessId;
\r
6937 cp->hFrom = hChildStdoutRdDup;
\r
6938 cp->hTo = hChildStdinWrDup;
\r
6940 *pr = (void *) cp;
\r
6942 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
6943 2000 where engines sometimes don't see the initial command(s)
\r
6944 from WinBoard and hang. I don't understand how that can happen,
\r
6945 but the Sleep is harmless, so I've put it in. Others have also
\r
6946 reported what may be the same problem, so hopefully this will fix
\r
6947 it for them too. */
\r
6955 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
6959 cp = (ChildProc *) pr;
\r
6960 if (cp == NULL) return;
\r
6962 switch (cp->kind) {
\r
6964 /* TerminateProcess is considered harmful, so... */
\r
6965 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
6966 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
6967 /* The following doesn't work because the chess program
\r
6968 doesn't "have the same console" as WinBoard. Maybe
\r
6969 we could arrange for this even though neither WinBoard
\r
6970 nor the chess program uses a console for stdio? */
\r
6971 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
6972 CloseHandle(cp->hProcess);
\r
6976 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
6980 closesocket(cp->sock);
\r
6985 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
6986 closesocket(cp->sock);
\r
6987 closesocket(cp->sock2);
\r
6995 InterruptChildProcess(ProcRef pr)
\r
6999 cp = (ChildProc *) pr;
\r
7000 if (cp == NULL) return;
\r
7001 switch (cp->kind) {
\r
7003 /* The following doesn't work because the chess program
\r
7004 doesn't "have the same console" as WinBoard. Maybe
\r
7005 we could arrange for this even though neither WinBoard
\r
7006 nor the chess program uses a console for stdio */
\r
7007 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
7012 /* Can't interrupt */
\r
7016 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
7023 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
7025 char cmdLine[MSG_SIZ];
\r
7027 if (port[0] == NULLCHAR) {
\r
7028 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
7030 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
7032 return StartChildProcess(cmdLine, "", pr);
\r
7036 /* Code to open TCP sockets */
\r
7039 OpenTCP(char *host, char *port, ProcRef *pr)
\r
7044 struct sockaddr_in sa, mysa;
\r
7045 struct hostent FAR *hp;
\r
7046 unsigned short uport;
\r
7047 WORD wVersionRequested;
\r
7050 /* Initialize socket DLL */
\r
7051 wVersionRequested = MAKEWORD(1, 1);
\r
7052 err = WSAStartup(wVersionRequested, &wsaData);
\r
7053 if (err != 0) return err;
\r
7056 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7057 err = WSAGetLastError();
\r
7062 /* Bind local address using (mostly) don't-care values.
\r
7064 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7065 mysa.sin_family = AF_INET;
\r
7066 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7067 uport = (unsigned short) 0;
\r
7068 mysa.sin_port = htons(uport);
\r
7069 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7070 == SOCKET_ERROR) {
\r
7071 err = WSAGetLastError();
\r
7076 /* Resolve remote host name */
\r
7077 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7078 if (!(hp = gethostbyname(host))) {
\r
7079 unsigned int b0, b1, b2, b3;
\r
7081 err = WSAGetLastError();
\r
7083 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7084 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7085 hp->h_addrtype = AF_INET;
\r
7087 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7088 hp->h_addr_list[0] = (char *) malloc(4);
\r
7089 hp->h_addr_list[0][0] = (char) b0;
\r
7090 hp->h_addr_list[0][1] = (char) b1;
\r
7091 hp->h_addr_list[0][2] = (char) b2;
\r
7092 hp->h_addr_list[0][3] = (char) b3;
\r
7098 sa.sin_family = hp->h_addrtype;
\r
7099 uport = (unsigned short) atoi(port);
\r
7100 sa.sin_port = htons(uport);
\r
7101 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7103 /* Make connection */
\r
7104 if (connect(s, (struct sockaddr *) &sa,
\r
7105 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7106 err = WSAGetLastError();
\r
7111 /* Prepare return value */
\r
7112 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7113 cp->kind = CPSock;
\r
7115 *pr = (ProcRef *) cp;
\r
7121 OpenCommPort(char *name, ProcRef *pr)
\r
7126 char fullname[MSG_SIZ];
\r
7128 if (*name != '\\')
\r
7129 sprintf(fullname, "\\\\.\\%s", name);
\r
7131 strcpy(fullname, name);
\r
7133 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
7134 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
7135 if (h == (HANDLE) -1) {
\r
7136 return GetLastError();
\r
7140 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
7142 /* Accumulate characters until a 100ms pause, then parse */
\r
7143 ct.ReadIntervalTimeout = 100;
\r
7144 ct.ReadTotalTimeoutMultiplier = 0;
\r
7145 ct.ReadTotalTimeoutConstant = 0;
\r
7146 ct.WriteTotalTimeoutMultiplier = 0;
\r
7147 ct.WriteTotalTimeoutConstant = 0;
\r
7148 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
7150 /* Prepare return value */
\r
7151 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7152 cp->kind = CPComm;
\r
7155 *pr = (ProcRef *) cp;
\r
7161 OpenLoopback(ProcRef *pr)
\r
7163 DisplayFatalError("Not implemented", 0, 1);
\r
7169 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
7174 struct sockaddr_in sa, mysa;
\r
7175 struct hostent FAR *hp;
\r
7176 unsigned short uport;
\r
7177 WORD wVersionRequested;
\r
7180 char stderrPortStr[MSG_SIZ];
\r
7182 /* Initialize socket DLL */
\r
7183 wVersionRequested = MAKEWORD(1, 1);
\r
7184 err = WSAStartup(wVersionRequested, &wsaData);
\r
7185 if (err != 0) return err;
\r
7187 /* Resolve remote host name */
\r
7188 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7189 if (!(hp = gethostbyname(host))) {
\r
7190 unsigned int b0, b1, b2, b3;
\r
7192 err = WSAGetLastError();
\r
7194 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7195 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7196 hp->h_addrtype = AF_INET;
\r
7198 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7199 hp->h_addr_list[0] = (char *) malloc(4);
\r
7200 hp->h_addr_list[0][0] = (char) b0;
\r
7201 hp->h_addr_list[0][1] = (char) b1;
\r
7202 hp->h_addr_list[0][2] = (char) b2;
\r
7203 hp->h_addr_list[0][3] = (char) b3;
\r
7209 sa.sin_family = hp->h_addrtype;
\r
7210 uport = (unsigned short) 514;
\r
7211 sa.sin_port = htons(uport);
\r
7212 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7214 /* Bind local socket to unused "privileged" port address
\r
7216 s = INVALID_SOCKET;
\r
7217 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7218 mysa.sin_family = AF_INET;
\r
7219 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7220 for (fromPort = 1023;; fromPort--) {
\r
7221 if (fromPort < 0) {
\r
7223 return WSAEADDRINUSE;
\r
7225 if (s == INVALID_SOCKET) {
\r
7226 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7227 err = WSAGetLastError();
\r
7232 uport = (unsigned short) fromPort;
\r
7233 mysa.sin_port = htons(uport);
\r
7234 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7235 == SOCKET_ERROR) {
\r
7236 err = WSAGetLastError();
\r
7237 if (err == WSAEADDRINUSE) continue;
\r
7241 if (connect(s, (struct sockaddr *) &sa,
\r
7242 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7243 err = WSAGetLastError();
\r
7244 if (err == WSAEADDRINUSE) {
\r
7255 /* Bind stderr local socket to unused "privileged" port address
\r
7257 s2 = INVALID_SOCKET;
\r
7258 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7259 mysa.sin_family = AF_INET;
\r
7260 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7261 for (fromPort = 1023;; fromPort--) {
\r
7262 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
7263 if (fromPort < 0) {
\r
7264 (void) closesocket(s);
\r
7266 return WSAEADDRINUSE;
\r
7268 if (s2 == INVALID_SOCKET) {
\r
7269 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7270 err = WSAGetLastError();
\r
7276 uport = (unsigned short) fromPort;
\r
7277 mysa.sin_port = htons(uport);
\r
7278 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7279 == SOCKET_ERROR) {
\r
7280 err = WSAGetLastError();
\r
7281 if (err == WSAEADDRINUSE) continue;
\r
7282 (void) closesocket(s);
\r
7286 if (listen(s2, 1) == SOCKET_ERROR) {
\r
7287 err = WSAGetLastError();
\r
7288 if (err == WSAEADDRINUSE) {
\r
7290 s2 = INVALID_SOCKET;
\r
7293 (void) closesocket(s);
\r
7294 (void) closesocket(s2);
\r
7300 prevStderrPort = fromPort; // remember port used
\r
7301 sprintf(stderrPortStr, "%d", fromPort);
\r
7303 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
7304 err = WSAGetLastError();
\r
7305 (void) closesocket(s);
\r
7306 (void) closesocket(s2);
\r
7311 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
7312 err = WSAGetLastError();
\r
7313 (void) closesocket(s);
\r
7314 (void) closesocket(s2);
\r
7318 if (*user == NULLCHAR) user = UserName();
\r
7319 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
7320 err = WSAGetLastError();
\r
7321 (void) closesocket(s);
\r
7322 (void) closesocket(s2);
\r
7326 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
7327 err = WSAGetLastError();
\r
7328 (void) closesocket(s);
\r
7329 (void) closesocket(s2);
\r
7334 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
7335 err = WSAGetLastError();
\r
7336 (void) closesocket(s);
\r
7337 (void) closesocket(s2);
\r
7341 (void) closesocket(s2); /* Stop listening */
\r
7343 /* Prepare return value */
\r
7344 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7345 cp->kind = CPRcmd;
\r
7348 *pr = (ProcRef *) cp;
\r
7355 AddInputSource(ProcRef pr, int lineByLine,
\r
7356 InputCallback func, VOIDSTAR closure)
\r
7358 InputSource *is, *is2;
\r
7359 ChildProc *cp = (ChildProc *) pr;
\r
7361 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
7362 is->lineByLine = lineByLine;
\r
7364 is->closure = closure;
\r
7365 is->second = NULL;
\r
7366 is->next = is->buf;
\r
7367 if (pr == NoProc) {
\r
7368 is->kind = CPReal;
\r
7369 consoleInputSource = is;
\r
7371 is->kind = cp->kind;
\r
7372 switch (cp->kind) {
\r
7374 is->hFile = cp->hFrom;
\r
7375 cp->hFrom = NULL; /* now owned by InputThread */
\r
7377 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
7378 (LPVOID) is, 0, &is->id);
\r
7382 is->hFile = cp->hFrom;
\r
7383 cp->hFrom = NULL; /* now owned by InputThread */
\r
7385 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
7386 (LPVOID) is, 0, &is->id);
\r
7390 is->sock = cp->sock;
\r
7392 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7393 (LPVOID) is, 0, &is->id);
\r
7397 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
7399 is->sock = cp->sock;
\r
7401 is2->sock = cp->sock2;
\r
7402 is2->second = is2;
\r
7404 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7405 (LPVOID) is, 0, &is->id);
\r
7407 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7408 (LPVOID) is2, 0, &is2->id);
\r
7412 return (InputSourceRef) is;
\r
7416 RemoveInputSource(InputSourceRef isr)
\r
7420 is = (InputSource *) isr;
\r
7421 is->hThread = NULL; /* tell thread to stop */
\r
7422 CloseHandle(is->hThread);
\r
7423 if (is->second != NULL) {
\r
7424 is->second->hThread = NULL;
\r
7425 CloseHandle(is->second->hThread);
\r
7431 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
7434 int outCount = SOCKET_ERROR;
\r
7435 ChildProc *cp = (ChildProc *) pr;
\r
7436 static OVERLAPPED ovl;
\r
7438 if (pr == NoProc) {
\r
7439 ConsoleOutput(message, count, FALSE);
\r
7443 if (ovl.hEvent == NULL) {
\r
7444 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7446 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7448 switch (cp->kind) {
\r
7451 outCount = send(cp->sock, message, count, 0);
\r
7452 if (outCount == SOCKET_ERROR) {
\r
7453 *outError = WSAGetLastError();
\r
7455 *outError = NO_ERROR;
\r
7460 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
7461 &dOutCount, NULL)) {
\r
7462 *outError = NO_ERROR;
\r
7463 outCount = (int) dOutCount;
\r
7465 *outError = GetLastError();
\r
7470 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
7471 &dOutCount, &ovl);
\r
7472 if (*outError == NO_ERROR) {
\r
7473 outCount = (int) dOutCount;
\r
7481 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
7484 /* Ignore delay, not implemented for WinBoard */
\r
7485 return OutputToProcess(pr, message, count, outError);
\r
7490 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
7491 char *buf, int count, int error)
\r
7493 DisplayFatalError("Not implemented", 0, 1);
\r
7496 /* see wgamelist.c for Game List functions */
\r
7497 /* see wedittags.c for Edit Tags functions */
\r
7504 char buf[MSG_SIZ];
\r
7507 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
7508 f = fopen(buf, "r");
\r
7510 ProcessICSInitScript(f);
\r
7518 StartAnalysisClock()
\r
7520 if (analysisTimerEvent) return;
\r
7521 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
7522 (UINT) 2000, NULL);
\r
7526 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7528 static HANDLE hwndText;
\r
7530 static int sizeX, sizeY;
\r
7531 int newSizeX, newSizeY, flags;
\r
7534 switch (message) {
\r
7535 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7536 /* Initialize the dialog items */
\r
7537 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
7538 SetWindowText(hDlg, analysisTitle);
\r
7539 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
7540 /* Size and position the dialog */
\r
7541 if (!analysisDialog) {
\r
7542 analysisDialog = hDlg;
\r
7543 flags = SWP_NOZORDER;
\r
7544 GetClientRect(hDlg, &rect);
\r
7545 sizeX = rect.right;
\r
7546 sizeY = rect.bottom;
\r
7547 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
7548 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
7549 WINDOWPLACEMENT wp;
\r
7550 EnsureOnScreen(&analysisX, &analysisY);
\r
7551 wp.length = sizeof(WINDOWPLACEMENT);
\r
7553 wp.showCmd = SW_SHOW;
\r
7554 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7555 wp.rcNormalPosition.left = analysisX;
\r
7556 wp.rcNormalPosition.right = analysisX + analysisW;
\r
7557 wp.rcNormalPosition.top = analysisY;
\r
7558 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
7559 SetWindowPlacement(hDlg, &wp);
\r
7561 GetClientRect(hDlg, &rect);
\r
7562 newSizeX = rect.right;
\r
7563 newSizeY = rect.bottom;
\r
7564 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7565 newSizeX, newSizeY);
\r
7572 case WM_COMMAND: /* message: received a command */
\r
7573 switch (LOWORD(wParam)) {
\r
7583 newSizeX = LOWORD(lParam);
\r
7584 newSizeY = HIWORD(lParam);
\r
7585 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7590 case WM_GETMINMAXINFO:
\r
7591 /* Prevent resizing window too small */
\r
7592 mmi = (MINMAXINFO *) lParam;
\r
7593 mmi->ptMinTrackSize.x = 100;
\r
7594 mmi->ptMinTrackSize.y = 100;
\r
7601 AnalysisPopUp(char* title, char* str)
\r
7606 if (str == NULL) str = "";
\r
7607 p = (char *) malloc(2 * strlen(str) + 2);
\r
7610 if (*str == '\n') *q++ = '\r';
\r
7614 if (analysisText != NULL) free(analysisText);
\r
7617 if (analysisDialog) {
\r
7618 SetWindowText(analysisDialog, title);
\r
7619 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
7620 ShowWindow(analysisDialog, SW_SHOW);
\r
7622 analysisTitle = title;
\r
7623 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
7624 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
7625 hwndMain, (DLGPROC)lpProc);
\r
7626 FreeProcInstance(lpProc);
\r
7628 analysisDialogUp = TRUE;
\r
7634 if (analysisDialog) {
\r
7635 ShowWindow(analysisDialog, SW_HIDE);
\r
7637 analysisDialogUp = FALSE;
\r
7642 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
7644 highlightInfo.sq[0].x = fromX;
\r
7645 highlightInfo.sq[0].y = fromY;
\r
7646 highlightInfo.sq[1].x = toX;
\r
7647 highlightInfo.sq[1].y = toY;
\r
7653 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
7654 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
7658 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
7660 premoveHighlightInfo.sq[0].x = fromX;
\r
7661 premoveHighlightInfo.sq[0].y = fromY;
\r
7662 premoveHighlightInfo.sq[1].x = toX;
\r
7663 premoveHighlightInfo.sq[1].y = toY;
\r
7667 ClearPremoveHighlights()
\r
7669 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
7670 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
7674 ShutDownFrontEnd()
\r
7676 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
7677 DeleteClipboardTempFiles();
\r
7683 if (IsIconic(hwndMain))
\r
7684 ShowWindow(hwndMain, SW_RESTORE);
\r
7686 SetActiveWindow(hwndMain);
\r
7690 * Prototypes for animation support routines
\r
7692 static void ScreenSquare(int column, int row, POINT * pt);
\r
7693 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
7694 POINT frames[], int * nFrames);
\r
7700 AnimateMove(board, fromX, fromY, toX, toY)
\r
7707 ChessSquare piece;
\r
7708 POINT start, finish, mid;
\r
7709 POINT frames[kFactor * 2 + 1];
\r
7712 if (!appData.animate) return;
\r
7713 if (doingSizing) return;
\r
7714 if (fromY < 0 || fromX < 0) return;
\r
7715 piece = board[fromY][fromX];
\r
7716 if (piece >= EmptySquare) return;
\r
7718 ScreenSquare(fromX, fromY, &start);
\r
7719 ScreenSquare(toX, toY, &finish);
\r
7721 /* All pieces except knights move in straight line */
\r
7722 if (piece != WhiteKnight && piece != BlackKnight) {
\r
7723 mid.x = start.x + (finish.x - start.x) / 2;
\r
7724 mid.y = start.y + (finish.y - start.y) / 2;
\r
7726 /* Knight: make diagonal movement then straight */
\r
7727 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
7728 mid.x = start.x + (finish.x - start.x) / 2;
\r
7732 mid.y = start.y + (finish.y - start.y) / 2;
\r
7736 /* Don't use as many frames for very short moves */
\r
7737 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
7738 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
7740 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
7742 animInfo.from.x = fromX;
\r
7743 animInfo.from.y = fromY;
\r
7744 animInfo.to.x = toX;
\r
7745 animInfo.to.y = toY;
\r
7746 animInfo.lastpos = start;
\r
7747 animInfo.piece = piece;
\r
7748 for (n = 0; n < nFrames; n++) {
\r
7749 animInfo.pos = frames[n];
\r
7750 DrawPosition(FALSE, NULL);
\r
7751 animInfo.lastpos = animInfo.pos;
\r
7752 Sleep(appData.animSpeed);
\r
7754 animInfo.pos = finish;
\r
7755 DrawPosition(FALSE, NULL);
\r
7756 animInfo.piece = EmptySquare;
\r
7759 /* Convert board position to corner of screen rect and color */
\r
7762 ScreenSquare(column, row, pt)
\r
7763 int column; int row; POINT * pt;
\r
7766 pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
7767 pt->y = lineGap + row * (squareSize + lineGap);
\r
7769 pt->x = lineGap + column * (squareSize + lineGap);
\r
7770 pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
7774 /* Generate a series of frame coords from start->mid->finish.
\r
7775 The movement rate doubles until the half way point is
\r
7776 reached, then halves back down to the final destination,
\r
7777 which gives a nice slow in/out effect. The algorithmn
\r
7778 may seem to generate too many intermediates for short
\r
7779 moves, but remember that the purpose is to attract the
\r
7780 viewers attention to the piece about to be moved and
\r
7781 then to where it ends up. Too few frames would be less
\r
7785 Tween(start, mid, finish, factor, frames, nFrames)
\r
7786 POINT * start; POINT * mid;
\r
7787 POINT * finish; int factor;
\r
7788 POINT frames[]; int * nFrames;
\r
7790 int n, fraction = 1, count = 0;
\r
7792 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
7793 for (n = 0; n < factor; n++)
\r
7795 for (n = 0; n < factor; n++) {
\r
7796 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
7797 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
7799 fraction = fraction / 2;
\r
7803 frames[count] = *mid;
\r
7806 /* Slow out, stepping 1/2, then 1/4, ... */
\r
7808 for (n = 0; n < factor; n++) {
\r
7809 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
7810 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
7812 fraction = fraction * 2;
\r
7818 HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current)
\r
7820 /* Currently not implemented in WinBoard */
\r