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
599 /* Make the window visible; update its client area; and return "success" */
\r
600 EnsureOnScreen(&boardX, &boardY);
\r
601 wp.length = sizeof(WINDOWPLACEMENT);
\r
603 wp.showCmd = nCmdShow;
\r
604 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
605 wp.rcNormalPosition.left = boardX;
\r
606 wp.rcNormalPosition.right = boardX + winWidth;
\r
607 wp.rcNormalPosition.top = boardY;
\r
608 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
609 SetWindowPlacement(hwndMain, &wp);
\r
611 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
612 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
615 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
616 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
618 ShowWindow(hwndConsole, nCmdShow);
\r
620 UpdateWindow(hwnd);
\r
628 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
629 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
630 ArgSettingsFilename
\r
638 String *pString; // ArgString
\r
639 int *pInt; // ArgInt
\r
640 float *pFloat; // ArgFloat
\r
641 Boolean *pBoolean; // ArgBoolean
\r
642 COLORREF *pColor; // ArgColor
\r
643 ColorClass cc; // ArgAttribs
\r
644 String *pFilename; // ArgFilename
\r
645 BoardSize *pBoardSize; // ArgBoardSize
\r
646 int whichFont; // ArgFont
\r
647 DCB *pDCB; // ArgCommSettings
\r
648 String *pFilename; // ArgSettingsFilename
\r
656 ArgDescriptor argDescriptors[] = {
\r
657 /* positional arguments */
\r
658 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
659 { "", ArgNone, NULL },
\r
660 /* keyword arguments */
\r
661 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
662 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
663 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
664 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
665 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
666 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
667 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
668 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
669 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
670 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
671 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
672 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
673 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
674 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
675 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
676 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
677 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
678 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
680 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
682 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
684 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
685 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
687 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
688 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
689 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
690 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
691 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
692 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
693 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
694 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
695 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
696 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
697 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
698 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
699 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
700 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
701 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
702 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
703 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
704 /*!!bitmapDirectory?*/
\r
705 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
706 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
707 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
708 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
709 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
710 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
711 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
712 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
713 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
714 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
715 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
716 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
717 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
718 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
719 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
720 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
721 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
722 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
723 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
724 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
725 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
726 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
727 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
728 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
729 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
730 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
731 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
732 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
733 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
734 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
735 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
736 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
737 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
738 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
739 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
740 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
741 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
742 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
743 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
744 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
745 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
746 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
747 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
748 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
749 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
750 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
751 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
752 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
753 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
754 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
755 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
756 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
757 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
758 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
759 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
760 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
761 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
762 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
763 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
764 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
765 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
766 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
767 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
768 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
769 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
770 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
771 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
772 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
773 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
774 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
775 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
776 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
777 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
778 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
779 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
780 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
781 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
782 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
783 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
784 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
785 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
786 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
787 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
788 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
789 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
790 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
791 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
792 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
793 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
794 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
795 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
796 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
797 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
798 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
799 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
800 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
801 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
802 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
803 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
804 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
805 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
806 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
807 TRUE }, /* must come after all fonts */
\r
808 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
809 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
810 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
811 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
812 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
813 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
814 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
815 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
816 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
817 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
818 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
819 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
820 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
821 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
822 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
823 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
824 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
825 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
826 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
827 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
828 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
829 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
830 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
831 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
832 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
833 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
834 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
835 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
836 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
837 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
838 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
840 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
841 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
843 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
844 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
845 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
846 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
847 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
848 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
849 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
850 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
851 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
852 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
853 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
854 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
855 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
856 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
857 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
858 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
859 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
860 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
861 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
862 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
863 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
864 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
865 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
866 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
867 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
868 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
869 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
870 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
871 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
872 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
873 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
874 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
875 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
876 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
877 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
878 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
879 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
880 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
881 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
882 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
883 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
884 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
885 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
886 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
887 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
888 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
889 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
890 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
891 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
892 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
893 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
894 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
895 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
896 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
897 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
898 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
899 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
900 { "highlightLastMove", ArgBoolean,
\r
901 (LPVOID) &appData.highlightLastMove, TRUE },
\r
902 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
903 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
904 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
905 { "highlightDragging", ArgBoolean,
\r
906 (LPVOID) &appData.highlightDragging, TRUE },
\r
907 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
908 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
909 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
910 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
911 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
912 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
913 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
914 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
915 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
916 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
917 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
918 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
919 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
920 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
921 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
922 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
923 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
924 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
925 { "soundShout", ArgFilename,
\r
926 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
927 { "soundSShout", ArgFilename,
\r
928 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
929 { "soundChannel1", ArgFilename,
\r
930 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
931 { "soundChannel", ArgFilename,
\r
932 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
933 { "soundKibitz", ArgFilename,
\r
934 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
935 { "soundTell", ArgFilename,
\r
936 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
937 { "soundChallenge", ArgFilename,
\r
938 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
939 { "soundRequest", ArgFilename,
\r
940 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
941 { "soundSeek", ArgFilename,
\r
942 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
943 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
944 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
945 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
946 { "soundIcsLoss", ArgFilename,
\r
947 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
948 { "soundIcsDraw", ArgFilename,
\r
949 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
950 { "soundIcsUnfinished", ArgFilename,
\r
951 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
952 { "soundIcsAlarm", ArgFilename,
\r
953 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
954 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
955 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
956 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
957 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
958 { "reuseChessPrograms", ArgBoolean,
\r
959 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
960 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
961 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
962 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
963 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
964 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
965 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
966 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
967 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
968 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
969 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
970 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
971 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
972 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
973 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
974 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
975 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
976 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
977 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
978 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
979 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
980 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
981 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
982 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
983 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
984 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
985 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
986 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
987 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
988 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
989 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
990 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
991 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
992 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
993 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
994 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
995 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
996 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
998 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1000 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1001 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1002 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1003 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion,
\r
1005 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,
\r
1007 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1008 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1009 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1010 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1012 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1013 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1014 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1015 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1016 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1017 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1018 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1019 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1020 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1021 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1022 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1023 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1024 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1026 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1027 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1028 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1029 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1030 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1031 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1032 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1034 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1035 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1036 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1037 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1038 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1039 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1040 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1041 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1042 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1043 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1044 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1045 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1046 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1047 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1048 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1049 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1050 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1051 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1053 { NULL, ArgNone, NULL, FALSE }
\r
1057 /* Kludge for indirection files on command line */
\r
1058 char* lastIndirectionFilename;
\r
1059 ArgDescriptor argDescriptorIndirection =
\r
1060 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1064 ExitArgError(char *msg, char *badArg)
\r
1066 char buf[MSG_SIZ];
\r
1068 sprintf(buf, "%s %s", msg, badArg);
\r
1069 DisplayFatalError(buf, 0, 2);
\r
1073 /* Command line font name parser. NULL name means do nothing.
\r
1074 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1075 For backward compatibility, syntax without the colon is also
\r
1076 accepted, but font names with digits in them won't work in that case.
\r
1079 ParseFontName(char *name, MyFontParams *mfp)
\r
1082 if (name == NULL) return;
\r
1084 q = strchr(p, ':');
\r
1086 if (q - p >= sizeof(mfp->faceName))
\r
1087 ExitArgError("Font name too long:", name);
\r
1088 memcpy(mfp->faceName, p, q - p);
\r
1089 mfp->faceName[q - p] = NULLCHAR;
\r
1092 q = mfp->faceName;
\r
1093 while (*p && !isdigit(*p)) {
\r
1095 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1096 ExitArgError("Font name too long:", name);
\r
1098 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1101 if (!*p) ExitArgError("Font point size missing:", name);
\r
1102 mfp->pointSize = (float) atof(p);
\r
1103 mfp->bold = (strchr(p, 'b') != NULL);
\r
1104 mfp->italic = (strchr(p, 'i') != NULL);
\r
1105 mfp->underline = (strchr(p, 'u') != NULL);
\r
1106 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1109 /* Color name parser.
\r
1110 X version accepts X color names, but this one
\r
1111 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1113 ParseColorName(char *name)
\r
1115 int red, green, blue, count;
\r
1116 char buf[MSG_SIZ];
\r
1118 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1120 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1121 &red, &green, &blue);
\r
1124 sprintf(buf, "Can't parse color name %s", name);
\r
1125 DisplayError(buf, 0);
\r
1126 return RGB(0, 0, 0);
\r
1128 return PALETTERGB(red, green, blue);
\r
1132 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1134 char *e = argValue;
\r
1138 if (*e == 'b') eff |= CFE_BOLD;
\r
1139 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1140 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1141 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1142 else if (*e == '#' || isdigit(*e)) break;
\r
1146 *color = ParseColorName(e);
\r
1151 ParseBoardSize(char *name)
\r
1153 BoardSize bs = SizeTiny;
\r
1154 while (sizeInfo[bs].name != NULL) {
\r
1155 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1158 ExitArgError("Unrecognized board size value", name);
\r
1159 return bs; /* not reached */
\r
1164 StringGet(void *getClosure)
\r
1166 char **p = (char **) getClosure;
\r
1171 FileGet(void *getClosure)
\r
1174 FILE* f = (FILE*) getClosure;
\r
1183 /* Parse settings file named "name". If file found, return the
\r
1184 full name in fullname and return TRUE; else return FALSE */
\r
1186 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1191 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1192 f = fopen(fullname, "r");
\r
1194 ParseArgs(FileGet, f);
\r
1203 ParseArgs(GetFunc get, void *cl)
\r
1205 char argName[ARG_MAX];
\r
1206 char argValue[ARG_MAX];
\r
1207 ArgDescriptor *ad;
\r
1216 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1217 if (ch == NULLCHAR) break;
\r
1219 /* Comment to end of line */
\r
1221 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1223 } else if (ch == '/' || ch == '-') {
\r
1226 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1227 ch != '\n' && ch != '\t') {
\r
1233 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1234 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1236 if (ad->argName == NULL)
\r
1237 ExitArgError("Unrecognized argument", argName);
\r
1239 } else if (ch == '@') {
\r
1240 /* Indirection file */
\r
1241 ad = &argDescriptorIndirection;
\r
1244 /* Positional argument */
\r
1245 ad = &argDescriptors[posarg++];
\r
1246 strcpy(argName, ad->argName);
\r
1249 if (ad->argType == ArgTrue) {
\r
1250 *(Boolean *) ad->argLoc = TRUE;
\r
1253 if (ad->argType == ArgFalse) {
\r
1254 *(Boolean *) ad->argLoc = FALSE;
\r
1258 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1259 if (ch == NULLCHAR || ch == '\n') {
\r
1260 ExitArgError("No value provided for argument", argName);
\r
1264 // Quoting with { }. No characters have to (or can) be escaped.
\r
1265 // Thus the string cannot contain a '}' character.
\r
1285 } else if (ch == '\'' || ch == '"') {
\r
1286 // Quoting with ' ' or " ", with \ as escape character.
\r
1287 // Inconvenient for long strings that may contain Windows filenames.
\r
1304 if (ch == start) {
\r
1313 if (ad->argType == ArgFilename
\r
1314 || ad->argType == ArgSettingsFilename) {
\r
1320 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1344 for (i = 0; i < 3; i++) {
\r
1345 if (ch >= '0' && ch <= '7') {
\r
1346 octval = octval*8 + (ch - '0');
\r
1353 *q++ = (char) octval;
\r
1364 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1371 switch (ad->argType) {
\r
1373 *(int *) ad->argLoc = atoi(argValue);
\r
1377 *(float *) ad->argLoc = (float) atof(argValue);
\r
1382 *(char **) ad->argLoc = strdup(argValue);
\r
1385 case ArgSettingsFilename:
\r
1387 char fullname[MSG_SIZ];
\r
1388 if (ParseSettingsFile(argValue, fullname)) {
\r
1389 if (ad->argLoc != NULL) {
\r
1390 *(char **) ad->argLoc = strdup(fullname);
\r
1393 if (ad->argLoc != NULL) {
\r
1395 ExitArgError("Failed to open indirection file", argValue);
\r
1402 switch (argValue[0]) {
\r
1405 *(Boolean *) ad->argLoc = TRUE;
\r
1409 *(Boolean *) ad->argLoc = FALSE;
\r
1412 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1418 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1421 case ArgAttribs: {
\r
1422 ColorClass cc = (ColorClass)ad->argLoc;
\r
1423 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1427 case ArgBoardSize:
\r
1428 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1432 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1435 case ArgCommSettings:
\r
1436 ParseCommSettings(argValue, &dcb);
\r
1440 ExitArgError("Unrecognized argument", argValue);
\r
1447 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1449 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1450 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1453 lf->lfEscapement = 0;
\r
1454 lf->lfOrientation = 0;
\r
1455 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1456 lf->lfItalic = mfp->italic;
\r
1457 lf->lfUnderline = mfp->underline;
\r
1458 lf->lfStrikeOut = mfp->strikeout;
\r
1459 lf->lfCharSet = DEFAULT_CHARSET;
\r
1460 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1461 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1462 lf->lfQuality = DEFAULT_QUALITY;
\r
1463 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1464 strcpy(lf->lfFaceName, mfp->faceName);
\r
1468 CreateFontInMF(MyFont *mf)
\r
1470 LFfromMFP(&mf->lf, &mf->mfp);
\r
1471 if (mf->hf) DeleteObject(mf->hf);
\r
1472 mf->hf = CreateFontIndirect(&mf->lf);
\r
1476 SetDefaultTextAttribs()
\r
1479 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1480 ParseAttribs(&textAttribs[cc].color,
\r
1481 &textAttribs[cc].effects,
\r
1482 defaultTextAttribs[cc]);
\r
1487 SetDefaultSounds()
\r
1491 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1492 textAttribs[cc].sound.name = strdup("");
\r
1493 textAttribs[cc].sound.data = NULL;
\r
1495 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1496 sounds[sc].name = strdup("");
\r
1497 sounds[sc].data = NULL;
\r
1499 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1507 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1508 MyLoadSound(&textAttribs[cc].sound);
\r
1510 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1511 MyLoadSound(&sounds[sc]);
\r
1516 InitAppData(LPSTR lpCmdLine)
\r
1519 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1522 programName = szAppName;
\r
1524 /* Initialize to defaults */
\r
1525 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1526 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1527 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1528 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1529 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1530 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1531 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1532 SetDefaultTextAttribs();
\r
1533 SetDefaultSounds();
\r
1534 appData.movesPerSession = MOVES_PER_SESSION;
\r
1535 appData.initString = INIT_STRING;
\r
1536 appData.secondInitString = INIT_STRING;
\r
1537 appData.firstComputerString = COMPUTER_STRING;
\r
1538 appData.secondComputerString = COMPUTER_STRING;
\r
1539 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1540 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1541 appData.firstPlaysBlack = FALSE;
\r
1542 appData.noChessProgram = FALSE;
\r
1543 chessProgram = FALSE;
\r
1544 appData.firstHost = FIRST_HOST;
\r
1545 appData.secondHost = SECOND_HOST;
\r
1546 appData.firstDirectory = FIRST_DIRECTORY;
\r
1547 appData.secondDirectory = SECOND_DIRECTORY;
\r
1548 appData.bitmapDirectory = "";
\r
1549 appData.remoteShell = REMOTE_SHELL;
\r
1550 appData.remoteUser = "";
\r
1551 appData.timeDelay = TIME_DELAY;
\r
1552 appData.timeControl = TIME_CONTROL;
\r
1553 appData.timeIncrement = TIME_INCREMENT;
\r
1554 appData.icsActive = FALSE;
\r
1555 appData.icsHost = "";
\r
1556 appData.icsPort = ICS_PORT;
\r
1557 appData.icsCommPort = ICS_COMM_PORT;
\r
1558 appData.icsLogon = ICS_LOGON;
\r
1559 appData.icsHelper = "";
\r
1560 appData.useTelnet = FALSE;
\r
1561 appData.telnetProgram = TELNET_PROGRAM;
\r
1562 appData.gateway = "";
\r
1563 appData.loadGameFile = "";
\r
1564 appData.loadGameIndex = 0;
\r
1565 appData.saveGameFile = "";
\r
1566 appData.autoSaveGames = FALSE;
\r
1567 appData.loadPositionFile = "";
\r
1568 appData.loadPositionIndex = 1;
\r
1569 appData.savePositionFile = "";
\r
1570 appData.matchMode = FALSE;
\r
1571 appData.matchGames = 0;
\r
1572 appData.monoMode = FALSE;
\r
1573 appData.debugMode = FALSE;
\r
1574 appData.clockMode = TRUE;
\r
1575 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1576 appData.Iconic = FALSE; /*unused*/
\r
1577 appData.searchTime = "";
\r
1578 appData.searchDepth = 0;
\r
1579 appData.showCoords = FALSE;
\r
1580 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1581 appData.autoCallFlag = FALSE;
\r
1582 appData.flipView = FALSE;
\r
1583 appData.autoFlipView = TRUE;
\r
1584 appData.cmailGameName = "";
\r
1585 appData.alwaysPromoteToQueen = FALSE;
\r
1586 appData.oldSaveStyle = FALSE;
\r
1587 appData.quietPlay = FALSE;
\r
1588 appData.showThinking = FALSE;
\r
1589 appData.ponderNextMove = TRUE;
\r
1590 appData.periodicUpdates = TRUE;
\r
1591 appData.popupExitMessage = TRUE;
\r
1592 appData.popupMoveErrors = FALSE;
\r
1593 appData.autoObserve = FALSE;
\r
1594 appData.autoComment = FALSE;
\r
1595 appData.animate = TRUE;
\r
1596 appData.animSpeed = 10;
\r
1597 appData.animateDragging = TRUE;
\r
1598 appData.highlightLastMove = TRUE;
\r
1599 appData.getMoveList = TRUE;
\r
1600 appData.testLegality = TRUE;
\r
1601 appData.premove = TRUE;
\r
1602 appData.premoveWhite = FALSE;
\r
1603 appData.premoveWhiteText = "";
\r
1604 appData.premoveBlack = FALSE;
\r
1605 appData.premoveBlackText = "";
\r
1606 appData.icsAlarm = TRUE;
\r
1607 appData.icsAlarmTime = 5000;
\r
1608 appData.autoRaiseBoard = TRUE;
\r
1609 appData.localLineEditing = TRUE;
\r
1610 appData.colorize = TRUE;
\r
1611 appData.reuseFirst = TRUE;
\r
1612 appData.reuseSecond = TRUE;
\r
1613 appData.blindfold = FALSE;
\r
1614 dcb.DCBlength = sizeof(DCB);
\r
1615 dcb.BaudRate = 9600;
\r
1616 dcb.fBinary = TRUE;
\r
1617 dcb.fParity = FALSE;
\r
1618 dcb.fOutxCtsFlow = FALSE;
\r
1619 dcb.fOutxDsrFlow = FALSE;
\r
1620 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1621 dcb.fDsrSensitivity = FALSE;
\r
1622 dcb.fTXContinueOnXoff = TRUE;
\r
1623 dcb.fOutX = FALSE;
\r
1625 dcb.fNull = FALSE;
\r
1626 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1627 dcb.fAbortOnError = FALSE;
\r
1628 dcb.wReserved = 0;
\r
1630 dcb.Parity = SPACEPARITY;
\r
1631 dcb.StopBits = ONESTOPBIT;
\r
1632 settingsFileName = SETTINGS_FILE;
\r
1633 saveSettingsOnExit = TRUE;
\r
1634 boardX = CW_USEDEFAULT;
\r
1635 boardY = CW_USEDEFAULT;
\r
1636 consoleX = CW_USEDEFAULT;
\r
1637 consoleY = CW_USEDEFAULT;
\r
1638 consoleW = CW_USEDEFAULT;
\r
1639 consoleH = CW_USEDEFAULT;
\r
1640 analysisX = CW_USEDEFAULT;
\r
1641 analysisY = CW_USEDEFAULT;
\r
1642 analysisW = CW_USEDEFAULT;
\r
1643 analysisH = CW_USEDEFAULT;
\r
1644 commentX = CW_USEDEFAULT;
\r
1645 commentY = CW_USEDEFAULT;
\r
1646 commentW = CW_USEDEFAULT;
\r
1647 commentH = CW_USEDEFAULT;
\r
1648 editTagsX = CW_USEDEFAULT;
\r
1649 editTagsY = CW_USEDEFAULT;
\r
1650 editTagsW = CW_USEDEFAULT;
\r
1651 editTagsH = CW_USEDEFAULT;
\r
1652 gameListX = CW_USEDEFAULT;
\r
1653 gameListY = CW_USEDEFAULT;
\r
1654 gameListW = CW_USEDEFAULT;
\r
1655 gameListH = CW_USEDEFAULT;
\r
1656 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1657 icsNames = ICS_NAMES;
\r
1658 firstChessProgramNames = FCP_NAMES;
\r
1659 secondChessProgramNames = SCP_NAMES;
\r
1660 appData.initialMode = "";
\r
1661 appData.variant = "normal";
\r
1662 appData.firstProtocolVersion = PROTOVER;
\r
1663 appData.secondProtocolVersion = PROTOVER;
\r
1664 appData.showButtonBar = TRUE;
\r
1666 appData.zippyTalk = ZIPPY_TALK;
\r
1667 appData.zippyPlay = ZIPPY_PLAY;
\r
1668 appData.zippyLines = ZIPPY_LINES;
\r
1669 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1670 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1671 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1672 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1673 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1674 appData.zippyUseI = ZIPPY_USE_I;
\r
1675 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1676 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1677 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1678 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1679 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1680 appData.zippyAbort = ZIPPY_ABORT;
\r
1681 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1682 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1683 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1686 /* Point font array elements to structures and
\r
1687 parse default font names */
\r
1688 for (i=0; i<NUM_FONTS; i++) {
\r
1689 for (j=0; j<NUM_SIZES; j++) {
\r
1690 font[j][i] = &fontRec[j][i];
\r
1691 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1695 /* Parse default settings file if any */
\r
1696 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1697 settingsFileName = strdup(buf);
\r
1700 /* Parse command line */
\r
1701 ParseArgs(StringGet, &lpCmdLine);
\r
1703 /* Propagate options that affect others */
\r
1704 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1705 if (appData.icsActive || appData.noChessProgram) {
\r
1706 chessProgram = FALSE; /* not local chess program mode */
\r
1709 /* Open startup dialog if needed */
\r
1710 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1711 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1712 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1713 *appData.secondChessProgram == NULLCHAR))) {
\r
1716 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1717 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1718 FreeProcInstance(lpProc);
\r
1721 /* Make sure save files land in the right (?) directory */
\r
1722 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1723 appData.saveGameFile = strdup(buf);
\r
1725 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1726 appData.savePositionFile = strdup(buf);
\r
1729 /* Finish initialization for fonts and sounds */
\r
1730 for (i=0; i<NUM_FONTS; i++) {
\r
1731 for (j=0; j<NUM_SIZES; j++) {
\r
1732 CreateFontInMF(font[j][i]);
\r
1735 /* xboard, and older WinBoards, controlled the move sound with the
\r
1736 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1737 always turn the option on (so that the backend will call us),
\r
1738 then let the user turn the sound off by setting it to silence if
\r
1739 desired. To accommodate old winboard.ini files saved by old
\r
1740 versions of WinBoard, we also turn off the sound if the option
\r
1741 was initially set to false. */
\r
1742 if (!appData.ringBellAfterMoves) {
\r
1743 sounds[(int)SoundMove].name = strdup("");
\r
1744 appData.ringBellAfterMoves = TRUE;
\r
1746 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1747 SetCurrentDirectory(installDir);
\r
1749 SetCurrentDirectory(currDir);
\r
1751 p = icsTextMenuString;
\r
1752 if (p[0] == '@') {
\r
1753 FILE* f = fopen(p + 1, "r");
\r
1755 DisplayFatalError(p + 1, errno, 2);
\r
1758 i = fread(buf, 1, sizeof(buf)-1, f);
\r
1760 buf[i] = NULLCHAR;
\r
1763 ParseIcsTextMenu(strdup(p));
\r
1770 HMENU hmenu = GetMenu(hwndMain);
\r
1772 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1773 MF_BYCOMMAND|((appData.icsActive &&
\r
1774 *appData.icsCommPort != NULLCHAR) ?
\r
1775 MF_ENABLED : MF_GRAYED));
\r
1776 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1777 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1778 MF_CHECKED : MF_UNCHECKED));
\r
1783 SaveSettings(char* name)
\r
1786 ArgDescriptor *ad;
\r
1787 WINDOWPLACEMENT wp;
\r
1788 char dir[MSG_SIZ];
\r
1790 if (!hwndMain) return;
\r
1792 GetCurrentDirectory(MSG_SIZ, dir);
\r
1793 SetCurrentDirectory(installDir);
\r
1794 f = fopen(name, "w");
\r
1795 SetCurrentDirectory(dir);
\r
1797 DisplayError(name, errno);
\r
1800 fprintf(f, ";\n");
\r
1801 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
1802 fprintf(f, ";\n");
\r
1803 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
1804 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
1805 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
1806 fprintf(f, ";\n");
\r
1808 wp.length = sizeof(WINDOWPLACEMENT);
\r
1809 GetWindowPlacement(hwndMain, &wp);
\r
1810 boardX = wp.rcNormalPosition.left;
\r
1811 boardY = wp.rcNormalPosition.top;
\r
1813 if (hwndConsole) {
\r
1814 GetWindowPlacement(hwndConsole, &wp);
\r
1815 consoleX = wp.rcNormalPosition.left;
\r
1816 consoleY = wp.rcNormalPosition.top;
\r
1817 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1818 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1821 if (analysisDialog) {
\r
1822 GetWindowPlacement(analysisDialog, &wp);
\r
1823 analysisX = wp.rcNormalPosition.left;
\r
1824 analysisY = wp.rcNormalPosition.top;
\r
1825 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1826 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1829 if (commentDialog) {
\r
1830 GetWindowPlacement(commentDialog, &wp);
\r
1831 commentX = wp.rcNormalPosition.left;
\r
1832 commentY = wp.rcNormalPosition.top;
\r
1833 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1834 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1837 if (editTagsDialog) {
\r
1838 GetWindowPlacement(editTagsDialog, &wp);
\r
1839 editTagsX = wp.rcNormalPosition.left;
\r
1840 editTagsY = wp.rcNormalPosition.top;
\r
1841 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1842 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1845 if (gameListDialog) {
\r
1846 GetWindowPlacement(gameListDialog, &wp);
\r
1847 gameListX = wp.rcNormalPosition.left;
\r
1848 gameListY = wp.rcNormalPosition.top;
\r
1849 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1850 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1853 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
1854 if (!ad->save) continue;
\r
1855 switch (ad->argType) {
\r
1858 char *p = *(char **)ad->argLoc;
\r
1859 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
1860 /* Quote multiline values or \-containing values
\r
1861 with { } if possible */
\r
1862 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
1864 /* Else quote with " " */
\r
1865 fprintf(f, "/%s=\"", ad->argName);
\r
1867 if (*p == '\n') fprintf(f, "\n");
\r
1868 else if (*p == '\r') fprintf(f, "\\r");
\r
1869 else if (*p == '\t') fprintf(f, "\\t");
\r
1870 else if (*p == '\b') fprintf(f, "\\b");
\r
1871 else if (*p == '\f') fprintf(f, "\\f");
\r
1872 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
1873 else if (*p == '\"') fprintf(f, "\\\"");
\r
1874 else if (*p == '\\') fprintf(f, "\\\\");
\r
1878 fprintf(f, "\"\n");
\r
1883 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
1886 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
1889 fprintf(f, "/%s=%s\n", ad->argName,
\r
1890 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
1893 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1896 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1900 COLORREF color = *(COLORREF *)ad->argLoc;
\r
1901 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
1902 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1907 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1908 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
1909 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1910 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1911 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1912 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1913 (ta->effects) ? " " : "",
\r
1914 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1918 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
1919 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
1921 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
1924 case ArgBoardSize:
\r
1925 fprintf(f, "/%s=%s\n", ad->argName,
\r
1926 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
1931 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1932 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1933 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1934 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
1935 ad->argName, mfp->faceName, mfp->pointSize,
\r
1936 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1937 mfp->bold ? "b" : "",
\r
1938 mfp->italic ? "i" : "",
\r
1939 mfp->underline ? "u" : "",
\r
1940 mfp->strikeout ? "s" : "");
\r
1944 case ArgCommSettings:
\r
1945 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
1953 /*---------------------------------------------------------------------------*\
\r
1955 * GDI board drawing routines
\r
1957 \*---------------------------------------------------------------------------*/
\r
1960 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
1964 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
1965 if (gameInfo.event &&
\r
1966 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
1967 strcmp(name, "k80s") == 0) {
\r
1968 strcpy(name, "tim");
\r
1970 return LoadBitmap(hinst, name);
\r
1974 /* Insert a color into the program's logical palette
\r
1975 structure. This code assumes the given color is
\r
1976 the result of the RGB or PALETTERGB macro, and it
\r
1977 knows how those macros work (which is documented).
\r
1980 InsertInPalette(COLORREF color)
\r
1982 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
1984 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
1985 DisplayFatalError("Too many colors", 0, 1);
\r
1986 pLogPal->palNumEntries--;
\r
1990 pe->peFlags = (char) 0;
\r
1991 pe->peRed = (char) (0xFF & color);
\r
1992 pe->peGreen = (char) (0xFF & (color >> 8));
\r
1993 pe->peBlue = (char) (0xFF & (color >> 16));
\r
1999 InitDrawingColors()
\r
2001 if (pLogPal == NULL) {
\r
2002 /* Allocate enough memory for a logical palette with
\r
2003 * PALETTESIZE entries and set the size and version fields
\r
2004 * of the logical palette structure.
\r
2006 pLogPal = (NPLOGPALETTE)
\r
2007 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2008 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2009 pLogPal->palVersion = 0x300;
\r
2011 pLogPal->palNumEntries = 0;
\r
2013 InsertInPalette(lightSquareColor);
\r
2014 InsertInPalette(darkSquareColor);
\r
2015 InsertInPalette(whitePieceColor);
\r
2016 InsertInPalette(blackPieceColor);
\r
2017 InsertInPalette(highlightSquareColor);
\r
2018 InsertInPalette(premoveHighlightColor);
\r
2020 /* create a logical color palette according the information
\r
2021 * in the LOGPALETTE structure.
\r
2023 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2025 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2026 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2027 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2028 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2029 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2034 BoardWidth(int boardSize)
\r
2036 return (BOARD_SIZE + 1) * sizeInfo[boardSize].lineGap +
\r
2037 BOARD_SIZE * sizeInfo[boardSize].squareSize;
\r
2040 /* Respond to board resize by dragging edge */
\r
2042 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2044 BoardSize newSize = NUM_SIZES - 1;
\r
2045 static int recurse = 0;
\r
2046 if (IsIconic(hwndMain)) return;
\r
2047 if (recurse > 0) return;
\r
2049 while (newSize > 0 &&
\r
2050 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2051 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2054 boardSize = newSize;
\r
2055 InitDrawingSizes(boardSize, flags);
\r
2062 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2064 int i, boardWidth;
\r
2065 ChessSquare piece;
\r
2066 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2068 SIZE clockSize, messageSize;
\r
2070 char buf[MSG_SIZ];
\r
2072 HMENU hmenu = GetMenu(hwndMain);
\r
2073 RECT crect, wrect;
\r
2075 LOGBRUSH logbrush;
\r
2077 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2078 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2079 squareSize = sizeInfo[boardSize].squareSize;
\r
2080 lineGap = sizeInfo[boardSize].lineGap;
\r
2082 if (tinyLayout != oldTinyLayout) {
\r
2083 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2085 style &= ~WS_SYSMENU;
\r
2086 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2087 "&Minimize\tCtrl+F4");
\r
2089 style |= WS_SYSMENU;
\r
2090 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2092 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2094 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2095 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2096 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2098 DrawMenuBar(hwndMain);
\r
2101 boardWidth = BoardWidth(boardSize);
\r
2103 /* Get text area sizes */
\r
2104 hdc = GetDC(hwndMain);
\r
2105 if (appData.clockMode) {
\r
2106 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2108 sprintf(buf, "White");
\r
2110 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2111 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2112 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2113 str = "We only care about the height here";
\r
2114 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2115 SelectObject(hdc, oldFont);
\r
2116 ReleaseDC(hwndMain, hdc);
\r
2118 /* Compute where everything goes */
\r
2119 whiteRect.left = OUTER_MARGIN;
\r
2120 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2121 whiteRect.top = OUTER_MARGIN;
\r
2122 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2124 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2125 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2126 blackRect.top = whiteRect.top;
\r
2127 blackRect.bottom = whiteRect.bottom;
\r
2129 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2130 if (appData.showButtonBar) {
\r
2131 messageRect.right = blackRect.right
\r
2132 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2134 messageRect.right = blackRect.right;
\r
2136 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2137 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2139 boardRect.left = whiteRect.left;
\r
2140 boardRect.right = boardRect.left + boardWidth;
\r
2141 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2142 boardRect.bottom = boardRect.top + boardWidth;
\r
2144 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2145 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2146 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2147 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2148 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2149 GetWindowRect(hwndMain, &wrect);
\r
2150 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2151 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2152 /* compensate if menu bar wrapped */
\r
2153 GetClientRect(hwndMain, &crect);
\r
2154 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2155 winHeight += offby;
\r
2157 case WMSZ_TOPLEFT:
\r
2158 SetWindowPos(hwndMain, NULL,
\r
2159 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2160 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2163 case WMSZ_TOPRIGHT:
\r
2165 SetWindowPos(hwndMain, NULL,
\r
2166 wrect.left, wrect.bottom - winHeight,
\r
2167 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2170 case WMSZ_BOTTOMLEFT:
\r
2172 SetWindowPos(hwndMain, NULL,
\r
2173 wrect.right - winWidth, wrect.top,
\r
2174 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2177 case WMSZ_BOTTOMRIGHT:
\r
2181 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2182 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2187 for (i = 0; i < N_BUTTONS; i++) {
\r
2188 if (buttonDesc[i].hwnd != NULL) {
\r
2189 DestroyWindow(buttonDesc[i].hwnd);
\r
2190 buttonDesc[i].hwnd = NULL;
\r
2192 if (appData.showButtonBar) {
\r
2193 buttonDesc[i].hwnd =
\r
2194 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2195 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2196 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2197 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2198 (HMENU) buttonDesc[i].id,
\r
2199 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2201 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2202 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2203 MAKELPARAM(FALSE, 0));
\r
2205 if (buttonDesc[i].id == IDM_Pause)
\r
2206 hwndPause = buttonDesc[i].hwnd;
\r
2207 buttonDesc[i].wndproc = (WNDPROC)
\r
2208 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2211 if (gridPen != NULL) DeleteObject(gridPen);
\r
2212 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2213 if (premovePen != NULL) DeleteObject(premovePen);
\r
2214 if (lineGap != 0) {
\r
2215 logbrush.lbStyle = BS_SOLID;
\r
2216 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2218 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2219 lineGap, &logbrush, 0, NULL);
\r
2220 logbrush.lbColor = highlightSquareColor;
\r
2222 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2223 lineGap, &logbrush, 0, NULL);
\r
2225 logbrush.lbColor = premoveHighlightColor;
\r
2227 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2228 lineGap, &logbrush, 0, NULL);
\r
2230 for (i = 0; i < BOARD_SIZE + 1; i++) {
\r
2231 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2232 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2;
\r
2233 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2234 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2235 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2236 BOARD_SIZE * (squareSize + lineGap);
\r
2237 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x =
\r
2238 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left +
\r
2239 lineGap / 2 + (i * (squareSize + lineGap));
\r
2240 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y =
\r
2241 boardRect.top + BOARD_SIZE * (squareSize + lineGap);
\r
2242 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2246 if (boardSize == oldBoardSize) return;
\r
2247 oldBoardSize = boardSize;
\r
2248 oldTinyLayout = tinyLayout;
\r
2250 /* Load piece bitmaps for this board size */
\r
2251 for (i=0; i<=2; i++) {
\r
2252 for (piece = WhitePawn;
\r
2253 (int) piece <= (int) WhiteKing;
\r
2254 piece = (ChessSquare) ((int) piece + 1)) {
\r
2255 if (pieceBitmap[i][piece] != NULL)
\r
2256 DeleteObject(pieceBitmap[i][piece]);
\r
2260 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2261 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2262 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2263 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2264 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2265 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2266 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2267 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2268 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2269 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2270 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2271 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2272 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2273 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2274 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2275 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2276 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2277 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2282 PieceBitmap(ChessSquare p, int kind)
\r
2284 if ((int) p >= (int) BlackPawn)
\r
2285 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2287 return pieceBitmap[kind][(int) p];
\r
2290 /***************************************************************/
\r
2292 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2293 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2295 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2296 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2300 SquareToPos(int row, int column, int * x, int * y)
\r
2303 *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
2304 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2306 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2307 *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
2312 DrawCoordsOnDC(HDC hdc)
\r
2314 static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'};
\r
2315 static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'};
\r
2316 char str[2] = { NULLCHAR, NULLCHAR };
\r
2317 int oldMode, oldAlign, x, y, start, i;
\r
2321 if (!appData.showCoords)
\r
2324 start = flipView ? 0 : 8;
\r
2326 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2327 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2328 oldAlign = GetTextAlign(hdc);
\r
2329 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2331 y = boardRect.top + lineGap;
\r
2332 x = boardRect.left + lineGap;
\r
2334 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2335 for (i = 0; i < 8; i++) {
\r
2336 str[0] = files[start + i];
\r
2337 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2338 y += squareSize + lineGap;
\r
2341 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2342 for (i = 0; i < 8; i++) {
\r
2343 str[0] = ranks[start + i];
\r
2344 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2345 x += squareSize + lineGap;
\r
2348 SelectObject(hdc, oldBrush);
\r
2349 SetBkMode(hdc, oldMode);
\r
2350 SetTextAlign(hdc, oldAlign);
\r
2351 SelectObject(hdc, oldFont);
\r
2355 DrawGridOnDC(HDC hdc)
\r
2359 if (lineGap != 0) {
\r
2360 oldPen = SelectObject(hdc, gridPen);
\r
2361 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2);
\r
2362 SelectObject(hdc, oldPen);
\r
2366 #define HIGHLIGHT_PEN 0
\r
2367 #define PREMOVE_PEN 1
\r
2370 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2373 HPEN oldPen, hPen;
\r
2374 if (lineGap == 0) return;
\r
2376 x1 = boardRect.left +
\r
2377 lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap);
\r
2378 y1 = boardRect.top +
\r
2379 lineGap/2 + y * (squareSize + lineGap);
\r
2381 x1 = boardRect.left +
\r
2382 lineGap/2 + x * (squareSize + lineGap);
\r
2383 y1 = boardRect.top +
\r
2384 lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap);
\r
2386 hPen = pen ? premovePen : highlightPen;
\r
2387 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2388 MoveToEx(hdc, x1, y1, NULL);
\r
2389 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2390 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2391 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2392 LineTo(hdc, x1, y1);
\r
2393 SelectObject(hdc, oldPen);
\r
2397 DrawHighlightsOnDC(HDC hdc)
\r
2400 for (i=0; i<2; i++) {
\r
2401 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
2402 DrawHighlightOnDC(hdc, TRUE,
\r
2403 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
2406 for (i=0; i<2; i++) {
\r
2407 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2408 premoveHighlightInfo.sq[i].y >= 0) {
\r
2409 DrawHighlightOnDC(hdc, TRUE,
\r
2410 premoveHighlightInfo.sq[i].x,
\r
2411 premoveHighlightInfo.sq[i].y,
\r
2417 /* Note: sqcolor is used only in monoMode */
\r
2418 /* Note that this code is largely duplicated in woptions.c,
\r
2419 function DrawSampleSquare, so that needs to be updated too */
\r
2421 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2423 HBITMAP oldBitmap;
\r
2426 if (appData.blindfold) return;
\r
2428 if (appData.monoMode) {
\r
2429 SelectObject(tmphdc, PieceBitmap(piece,
\r
2430 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2431 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2432 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2435 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2436 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2437 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2439 /* Use black piece color for outline of white pieces */
\r
2440 /* Not sure this looks really good (though xboard does it).
\r
2441 Maybe better to have another selectable color, default black */
\r
2442 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
2443 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2444 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2446 /* Use black for outline of white pieces */
\r
2447 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2448 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
2452 /* Use white piece color for details of black pieces */
\r
2453 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
2454 WHITE_PIECE ones aren't always the right shape. */
\r
2455 /* Not sure this looks really good (though xboard does it).
\r
2456 Maybe better to have another selectable color, default medium gray? */
\r
2457 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
2458 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
2459 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2460 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2461 SelectObject(hdc, blackPieceBrush);
\r
2462 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2464 /* Use square color for details of black pieces */
\r
2465 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2466 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2467 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2470 SelectObject(hdc, oldBrush);
\r
2471 SelectObject(tmphdc, oldBitmap);
\r
2476 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
2478 int row, column, x, y, square_color, piece_color;
\r
2479 ChessSquare piece;
\r
2482 for (row = 0; row < BOARD_SIZE; row++) {
\r
2483 for (column = 0; column < BOARD_SIZE; column++) {
\r
2485 SquareToPos(row, column, &x, &y);
\r
2487 piece = board[row][column];
\r
2489 square_color = ((column + row) % 2) == 1;
\r
2490 piece_color = (int) piece < (int) BlackPawn;
\r
2492 if (appData.monoMode) {
\r
2493 if (piece == EmptySquare) {
\r
2494 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
2495 square_color ? WHITENESS : BLACKNESS);
\r
2497 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
2500 oldBrush = SelectObject(hdc, square_color ?
\r
2501 lightSquareBrush : darkSquareBrush);
\r
2502 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
2503 SelectObject(hdc, oldBrush);
\r
2504 if (piece != EmptySquare)
\r
2505 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
2511 #define MAX_CLIPS 200 /* more than enough */
\r
2514 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
2516 static Board lastReq, lastDrawn;
\r
2517 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
2518 static int lastDrawnFlipView = 0;
\r
2519 static int lastReqValid = 0, lastDrawnValid = 0;
\r
2520 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
2523 HBITMAP bufferBitmap;
\r
2524 HBITMAP oldBitmap;
\r
2526 HRGN clips[MAX_CLIPS];
\r
2527 ChessSquare dragged_piece = EmptySquare;
\r
2529 /* I'm undecided on this - this function figures out whether a full
\r
2530 * repaint is necessary on its own, so there's no real reason to have the
\r
2531 * caller tell it that. I think this can safely be set to FALSE - but
\r
2532 * if we trust the callers not to request full repaints unnessesarily, then
\r
2533 * we could skip some clipping work. In other words, only request a full
\r
2534 * redraw when the majority of pieces have changed positions (ie. flip,
\r
2535 * gamestart and similar) --Hawk
\r
2537 Boolean fullrepaint = repaint;
\r
2539 if (board == NULL) {
\r
2540 if (!lastReqValid) {
\r
2545 CopyBoard(lastReq, board);
\r
2549 if (doingSizing) {
\r
2553 if (IsIconic(hwndMain)) {
\r
2557 if (hdc == NULL) {
\r
2558 hdc = GetDC(hwndMain);
\r
2559 if (!appData.monoMode) {
\r
2560 SelectPalette(hdc, hPal, FALSE);
\r
2561 RealizePalette(hdc);
\r
2565 releaseDC = FALSE;
\r
2569 fprintf(debugFP, "*******************************\n"
\r
2571 "dragInfo.from (%d,%d)\n"
\r
2572 "dragInfo.start (%d,%d)\n"
\r
2573 "dragInfo.pos (%d,%d)\n"
\r
2574 "dragInfo.lastpos (%d,%d)\n",
\r
2575 repaint ? "TRUE" : "FALSE",
\r
2576 dragInfo.from.x, dragInfo.from.y,
\r
2577 dragInfo.start.x, dragInfo.start.y,
\r
2578 dragInfo.pos.x, dragInfo.pos.y,
\r
2579 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
2580 fprintf(debugFP, "prev: ");
\r
2581 for (row = 0; row < 8; row++) {
\r
2582 for (column = 0; column < 8; column++) {
\r
2583 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
2586 fprintf(debugFP, "\n");
\r
2587 fprintf(debugFP, "board: ");
\r
2588 for (row = 0; row < 8; row++) {
\r
2589 for (column = 0; column < 8; column++) {
\r
2590 fprintf(debugFP, "%d ", board[row][column]);
\r
2593 fprintf(debugFP, "\n");
\r
2597 /* Create some work-DCs */
\r
2598 hdcmem = CreateCompatibleDC(hdc);
\r
2599 tmphdc = CreateCompatibleDC(hdc);
\r
2601 /* Figure out which squares need updating by comparing the
\r
2602 * newest board with the last drawn board and checking if
\r
2603 * flipping has changed.
\r
2605 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
2606 for (row = 0; row < 8; row++) {
\r
2607 for (column = 0; column < 8; column++) {
\r
2608 if (lastDrawn[row][column] != board[row][column]) {
\r
2609 SquareToPos(row, column, &x, &y);
\r
2610 clips[num_clips++] =
\r
2611 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
2615 for (i=0; i<2; i++) {
\r
2616 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
2617 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
2618 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
2619 lastDrawnHighlight.sq[i].y >= 0) {
\r
2620 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
2621 lastDrawnHighlight.sq[i].x, &x, &y);
\r
2622 clips[num_clips++] =
\r
2623 CreateRectRgn(x - lineGap, y - lineGap,
\r
2624 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2626 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
2627 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
2628 clips[num_clips++] =
\r
2629 CreateRectRgn(x - lineGap, y - lineGap,
\r
2630 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2634 for (i=0; i<2; i++) {
\r
2635 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
2636 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
2637 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
2638 lastDrawnPremove.sq[i].y >= 0) {
\r
2639 SquareToPos(lastDrawnPremove.sq[i].y,
\r
2640 lastDrawnPremove.sq[i].x, &x, &y);
\r
2641 clips[num_clips++] =
\r
2642 CreateRectRgn(x - lineGap, y - lineGap,
\r
2643 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2645 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2646 premoveHighlightInfo.sq[i].y >= 0) {
\r
2647 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
2648 premoveHighlightInfo.sq[i].x, &x, &y);
\r
2649 clips[num_clips++] =
\r
2650 CreateRectRgn(x - lineGap, y - lineGap,
\r
2651 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2656 fullrepaint = TRUE;
\r
2659 /* Create a buffer bitmap - this is the actual bitmap
\r
2660 * being written to. When all the work is done, we can
\r
2661 * copy it to the real DC (the screen). This avoids
\r
2662 * the problems with flickering.
\r
2664 GetClientRect(hwndMain, &Rect);
\r
2665 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
2666 Rect.bottom-Rect.top+1);
\r
2667 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
2668 if (!appData.monoMode) {
\r
2669 SelectPalette(hdcmem, hPal, FALSE);
\r
2672 /* Create clips for dragging */
\r
2673 if (!fullrepaint) {
\r
2674 if (dragInfo.from.x >= 0) {
\r
2675 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
2676 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2678 if (dragInfo.start.x >= 0) {
\r
2679 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
2680 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2682 if (dragInfo.pos.x >= 0) {
\r
2683 x = dragInfo.pos.x - squareSize / 2;
\r
2684 y = dragInfo.pos.y - squareSize / 2;
\r
2685 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2687 if (dragInfo.lastpos.x >= 0) {
\r
2688 x = dragInfo.lastpos.x - squareSize / 2;
\r
2689 y = dragInfo.lastpos.y - squareSize / 2;
\r
2690 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2694 /* If dragging is in progress, we temporarely remove the piece */
\r
2695 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
2696 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
2697 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
2700 /* Are we animating a move?
\r
2702 * - remove the piece from the board (temporarely)
\r
2703 * - calculate the clipping region
\r
2705 if (!fullrepaint) {
\r
2706 if (animInfo.piece != EmptySquare) {
\r
2707 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
2708 x = boardRect.left + animInfo.lastpos.x;
\r
2709 y = boardRect.top + animInfo.lastpos.y;
\r
2710 x2 = boardRect.left + animInfo.pos.x;
\r
2711 y2 = boardRect.top + animInfo.pos.y;
\r
2712 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
2713 /* Slight kludge. The real problem is that after AnimateMove is
\r
2714 done, the position on the screen does not match lastDrawn.
\r
2715 This currently causes trouble only on e.p. captures in
\r
2716 atomic, where the piece moves to an empty square and then
\r
2717 explodes. The old and new positions both had an empty square
\r
2718 at the destination, but animation has drawn a piece there and
\r
2719 we have to remember to erase it. */
\r
2720 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
2724 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
2725 if (num_clips == 0)
\r
2726 fullrepaint = TRUE;
\r
2728 /* Set clipping on the memory DC */
\r
2729 if (!fullrepaint) {
\r
2730 SelectClipRgn(hdcmem, clips[0]);
\r
2731 for (x = 1; x < num_clips; x++) {
\r
2732 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
2733 abort(); // this should never ever happen!
\r
2737 /* Do all the drawing to the memory DC */
\r
2738 DrawGridOnDC(hdcmem);
\r
2739 DrawHighlightsOnDC(hdcmem);
\r
2740 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
2741 DrawCoordsOnDC(hdcmem);
\r
2743 /* Put the dragged piece back into place and draw it */
\r
2744 if (dragged_piece != EmptySquare) {
\r
2745 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
2746 x = dragInfo.pos.x - squareSize / 2;
\r
2747 y = dragInfo.pos.y - squareSize / 2;
\r
2748 DrawPieceOnDC(hdcmem, dragged_piece,
\r
2749 ((int) dragged_piece < (int) BlackPawn),
\r
2750 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
2753 /* Put the animated piece back into place and draw it */
\r
2754 if (animInfo.piece != EmptySquare) {
\r
2755 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
2756 x = boardRect.left + animInfo.pos.x;
\r
2757 y = boardRect.top + animInfo.pos.y;
\r
2758 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
2759 ((int) animInfo.piece < (int) BlackPawn),
\r
2760 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
2763 /* Release the bufferBitmap by selecting in the old bitmap
\r
2764 * and delete the memory DC
\r
2766 SelectObject(hdcmem, oldBitmap);
\r
2769 /* Set clipping on the target DC */
\r
2770 if (!fullrepaint) {
\r
2771 SelectClipRgn(hdc, clips[0]);
\r
2772 for (x = 1; x < num_clips; x++) {
\r
2773 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
2774 abort(); // this should never ever happen!
\r
2778 /* Copy the new bitmap onto the screen in one go.
\r
2779 * This way we avoid any flickering
\r
2781 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
2782 BitBlt(hdc, boardRect.left, boardRect.top,
\r
2783 boardRect.right - boardRect.left,
\r
2784 boardRect.bottom - boardRect.top,
\r
2785 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
2786 SelectObject(tmphdc, oldBitmap);
\r
2788 /* Massive cleanup */
\r
2789 for (x = 0; x < num_clips; x++)
\r
2790 DeleteObject(clips[x]);
\r
2793 DeleteObject(bufferBitmap);
\r
2796 ReleaseDC(hwndMain, hdc);
\r
2798 if (lastDrawnFlipView != flipView) {
\r
2800 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
2802 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
2805 CopyBoard(lastDrawn, board);
\r
2806 lastDrawnHighlight = highlightInfo;
\r
2807 lastDrawnPremove = premoveHighlightInfo;
\r
2808 lastDrawnFlipView = flipView;
\r
2809 lastDrawnValid = 1;
\r
2813 /*---------------------------------------------------------------------------*\
\r
2814 | CLIENT PAINT PROCEDURE
\r
2815 | This is the main event-handler for the WM_PAINT message.
\r
2817 \*---------------------------------------------------------------------------*/
\r
2819 PaintProc(HWND hwnd)
\r
2825 if(hdc = BeginPaint(hwnd, &ps)) {
\r
2826 if (IsIconic(hwnd)) {
\r
2827 DrawIcon(hdc, 2, 2, iconCurrent);
\r
2829 if (!appData.monoMode) {
\r
2830 SelectPalette(hdc, hPal, FALSE);
\r
2831 RealizePalette(hdc);
\r
2833 HDCDrawPosition(hdc, 1, NULL);
\r
2835 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2836 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
2837 ETO_CLIPPED|ETO_OPAQUE,
\r
2838 &messageRect, messageText, strlen(messageText), NULL);
\r
2839 SelectObject(hdc, oldFont);
\r
2840 DisplayBothClocks();
\r
2842 EndPaint(hwnd,&ps);
\r
2850 * If the user selects on a border boundary, return -1; if off the board,
\r
2851 * return -2. Otherwise map the event coordinate to the square.
\r
2852 * The offset boardRect.left or boardRect.top must already have been
\r
2853 * subtracted from x.
\r
2856 EventToSquare(int x)
\r
2863 if ((x % (squareSize + lineGap)) >= squareSize)
\r
2865 x /= (squareSize + lineGap);
\r
2866 if (x >= BOARD_SIZE)
\r
2877 DropEnable dropEnables[] = {
\r
2878 { 'P', DP_Pawn, "Pawn" },
\r
2879 { 'N', DP_Knight, "Knight" },
\r
2880 { 'B', DP_Bishop, "Bishop" },
\r
2881 { 'R', DP_Rook, "Rook" },
\r
2882 { 'Q', DP_Queen, "Queen" },
\r
2886 SetupDropMenu(HMENU hmenu)
\r
2888 int i, count, enable;
\r
2890 extern char white_holding[], black_holding[];
\r
2891 char item[MSG_SIZ];
\r
2893 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
2894 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
2895 dropEnables[i].piece);
\r
2897 while (p && *p++ == dropEnables[i].piece) count++;
\r
2898 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
2899 enable = count > 0 || !appData.testLegality
\r
2900 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
2901 && !appData.icsActive);
\r
2902 ModifyMenu(hmenu, dropEnables[i].command,
\r
2903 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
2904 dropEnables[i].command, item);
\r
2908 static int fromX = -1, fromY = -1, toX, toY;
\r
2910 /* Event handler for mouse messages */
\r
2912 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
2916 static int recursive = 0;
\r
2918 BOOLEAN saveAnimate;
\r
2919 static BOOLEAN sameAgain = FALSE;
\r
2922 if (message == WM_MBUTTONUP) {
\r
2923 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
2924 to the middle button: we simulate pressing the left button too!
\r
2926 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
2927 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
2933 pt.x = LOWORD(lParam);
\r
2934 pt.y = HIWORD(lParam);
\r
2935 x = EventToSquare(pt.x - boardRect.left);
\r
2936 y = EventToSquare(pt.y - boardRect.top);
\r
2937 if (!flipView && y >= 0) {
\r
2938 y = BOARD_SIZE - 1 - y;
\r
2940 if (flipView && x >= 0) {
\r
2941 x = BOARD_SIZE - 1 - x;
\r
2944 switch (message) {
\r
2945 case WM_LBUTTONDOWN:
\r
2947 sameAgain = FALSE;
\r
2949 /* Downclick vertically off board; check if on clock */
\r
2950 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
2951 if (gameMode == EditPosition) {
\r
2952 SetWhiteToPlayEvent();
\r
2953 } else if (gameMode == IcsPlayingBlack ||
\r
2954 gameMode == MachinePlaysWhite) {
\r
2957 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
2958 if (gameMode == EditPosition) {
\r
2959 SetBlackToPlayEvent();
\r
2960 } else if (gameMode == IcsPlayingWhite ||
\r
2961 gameMode == MachinePlaysBlack) {
\r
2965 if (!appData.highlightLastMove) {
\r
2966 ClearHighlights();
\r
2967 DrawPosition(FALSE, NULL);
\r
2969 fromX = fromY = -1;
\r
2970 dragInfo.start.x = dragInfo.start.y = -1;
\r
2971 dragInfo.from = dragInfo.start;
\r
2973 } else if (x < 0 || y < 0) {
\r
2975 } else if (fromX == x && fromY == y) {
\r
2976 /* Downclick on same square again */
\r
2977 ClearHighlights();
\r
2978 DrawPosition(FALSE, NULL);
\r
2979 sameAgain = TRUE;
\r
2980 } else if (fromX != -1) {
\r
2981 /* Downclick on different square */
\r
2982 ChessSquare pdown, pup;
\r
2983 pdown = boards[currentMove][fromY][fromX];
\r
2984 pup = boards[currentMove][y][x];
\r
2985 if (gameMode == EditPosition ||
\r
2986 !((WhitePawn <= pdown && pdown <= WhiteKing &&
\r
2987 WhitePawn <= pup && pup <= WhiteKing) ||
\r
2988 (BlackPawn <= pdown && pdown <= BlackKing &&
\r
2989 BlackPawn <= pup && pup <= BlackKing))) {
\r
2990 /* EditPosition, empty square, or different color piece;
\r
2991 click-click move is possible */
\r
2994 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
2995 if (appData.alwaysPromoteToQueen) {
\r
2996 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
2997 if (!appData.highlightLastMove) {
\r
2998 ClearHighlights();
\r
2999 DrawPosition(FALSE, NULL);
\r
3002 SetHighlights(fromX, fromY, toX, toY);
\r
3003 DrawPosition(FALSE, NULL);
\r
3004 PromotionPopup(hwnd);
\r
3006 } else { /* not a promotion */
\r
3007 if (appData.animate || appData.highlightLastMove) {
\r
3008 SetHighlights(fromX, fromY, toX, toY);
\r
3010 ClearHighlights();
\r
3012 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3013 if (appData.animate && !appData.highlightLastMove) {
\r
3014 ClearHighlights();
\r
3015 DrawPosition(FALSE, NULL);
\r
3018 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3019 fromX = fromY = -1;
\r
3022 ClearHighlights();
\r
3023 DrawPosition(FALSE, NULL);
\r
3025 /* First downclick, or restart on a square with same color piece */
\r
3026 if (!frozen && OKToStartUserMove(x, y)) {
\r
3029 dragInfo.lastpos = pt;
\r
3030 dragInfo.from.x = fromX;
\r
3031 dragInfo.from.y = fromY;
\r
3032 dragInfo.start = dragInfo.from;
\r
3033 SetCapture(hwndMain);
\r
3035 fromX = fromY = -1;
\r
3036 dragInfo.start.x = dragInfo.start.y = -1;
\r
3037 dragInfo.from = dragInfo.start;
\r
3041 case WM_LBUTTONUP:
\r
3043 if (fromX == -1) break;
\r
3044 if (x == fromX && y == fromY) {
\r
3045 dragInfo.from.x = dragInfo.from.y = -1;
\r
3046 /* Upclick on same square */
\r
3048 /* Clicked same square twice: abort click-click move */
\r
3049 fromX = fromY = -1;
\r
3051 ClearPremoveHighlights();
\r
3053 /* First square clicked: start click-click move */
\r
3054 SetHighlights(fromX, fromY, -1, -1);
\r
3056 DrawPosition(FALSE, NULL);
\r
3057 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
3058 /* Errant click; ignore */
\r
3061 /* Finish drag move */
\r
3062 dragInfo.from.x = dragInfo.from.y = -1;
\r
3065 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
3066 appData.animate = appData.animate && !appData.animateDragging;
\r
3067 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
3068 if (appData.alwaysPromoteToQueen) {
\r
3069 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3071 DrawPosition(FALSE, NULL);
\r
3072 PromotionPopup(hwnd);
\r
3075 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3077 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3078 appData.animate = saveAnimate;
\r
3079 fromX = fromY = -1;
\r
3080 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
3081 ClearHighlights();
\r
3083 if (appData.animate || appData.animateDragging ||
\r
3084 appData.highlightDragging || gotPremove) {
\r
3085 DrawPosition(FALSE, NULL);
\r
3088 dragInfo.start.x = dragInfo.start.y = -1;
\r
3089 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
3092 case WM_MOUSEMOVE:
\r
3093 if ((appData.animateDragging || appData.highlightDragging)
\r
3094 && (wParam & MK_LBUTTON)
\r
3095 && dragInfo.from.x >= 0) {
\r
3096 if (appData.animateDragging) {
\r
3097 dragInfo.pos = pt;
\r
3099 if (appData.highlightDragging) {
\r
3100 SetHighlights(fromX, fromY, x, y);
\r
3102 DrawPosition(FALSE, NULL);
\r
3103 dragInfo.lastpos = dragInfo.pos;
\r
3106 case WM_MOUSEWHEEL:
\r
3107 /* Mouse Wheel is being rolled forward
\r
3108 * Play moves forward
\r
3110 if ((short)HIWORD(wParam) > 0)
\r
3111 if (forwardMostMove > 0 && currentMove != forwardMostMove)
\r
3113 /* Mouse Wheel is being rolled backward
\r
3114 * Play moves backward
\r
3116 if ((short)HIWORD(wParam) < 0)
\r
3117 if (currentMove > 0) BackwardEvent();
\r
3119 case WM_MBUTTONDOWN:
\r
3120 case WM_RBUTTONDOWN:
\r
3123 fromX = fromY = -1;
\r
3124 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
3125 dragInfo.start.x = dragInfo.start.y = -1;
\r
3126 dragInfo.from = dragInfo.start;
\r
3127 dragInfo.lastpos = dragInfo.pos;
\r
3128 if (appData.highlightDragging) {
\r
3129 ClearHighlights();
\r
3131 DrawPosition(TRUE, NULL);
\r
3133 switch (gameMode) {
\r
3134 case EditPosition:
\r
3135 case IcsExamining:
\r
3136 if (x < 0 || y < 0) break;
\r
3139 if (message == WM_MBUTTONDOWN) {
\r
3140 buttonCount = 3; /* even if system didn't think so */
\r
3141 if (wParam & MK_SHIFT)
\r
3142 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3144 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3145 } else { /* message == WM_RBUTTONDOWN */
\r
3147 if (buttonCount == 3) {
\r
3148 if (wParam & MK_SHIFT)
\r
3149 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3151 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3153 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3156 /* Just have one menu, on the right button. Windows users don't
\r
3157 think to try the middle one, and sometimes other software steals
\r
3158 it, or it doesn't really exist. */
\r
3159 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3163 case IcsPlayingWhite:
\r
3164 case IcsPlayingBlack:
\r
3166 case MachinePlaysWhite:
\r
3167 case MachinePlaysBlack:
\r
3168 if (appData.testLegality &&
\r
3169 gameInfo.variant != VariantBughouse &&
\r
3170 gameInfo.variant != VariantCrazyhouse) break;
\r
3171 if (x < 0 || y < 0) break;
\r
3174 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
3175 SetupDropMenu(hmenu);
\r
3176 MenuPopup(hwnd, pt, hmenu, -1);
\r
3187 /* Preprocess messages for buttons in main window */
\r
3189 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3191 int id = GetWindowLong(hwnd, GWL_ID);
\r
3194 for (i=0; i<N_BUTTONS; i++) {
\r
3195 if (buttonDesc[i].id == id) break;
\r
3197 if (i == N_BUTTONS) return 0;
\r
3198 switch (message) {
\r
3203 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
3204 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
3211 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
3214 if (appData.icsActive) {
\r
3215 if (GetKeyState(VK_SHIFT) < 0) {
\r
3217 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3218 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3222 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3223 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3230 if (appData.icsActive) {
\r
3231 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3232 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3234 SendMessage(h, WM_CHAR, wParam, lParam);
\r
3236 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
3237 PopUpMoveDialog((char)wParam);
\r
3243 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
3246 /* Process messages for Promotion dialog box */
\r
3248 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
3252 switch (message) {
\r
3253 case WM_INITDIALOG: /* message: initialize dialog box */
\r
3254 /* Center the dialog over the application window */
\r
3255 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
3256 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
3257 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
3258 gameInfo.variant == VariantGiveaway) ?
\r
3259 SW_SHOW : SW_HIDE);
\r
3262 case WM_COMMAND: /* message: received a command */
\r
3263 switch (LOWORD(wParam)) {
\r
3265 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3266 ClearHighlights();
\r
3267 DrawPosition(FALSE, NULL);
\r
3287 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3288 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
3289 if (!appData.highlightLastMove) {
\r
3290 ClearHighlights();
\r
3291 DrawPosition(FALSE, NULL);
\r
3298 /* Pop up promotion dialog */
\r
3300 PromotionPopup(HWND hwnd)
\r
3304 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
3305 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
3306 hwnd, (DLGPROC)lpProc);
\r
3307 FreeProcInstance(lpProc);
\r
3310 /* Toggle ShowThinking */
\r
3312 ToggleShowThinking()
\r
3314 ShowThinkingEvent(!appData.showThinking);
\r
3318 LoadGameDialog(HWND hwnd, char* title)
\r
3322 char fileTitle[MSG_SIZ];
\r
3323 f = OpenFileDialog(hwnd, FALSE, "",
\r
3324 appData.oldSaveStyle ? "gam" : "pgn",
\r
3326 title, &number, fileTitle, NULL);
\r
3328 cmailMsgLoaded = FALSE;
\r
3329 if (number == 0) {
\r
3330 int error = GameListBuild(f);
\r
3332 DisplayError("Cannot build game list", error);
\r
3333 } else if (!ListEmpty(&gameList) &&
\r
3334 ((ListGame *) gameList.tailPred)->number > 1) {
\r
3335 GameListPopUp(f, fileTitle);
\r
3338 GameListDestroy();
\r
3341 LoadGame(f, number, fileTitle, FALSE);
\r
3346 ChangedConsoleFont()
\r
3349 CHARRANGE tmpsel, sel;
\r
3350 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
3351 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3352 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3355 cfmt.cbSize = sizeof(CHARFORMAT);
\r
3356 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
3357 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
3358 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
3359 * size. This was undocumented in the version of MSVC++ that I had
\r
3360 * when I wrote the code, but is apparently documented now.
\r
3362 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
3363 cfmt.bCharSet = f->lf.lfCharSet;
\r
3364 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
3365 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
3366 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
3367 /* Why are the following seemingly needed too? */
\r
3368 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
3369 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
3370 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
3372 tmpsel.cpMax = -1; /*999999?*/
\r
3373 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
3374 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
3375 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
3376 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
3378 paraf.cbSize = sizeof(paraf);
\r
3379 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
3380 paraf.dxStartIndent = 0;
\r
3381 paraf.dxOffset = WRAP_INDENT;
\r
3382 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
3383 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
3386 /*---------------------------------------------------------------------------*\
\r
3388 * Window Proc for main window
\r
3390 \*---------------------------------------------------------------------------*/
\r
3392 /* Process messages for main window, etc. */
\r
3394 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3397 int wmId, wmEvent;
\r
3401 char fileTitle[MSG_SIZ];
\r
3403 switch (message) {
\r
3405 case WM_PAINT: /* message: repaint portion of window */
\r
3409 case WM_ERASEBKGND:
\r
3410 if (IsIconic(hwnd)) {
\r
3411 /* Cheat; change the message */
\r
3412 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
3414 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
3418 case WM_LBUTTONDOWN:
\r
3419 case WM_MBUTTONDOWN:
\r
3420 case WM_RBUTTONDOWN:
\r
3421 case WM_LBUTTONUP:
\r
3422 case WM_MBUTTONUP:
\r
3423 case WM_RBUTTONUP:
\r
3424 case WM_MOUSEMOVE:
\r
3425 case WM_MOUSEWHEEL:
\r
3426 MouseEvent(hwnd, message, wParam, lParam);
\r
3431 if (appData.icsActive) {
\r
3432 if (wParam == '\t') {
\r
3433 if (GetKeyState(VK_SHIFT) < 0) {
\r
3435 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3436 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3440 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3441 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3445 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3446 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3448 SendMessage(h, message, wParam, lParam);
\r
3450 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
3451 PopUpMoveDialog((char)wParam);
\r
3455 case WM_PALETTECHANGED:
\r
3456 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
3458 HDC hdc = GetDC(hwndMain);
\r
3459 SelectPalette(hdc, hPal, TRUE);
\r
3460 nnew = RealizePalette(hdc);
\r
3462 paletteChanged = TRUE;
\r
3464 UpdateColors(hdc);
\r
3466 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
3469 ReleaseDC(hwnd, hdc);
\r
3473 case WM_QUERYNEWPALETTE:
\r
3474 if (!appData.monoMode /*&& paletteChanged*/) {
\r
3476 HDC hdc = GetDC(hwndMain);
\r
3477 paletteChanged = FALSE;
\r
3478 SelectPalette(hdc, hPal, FALSE);
\r
3479 nnew = RealizePalette(hdc);
\r
3481 InvalidateRect(hwnd, &boardRect, FALSE);
\r
3483 ReleaseDC(hwnd, hdc);
\r
3488 case WM_COMMAND: /* message: command from application menu */
\r
3489 wmId = LOWORD(wParam);
\r
3490 wmEvent = HIWORD(wParam);
\r
3495 AnalysisPopDown();
\r
3498 case IDM_LoadGame:
\r
3499 LoadGameDialog(hwnd, "Load Game from File");
\r
3502 case IDM_LoadNextGame:
\r
3506 case IDM_LoadPrevGame:
\r
3510 case IDM_ReloadGame:
\r
3514 case IDM_LoadPosition:
\r
3515 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
3516 Reset(FALSE, TRUE);
\r
3519 f = OpenFileDialog(hwnd, FALSE, "",
\r
3520 appData.oldSaveStyle ? "pos" : "fen",
\r
3522 "Load Position from File", &number, fileTitle, NULL);
\r
3524 LoadPosition(f, number, fileTitle);
\r
3528 case IDM_LoadNextPosition:
\r
3529 ReloadPosition(1);
\r
3532 case IDM_LoadPrevPosition:
\r
3533 ReloadPosition(-1);
\r
3536 case IDM_ReloadPosition:
\r
3537 ReloadPosition(0);
\r
3540 case IDM_SaveGame:
\r
3541 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
3542 f = OpenFileDialog(hwnd, TRUE, defName,
\r
3543 appData.oldSaveStyle ? "gam" : "pgn",
\r
3545 "Save Game to File", NULL, fileTitle, NULL);
\r
3547 SaveGame(f, 0, "");
\r
3551 case IDM_SavePosition:
\r
3552 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
3553 f = OpenFileDialog(hwnd, TRUE, defName,
\r
3554 appData.oldSaveStyle ? "pos" : "fen",
\r
3556 "Save Position to File", NULL, fileTitle, NULL);
\r
3558 SavePosition(f, 0, "");
\r
3562 case IDM_CopyGame:
\r
3563 CopyGameToClipboard();
\r
3566 case IDM_PasteGame:
\r
3567 PasteGameFromClipboard();
\r
3570 case IDM_CopyPosition:
\r
3571 CopyFENToClipboard();
\r
3574 case IDM_PastePosition:
\r
3575 PasteFENFromClipboard();
\r
3578 case IDM_MailMove:
\r
3582 case IDM_ReloadCMailMsg:
\r
3583 Reset(TRUE, TRUE);
\r
3584 ReloadCmailMsgEvent(FALSE);
\r
3587 case IDM_Minimize:
\r
3588 ShowWindow(hwnd, SW_MINIMIZE);
\r
3595 case IDM_MachineWhite:
\r
3596 MachineWhiteEvent();
\r
3598 * refresh the tags dialog only if it's visible
\r
3600 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
3602 tags = PGNTags(&gameInfo);
\r
3603 TagsPopUp(tags, CmailMsg());
\r
3608 case IDM_MachineBlack:
\r
3609 MachineBlackEvent();
\r
3611 * refresh the tags dialog only if it's visible
\r
3613 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
3615 tags = PGNTags(&gameInfo);
\r
3616 TagsPopUp(tags, CmailMsg());
\r
3621 case IDM_TwoMachines:
\r
3622 TwoMachinesEvent();
\r
3624 * refresh the tags dialog only if it's visible
\r
3626 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
3628 tags = PGNTags(&gameInfo);
\r
3629 TagsPopUp(tags, CmailMsg());
\r
3634 case IDM_AnalysisMode:
\r
3635 if (!first.analysisSupport) {
\r
3636 char buf[MSG_SIZ];
\r
3637 sprintf(buf, "%s does not support analysis", first.tidy);
\r
3638 DisplayError(buf, 0);
\r
3640 if (!appData.showThinking) ToggleShowThinking();
\r
3641 AnalyzeModeEvent();
\r
3645 case IDM_AnalyzeFile:
\r
3646 if (!first.analysisSupport) {
\r
3647 char buf[MSG_SIZ];
\r
3648 sprintf(buf, "%s does not support analysis", first.tidy);
\r
3649 DisplayError(buf, 0);
\r
3651 if (!appData.showThinking) ToggleShowThinking();
\r
3652 AnalyzeFileEvent();
\r
3653 LoadGameDialog(hwnd, "Analyze Game from File");
\r
3654 AnalysisPeriodicEvent(1);
\r
3658 case IDM_IcsClient:
\r
3662 case IDM_EditGame:
\r
3666 case IDM_EditPosition:
\r
3667 EditPositionEvent();
\r
3670 case IDM_Training:
\r
3674 case IDM_ShowGameList:
\r
3675 ShowGameListProc();
\r
3678 case IDM_EditTags:
\r
3682 case IDM_EditComment:
\r
3683 if (commentDialogUp && editComment) {
\r
3686 EditCommentEvent();
\r
3706 case IDM_CallFlag:
\r
3726 case IDM_StopObserving:
\r
3727 StopObservingEvent();
\r
3730 case IDM_StopExamining:
\r
3731 StopExaminingEvent();
\r
3734 case IDM_TypeInMove:
\r
3735 PopUpMoveDialog('\000');
\r
3738 case IDM_Backward:
\r
3740 SetFocus(hwndMain);
\r
3745 SetFocus(hwndMain);
\r
3750 SetFocus(hwndMain);
\r
3755 SetFocus(hwndMain);
\r
3762 case IDM_TruncateGame:
\r
3763 TruncateGameEvent();
\r
3770 case IDM_RetractMove:
\r
3771 RetractMoveEvent();
\r
3774 case IDM_FlipView:
\r
3775 flipView = !flipView;
\r
3776 DrawPosition(FALSE, NULL);
\r
3779 case IDM_GeneralOptions:
\r
3780 GeneralOptionsPopup(hwnd);
\r
3783 case IDM_BoardOptions:
\r
3784 BoardOptionsPopup(hwnd);
\r
3787 case IDM_IcsOptions:
\r
3788 IcsOptionsPopup(hwnd);
\r
3792 FontsOptionsPopup(hwnd);
\r
3796 SoundOptionsPopup(hwnd);
\r
3799 case IDM_CommPort:
\r
3800 CommPortOptionsPopup(hwnd);
\r
3803 case IDM_LoadOptions:
\r
3804 LoadOptionsPopup(hwnd);
\r
3807 case IDM_SaveOptions:
\r
3808 SaveOptionsPopup(hwnd);
\r
3811 case IDM_TimeControl:
\r
3812 TimeControlOptionsPopup(hwnd);
\r
3815 case IDM_SaveSettings:
\r
3816 SaveSettings(settingsFileName);
\r
3819 case IDM_SaveSettingsOnExit:
\r
3820 saveSettingsOnExit = !saveSettingsOnExit;
\r
3821 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
3822 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
3823 MF_CHECKED : MF_UNCHECKED));
\r
3834 case IDM_AboutGame:
\r
3839 appData.debugMode = !appData.debugMode;
\r
3840 if (appData.debugMode) {
\r
3841 char dir[MSG_SIZ];
\r
3842 GetCurrentDirectory(MSG_SIZ, dir);
\r
3843 SetCurrentDirectory(installDir);
\r
3844 debugFP = fopen("WinBoard.debug", "w");
\r
3845 SetCurrentDirectory(dir);
\r
3846 setbuf(debugFP, NULL);
\r
3853 case IDM_HELPCONTENTS:
\r
3854 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
3855 MessageBox (GetFocus(),
\r
3856 "Unable to activate help",
\r
3857 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3861 case IDM_HELPSEARCH:
\r
3862 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
3863 MessageBox (GetFocus(),
\r
3864 "Unable to activate help",
\r
3865 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3869 case IDM_HELPHELP:
\r
3870 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
3871 MessageBox (GetFocus(),
\r
3872 "Unable to activate help",
\r
3873 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3878 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
3880 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
3881 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
3882 FreeProcInstance(lpProc);
\r
3885 case IDM_DirectCommand1:
\r
3886 AskQuestionEvent("Direct Command",
\r
3887 "Send to chess program:", "", "1");
\r
3889 case IDM_DirectCommand2:
\r
3890 AskQuestionEvent("Direct Command",
\r
3891 "Send to second chess program:", "", "2");
\r
3894 case EP_WhitePawn:
\r
3895 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
3896 fromX = fromY = -1;
\r
3899 case EP_WhiteKnight:
\r
3900 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
3901 fromX = fromY = -1;
\r
3904 case EP_WhiteBishop:
\r
3905 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
3906 fromX = fromY = -1;
\r
3909 case EP_WhiteRook:
\r
3910 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
3911 fromX = fromY = -1;
\r
3914 case EP_WhiteQueen:
\r
3915 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
3916 fromX = fromY = -1;
\r
3919 case EP_WhiteKing:
\r
3920 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
3921 fromX = fromY = -1;
\r
3924 case EP_BlackPawn:
\r
3925 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
3926 fromX = fromY = -1;
\r
3929 case EP_BlackKnight:
\r
3930 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
3931 fromX = fromY = -1;
\r
3934 case EP_BlackBishop:
\r
3935 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
3936 fromX = fromY = -1;
\r
3939 case EP_BlackRook:
\r
3940 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
3941 fromX = fromY = -1;
\r
3944 case EP_BlackQueen:
\r
3945 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
3946 fromX = fromY = -1;
\r
3949 case EP_BlackKing:
\r
3950 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
3951 fromX = fromY = -1;
\r
3954 case EP_EmptySquare:
\r
3955 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
3956 fromX = fromY = -1;
\r
3959 case EP_ClearBoard:
\r
3960 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
3961 fromX = fromY = -1;
\r
3965 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
3966 fromX = fromY = -1;
\r
3970 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
3971 fromX = fromY = -1;
\r
3975 DropMenuEvent(WhitePawn, fromX, fromY);
\r
3976 fromX = fromY = -1;
\r
3980 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
3981 fromX = fromY = -1;
\r
3985 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
3986 fromX = fromY = -1;
\r
3990 DropMenuEvent(WhiteRook, fromX, fromY);
\r
3991 fromX = fromY = -1;
\r
3995 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
3996 fromX = fromY = -1;
\r
4000 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4006 case CLOCK_TIMER_ID:
\r
4007 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
4008 clockTimerEvent = 0;
\r
4009 DecrementClocks(); /* call into back end */
\r
4011 case LOAD_GAME_TIMER_ID:
\r
4012 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
4013 loadGameTimerEvent = 0;
\r
4014 AutoPlayGameLoop(); /* call into back end */
\r
4016 case ANALYSIS_TIMER_ID:
\r
4017 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
4018 appData.periodicUpdates) {
\r
4019 AnalysisPeriodicEvent(0);
\r
4021 KillTimer(hwnd, analysisTimerEvent);
\r
4022 analysisTimerEvent = 0;
\r
4025 case DELAYED_TIMER_ID:
\r
4026 KillTimer(hwnd, delayedTimerEvent);
\r
4027 delayedTimerEvent = 0;
\r
4028 delayedTimerCallback();
\r
4033 case WM_USER_Input:
\r
4034 InputEvent(hwnd, message, wParam, lParam);
\r
4037 case WM_ENTERSIZEMOVE:
\r
4038 if (hwnd == hwndMain) {
\r
4039 doingSizing = TRUE;
\r
4045 if (hwnd == hwndMain) {
\r
4046 lastSizing = wParam;
\r
4050 case WM_EXITSIZEMOVE:
\r
4051 if (hwnd == hwndMain) {
\r
4053 doingSizing = FALSE;
\r
4054 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4055 GetClientRect(hwnd, &client);
\r
4056 ResizeBoard(client.right, client.bottom, lastSizing);
\r
4061 case WM_DESTROY: /* message: window being destroyed */
\r
4062 PostQuitMessage(0);
\r
4066 if (hwnd == hwndMain) {
\r
4071 default: /* Passes it on if unprocessed */
\r
4072 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4077 /*---------------------------------------------------------------------------*\
\r
4079 * Misc utility routines
\r
4081 \*---------------------------------------------------------------------------*/
\r
4084 * Decent random number generator, at least not as bad as Windows
\r
4085 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
4087 unsigned int randstate;
\r
4092 randstate = randstate * 1664525 + 1013904223;
\r
4093 return (int) randstate & 0x7fffffff;
\r
4097 mysrandom(unsigned int seed)
\r
4104 * returns TRUE if user selects a different color, FALSE otherwise
\r
4108 ChangeColor(HWND hwnd, COLORREF *which)
\r
4110 static BOOL firstTime = TRUE;
\r
4111 static DWORD customColors[16];
\r
4113 COLORREF newcolor;
\r
4118 /* Make initial colors in use available as custom colors */
\r
4119 /* Should we put the compiled-in defaults here instead? */
\r
4121 customColors[i++] = lightSquareColor & 0xffffff;
\r
4122 customColors[i++] = darkSquareColor & 0xffffff;
\r
4123 customColors[i++] = whitePieceColor & 0xffffff;
\r
4124 customColors[i++] = blackPieceColor & 0xffffff;
\r
4125 customColors[i++] = highlightSquareColor & 0xffffff;
\r
4126 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
4128 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
4129 customColors[i++] = textAttribs[ccl].color;
\r
4131 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
4132 firstTime = FALSE;
\r
4135 cc.lStructSize = sizeof(cc);
\r
4136 cc.hwndOwner = hwnd;
\r
4137 cc.hInstance = NULL;
\r
4138 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
4139 cc.lpCustColors = (LPDWORD) customColors;
\r
4140 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
4142 if (!ChooseColor(&cc)) return FALSE;
\r
4144 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
4145 if (newcolor == *which) return FALSE;
\r
4146 *which = newcolor;
\r
4150 InitDrawingColors();
\r
4151 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4156 MyLoadSound(MySound *ms)
\r
4162 if (ms->data) free(ms->data);
\r
4165 switch (ms->name[0]) {
\r
4171 /* System sound from Control Panel. Don't preload here. */
\r
4175 if (ms->name[1] == NULLCHAR) {
\r
4176 /* "!" alone = silence */
\r
4179 /* Builtin wave resource. Error if not found. */
\r
4180 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
4181 if (h == NULL) break;
\r
4182 ms->data = (void *)LoadResource(hInst, h);
\r
4183 if (h == NULL) break;
\r
4188 /* .wav file. Error if not found. */
\r
4189 f = fopen(ms->name, "rb");
\r
4190 if (f == NULL) break;
\r
4191 if (fstat(fileno(f), &st) < 0) break;
\r
4192 ms->data = malloc(st.st_size);
\r
4193 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
4199 char buf[MSG_SIZ];
\r
4200 sprintf(buf, "Error loading sound %s", ms->name);
\r
4201 DisplayError(buf, GetLastError());
\r
4207 MyPlaySound(MySound *ms)
\r
4209 BOOLEAN ok = FALSE;
\r
4210 switch (ms->name[0]) {
\r
4216 /* System sound from Control Panel (deprecated feature).
\r
4217 "$" alone or an unset sound name gets default beep (still in use). */
\r
4218 if (ms->name[1]) {
\r
4219 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
4221 if (!ok) ok = MessageBeep(MB_OK);
\r
4224 /* Builtin wave resource, or "!" alone for silence */
\r
4225 if (ms->name[1]) {
\r
4226 if (ms->data == NULL) return FALSE;
\r
4227 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4233 /* .wav file. Error if not found. */
\r
4234 if (ms->data == NULL) return FALSE;
\r
4235 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4238 /* Don't print an error: this can happen innocently if the sound driver
\r
4239 is busy; for instance, if another instance of WinBoard is playing
\r
4240 a sound at about the same time. */
\r
4243 char buf[MSG_SIZ];
\r
4244 sprintf(buf, "Error playing sound %s", ms->name);
\r
4245 DisplayError(buf, GetLastError());
\r
4253 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4256 OPENFILENAME *ofn;
\r
4257 static UINT *number; /* gross that this is static */
\r
4259 switch (message) {
\r
4260 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4261 /* Center the dialog over the application window */
\r
4262 ofn = (OPENFILENAME *) lParam;
\r
4263 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
4264 number = (UINT *) ofn->lCustData;
\r
4265 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
4269 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4270 return FALSE; /* Allow for further processing */
\r
4273 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
4274 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
4276 return FALSE; /* Allow for further processing */
\r
4282 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
4284 static UINT *number;
\r
4285 OPENFILENAME *ofname;
\r
4288 case WM_INITDIALOG:
\r
4289 ofname = (OPENFILENAME *)lParam;
\r
4290 number = (UINT *)(ofname->lCustData);
\r
4293 ofnot = (OFNOTIFY *)lParam;
\r
4294 if (ofnot->hdr.code == CDN_FILEOK) {
\r
4295 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
4304 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
4305 char *nameFilt, char *dlgTitle, UINT *number,
\r
4306 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
4308 OPENFILENAME openFileName;
\r
4309 char buf1[MSG_SIZ];
\r
4312 if (fileName == NULL) fileName = buf1;
\r
4313 if (defName == NULL) {
\r
4314 strcpy(fileName, "*.");
\r
4315 strcat(fileName, defExt);
\r
4317 strcpy(fileName, defName);
\r
4319 if (fileTitle) strcpy(fileTitle, "");
\r
4320 if (number) *number = 0;
\r
4322 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
4323 openFileName.hwndOwner = hwnd;
\r
4324 openFileName.hInstance = (HANDLE) hInst;
\r
4325 openFileName.lpstrFilter = nameFilt;
\r
4326 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
4327 openFileName.nMaxCustFilter = 0L;
\r
4328 openFileName.nFilterIndex = 1L;
\r
4329 openFileName.lpstrFile = fileName;
\r
4330 openFileName.nMaxFile = MSG_SIZ;
\r
4331 openFileName.lpstrFileTitle = fileTitle;
\r
4332 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
4333 openFileName.lpstrInitialDir = NULL;
\r
4334 openFileName.lpstrTitle = dlgTitle;
\r
4335 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
4336 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
4337 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
4338 | (oldDialog ? 0 : OFN_EXPLORER);
\r
4339 openFileName.nFileOffset = 0;
\r
4340 openFileName.nFileExtension = 0;
\r
4341 openFileName.lpstrDefExt = defExt;
\r
4342 openFileName.lCustData = (LONG) number;
\r
4343 openFileName.lpfnHook = oldDialog ?
\r
4344 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
4345 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
4347 if (write ? GetSaveFileName(&openFileName) :
\r
4348 GetOpenFileName(&openFileName)) {
\r
4349 /* open the file */
\r
4350 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
4352 MessageBox(hwnd, "File open failed", NULL,
\r
4353 MB_OK|MB_ICONEXCLAMATION);
\r
4357 int err = CommDlgExtendedError();
\r
4358 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
4367 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
4369 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
4372 * Get the first pop-up menu in the menu template. This is the
\r
4373 * menu that TrackPopupMenu displays.
\r
4375 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
4377 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
4380 * TrackPopup uses screen coordinates, so convert the
\r
4381 * coordinates of the mouse click to screen coordinates.
\r
4383 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
4385 /* Draw and track the floating pop-up menu. */
\r
4386 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
4387 pt.x, pt.y, 0, hwnd, NULL);
\r
4389 /* Destroy the menu.*/
\r
4390 DestroyMenu(hmenu);
\r
4395 int sizeX, sizeY, newSizeX, newSizeY;
\r
4397 } ResizeEditPlusButtonsClosure;
\r
4400 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
4402 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
4406 if (hChild == cl->hText) return TRUE;
\r
4407 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
4408 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
4409 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
4410 ScreenToClient(cl->hDlg, &pt);
\r
4411 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
4412 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
4416 /* Resize a dialog that has a (rich) edit field filling most of
\r
4417 the top, with a row of buttons below */
\r
4419 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
4422 int newTextHeight, newTextWidth;
\r
4423 ResizeEditPlusButtonsClosure cl;
\r
4425 /*if (IsIconic(hDlg)) return;*/
\r
4426 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
4428 cl.hdwp = BeginDeferWindowPos(8);
\r
4430 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
4431 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
4432 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
4433 if (newTextHeight < 0) {
\r
4434 newSizeY += -newTextHeight;
\r
4435 newTextHeight = 0;
\r
4437 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
4438 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
4444 cl.newSizeX = newSizeX;
\r
4445 cl.newSizeY = newSizeY;
\r
4446 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
4448 EndDeferWindowPos(cl.hdwp);
\r
4451 /* Center one window over another */
\r
4452 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
4454 RECT rChild, rParent;
\r
4455 int wChild, hChild, wParent, hParent;
\r
4456 int wScreen, hScreen, xNew, yNew;
\r
4459 /* Get the Height and Width of the child window */
\r
4460 GetWindowRect (hwndChild, &rChild);
\r
4461 wChild = rChild.right - rChild.left;
\r
4462 hChild = rChild.bottom - rChild.top;
\r
4464 /* Get the Height and Width of the parent window */
\r
4465 GetWindowRect (hwndParent, &rParent);
\r
4466 wParent = rParent.right - rParent.left;
\r
4467 hParent = rParent.bottom - rParent.top;
\r
4469 /* Get the display limits */
\r
4470 hdc = GetDC (hwndChild);
\r
4471 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
4472 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
4473 ReleaseDC(hwndChild, hdc);
\r
4475 /* Calculate new X position, then adjust for screen */
\r
4476 xNew = rParent.left + ((wParent - wChild) /2);
\r
4479 } else if ((xNew+wChild) > wScreen) {
\r
4480 xNew = wScreen - wChild;
\r
4483 /* Calculate new Y position, then adjust for screen */
\r
4484 yNew = rParent.top + ((hParent - hChild) /2);
\r
4487 } else if ((yNew+hChild) > hScreen) {
\r
4488 yNew = hScreen - hChild;
\r
4491 /* Set it, and return */
\r
4492 return SetWindowPos (hwndChild, NULL,
\r
4493 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
4496 /*---------------------------------------------------------------------------*\
\r
4498 * Startup Dialog functions
\r
4500 \*---------------------------------------------------------------------------*/
\r
4502 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
4504 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
4506 while (*cd != NULL) {
\r
4507 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
4513 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
4515 char buf1[ARG_MAX];
\r
4518 if (str[0] == '@') {
\r
4519 FILE* f = fopen(str + 1, "r");
\r
4521 DisplayFatalError(str + 1, errno, 2);
\r
4524 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
4526 buf1[len] = NULLCHAR;
\r
4530 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
4533 char buf[MSG_SIZ];
\r
4534 char *end = strchr(str, '\n');
\r
4535 if (end == NULL) return;
\r
4536 memcpy(buf, str, end - str);
\r
4537 buf[end - str] = NULLCHAR;
\r
4538 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
4544 SetStartupDialogEnables(HWND hDlg)
\r
4546 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
4547 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
4548 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
4549 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
4550 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
4551 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
4552 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
4553 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
4554 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
4555 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
4556 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
4557 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
4558 IsDlgButtonChecked(hDlg, OPT_View));
\r
4562 QuoteForFilename(char *filename)
\r
4564 int dquote, space;
\r
4565 dquote = strchr(filename, '"') != NULL;
\r
4566 space = strchr(filename, ' ') != NULL;
\r
4567 if (dquote || space) {
\r
4579 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
4581 char buf[MSG_SIZ];
\r
4584 InitComboStringsFromOption(hwndCombo, nthnames);
\r
4585 q = QuoteForFilename(nthcp);
\r
4586 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
4587 if (*nthdir != NULLCHAR) {
\r
4588 q = QuoteForFilename(nthdir);
\r
4589 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
4591 if (*nthcp == NULLCHAR) {
\r
4592 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
4593 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
4594 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
4595 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
4600 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4602 char buf[MSG_SIZ];
\r
4606 switch (message) {
\r
4607 case WM_INITDIALOG:
\r
4608 /* Center the dialog */
\r
4609 CenterWindow (hDlg, GetDesktopWindow());
\r
4610 /* Initialize the dialog items */
\r
4611 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
4612 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
4613 firstChessProgramNames);
\r
4614 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
4615 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
4616 secondChessProgramNames);
\r
4617 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
4618 InitComboStringsFromOption(hwndCombo, icsNames);
\r
4619 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
4620 if (*appData.icsHelper != NULLCHAR) {
\r
4621 char *q = QuoteForFilename(appData.icsHelper);
\r
4622 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
4624 if (*appData.icsHost == NULLCHAR) {
\r
4625 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
4626 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
4627 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
4628 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
4629 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
4631 if (chessProgram) {
\r
4632 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
4633 } else if (appData.icsActive) {
\r
4634 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
4635 } else if (appData.noChessProgram) {
\r
4636 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
4638 SetStartupDialogEnables(hDlg);
\r
4642 switch (LOWORD(wParam)) {
\r
4644 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
4645 strcpy(buf, "/fcp=");
\r
4646 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4648 ParseArgs(StringGet, &p);
\r
4649 strcpy(buf, "/scp=");
\r
4650 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4652 ParseArgs(StringGet, &p);
\r
4653 appData.noChessProgram = FALSE;
\r
4654 appData.icsActive = FALSE;
\r
4655 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
4656 strcpy(buf, "/ics /icshost=");
\r
4657 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4659 ParseArgs(StringGet, &p);
\r
4660 if (appData.zippyPlay) {
\r
4661 strcpy(buf, "/fcp=");
\r
4662 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4664 ParseArgs(StringGet, &p);
\r
4666 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
4667 appData.noChessProgram = TRUE;
\r
4668 appData.icsActive = FALSE;
\r
4670 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
4671 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
4674 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
4675 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
4677 ParseArgs(StringGet, &p);
\r
4679 EndDialog(hDlg, TRUE);
\r
4686 case IDM_HELPCONTENTS:
\r
4687 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
4688 MessageBox (GetFocus(),
\r
4689 "Unable to activate help",
\r
4690 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4695 SetStartupDialogEnables(hDlg);
\r
4703 /*---------------------------------------------------------------------------*\
\r
4705 * About box dialog functions
\r
4707 \*---------------------------------------------------------------------------*/
\r
4709 /* Process messages for "About" dialog box */
\r
4711 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4713 switch (message) {
\r
4714 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4715 /* Center the dialog over the application window */
\r
4716 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4717 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
4720 case WM_COMMAND: /* message: received a command */
\r
4721 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
4722 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
4723 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4731 /*---------------------------------------------------------------------------*\
\r
4733 * Comment Dialog functions
\r
4735 \*---------------------------------------------------------------------------*/
\r
4738 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4740 static HANDLE hwndText = NULL;
\r
4741 int len, newSizeX, newSizeY, flags;
\r
4742 static int sizeX, sizeY;
\r
4747 switch (message) {
\r
4748 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4749 /* Initialize the dialog items */
\r
4750 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
4751 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
4752 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
4753 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
4754 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
4755 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
4756 SetWindowText(hDlg, commentTitle);
\r
4757 if (editComment) {
\r
4758 SetFocus(hwndText);
\r
4760 SetFocus(GetDlgItem(hDlg, IDOK));
\r
4762 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
4763 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
4764 MAKELPARAM(FALSE, 0));
\r
4765 /* Size and position the dialog */
\r
4766 if (!commentDialog) {
\r
4767 commentDialog = hDlg;
\r
4768 flags = SWP_NOZORDER;
\r
4769 GetClientRect(hDlg, &rect);
\r
4770 sizeX = rect.right;
\r
4771 sizeY = rect.bottom;
\r
4772 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
4773 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
4774 WINDOWPLACEMENT wp;
\r
4775 EnsureOnScreen(&commentX, &commentY);
\r
4776 wp.length = sizeof(WINDOWPLACEMENT);
\r
4778 wp.showCmd = SW_SHOW;
\r
4779 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
4780 wp.rcNormalPosition.left = commentX;
\r
4781 wp.rcNormalPosition.right = commentX + commentW;
\r
4782 wp.rcNormalPosition.top = commentY;
\r
4783 wp.rcNormalPosition.bottom = commentY + commentH;
\r
4784 SetWindowPlacement(hDlg, &wp);
\r
4786 GetClientRect(hDlg, &rect);
\r
4787 newSizeX = rect.right;
\r
4788 newSizeY = rect.bottom;
\r
4789 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
4790 newSizeX, newSizeY);
\r
4797 case WM_COMMAND: /* message: received a command */
\r
4798 switch (LOWORD(wParam)) {
\r
4800 if (editComment) {
\r
4802 /* Read changed options from the dialog box */
\r
4803 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
4804 len = GetWindowTextLength(hwndText);
\r
4805 str = (char *) malloc(len + 1);
\r
4806 GetWindowText(hwndText, str, len + 1);
\r
4815 ReplaceComment(commentIndex, str);
\r
4822 case OPT_CancelComment:
\r
4826 case OPT_ClearComment:
\r
4827 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
4830 case OPT_EditComment:
\r
4831 EditCommentEvent();
\r
4840 newSizeX = LOWORD(lParam);
\r
4841 newSizeY = HIWORD(lParam);
\r
4842 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
4847 case WM_GETMINMAXINFO:
\r
4848 /* Prevent resizing window too small */
\r
4849 mmi = (MINMAXINFO *) lParam;
\r
4850 mmi->ptMinTrackSize.x = 100;
\r
4851 mmi->ptMinTrackSize.y = 100;
\r
4858 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
4863 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
4865 if (str == NULL) str = "";
\r
4866 p = (char *) malloc(2 * strlen(str) + 2);
\r
4869 if (*str == '\n') *q++ = '\r';
\r
4873 if (commentText != NULL) free(commentText);
\r
4875 commentIndex = index;
\r
4876 commentTitle = title;
\r
4878 editComment = edit;
\r
4880 if (commentDialog) {
\r
4881 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
4882 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
4884 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
4885 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
4886 hwndMain, (DLGPROC)lpProc);
\r
4887 FreeProcInstance(lpProc);
\r
4889 commentDialogUp = TRUE;
\r
4893 /*---------------------------------------------------------------------------*\
\r
4895 * Type-in move dialog functions
\r
4897 \*---------------------------------------------------------------------------*/
\r
4900 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4902 char move[MSG_SIZ];
\r
4904 ChessMove moveType;
\r
4905 int fromX, fromY, toX, toY;
\r
4908 switch (message) {
\r
4909 case WM_INITDIALOG:
\r
4910 move[0] = (char) lParam;
\r
4911 move[1] = NULLCHAR;
\r
4912 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4913 hInput = GetDlgItem(hDlg, OPT_Move);
\r
4914 SetWindowText(hInput, move);
\r
4916 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
4920 switch (LOWORD(wParam)) {
\r
4922 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
4923 gameMode != Training) {
\r
4924 DisplayMoveError("Displayed move is not current");
\r
4926 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
4927 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
4928 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
4929 if (gameMode != Training)
\r
4930 forwardMostMove = currentMove;
\r
4931 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4933 DisplayMoveError("Could not parse move");
\r
4936 EndDialog(hDlg, TRUE);
\r
4939 EndDialog(hDlg, FALSE);
\r
4950 PopUpMoveDialog(char firstchar)
\r
4954 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
4955 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
4956 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
4957 gameMode == EditPosition || gameMode == IcsExamining ||
\r
4958 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
4959 gameMode == Training) {
\r
4960 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
4961 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
4962 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
4963 FreeProcInstance(lpProc);
\r
4967 /*---------------------------------------------------------------------------*\
\r
4971 \*---------------------------------------------------------------------------*/
\r
4973 /* Nonmodal error box */
\r
4974 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
4975 WPARAM wParam, LPARAM lParam);
\r
4978 ErrorPopUp(char *title, char *content)
\r
4982 BOOLEAN modal = hwndMain == NULL;
\r
5000 strncpy(errorTitle, title, sizeof(errorTitle));
\r
5001 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
5004 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
5006 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
5007 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
5008 hwndMain, (DLGPROC)lpProc);
\r
5009 FreeProcInstance(lpProc);
\r
5016 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
5017 if (errorDialog == NULL) return;
\r
5018 DestroyWindow(errorDialog);
\r
5019 errorDialog = NULL;
\r
5023 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5028 switch (message) {
\r
5029 case WM_INITDIALOG:
\r
5030 GetWindowRect(hDlg, &rChild);
\r
5031 SetWindowPos(hDlg, NULL, rChild.left,
\r
5032 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
5033 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
5034 errorDialog = hDlg;
\r
5035 SetWindowText(hDlg, errorTitle);
\r
5036 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
5037 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
5041 switch (LOWORD(wParam)) {
\r
5044 if (errorDialog == hDlg) errorDialog = NULL;
\r
5045 DestroyWindow(hDlg);
\r
5056 /*---------------------------------------------------------------------------*\
\r
5058 * Ics Interaction console functions
\r
5060 \*---------------------------------------------------------------------------*/
\r
5062 #define HISTORY_SIZE 64
\r
5063 static char *history[HISTORY_SIZE];
\r
5064 int histIn = 0, histP = 0;
\r
5067 SaveInHistory(char *cmd)
\r
5069 if (history[histIn] != NULL) {
\r
5070 free(history[histIn]);
\r
5071 history[histIn] = NULL;
\r
5073 if (*cmd == NULLCHAR) return;
\r
5074 history[histIn] = StrSave(cmd);
\r
5075 histIn = (histIn + 1) % HISTORY_SIZE;
\r
5076 if (history[histIn] != NULL) {
\r
5077 free(history[histIn]);
\r
5078 history[histIn] = NULL;
\r
5084 PrevInHistory(char *cmd)
\r
5087 if (histP == histIn) {
\r
5088 if (history[histIn] != NULL) free(history[histIn]);
\r
5089 history[histIn] = StrSave(cmd);
\r
5091 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
5092 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
5094 return history[histP];
\r
5100 if (histP == histIn) return NULL;
\r
5101 histP = (histP + 1) % HISTORY_SIZE;
\r
5102 return history[histP];
\r
5109 BOOLEAN immediate;
\r
5110 } IcsTextMenuEntry;
\r
5111 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
5112 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
5115 ParseIcsTextMenu(char *icsTextMenuString)
\r
5118 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
5119 char *p = icsTextMenuString;
\r
5120 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5123 if (e->command != NULL) {
\r
5125 e->command = NULL;
\r
5129 e = icsTextMenuEntry;
\r
5130 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5131 if (*p == ';' || *p == '\n') {
\r
5132 e->item = strdup("-");
\r
5133 e->command = NULL;
\r
5135 } else if (*p == '-') {
\r
5136 e->item = strdup("-");
\r
5137 e->command = NULL;
\r
5141 char *q, *r, *s, *t;
\r
5143 q = strchr(p, ',');
\r
5144 if (q == NULL) break;
\r
5146 r = strchr(q + 1, ',');
\r
5147 if (r == NULL) break;
\r
5149 s = strchr(r + 1, ',');
\r
5150 if (s == NULL) break;
\r
5153 t = strchr(s + 1, c);
\r
5156 t = strchr(s + 1, c);
\r
5158 if (t != NULL) *t = NULLCHAR;
\r
5159 e->item = strdup(p);
\r
5160 e->command = strdup(q + 1);
\r
5161 e->getname = *(r + 1) != '0';
\r
5162 e->immediate = *(s + 1) != '0';
\r
5166 if (t == NULL) break;
\r
5175 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
5179 hmenu = LoadMenu(hInst, "TextMenu");
\r
5180 h = GetSubMenu(hmenu, 0);
\r
5182 if (strcmp(e->item, "-") == 0) {
\r
5183 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
5185 if (e->item[0] == '|') {
\r
5186 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
5187 IDM_CommandX + i, &e->item[1]);
\r
5189 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
5198 WNDPROC consoleTextWindowProc;
\r
5201 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
5203 char buf[MSG_SIZ], name[MSG_SIZ];
\r
5204 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5208 SetWindowText(hInput, command);
\r
5210 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5212 sel.cpMin = 999999;
\r
5213 sel.cpMax = 999999;
\r
5214 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5219 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5220 if (sel.cpMin == sel.cpMax) {
\r
5221 /* Expand to surrounding word */
\r
5224 tr.chrg.cpMax = sel.cpMin;
\r
5225 tr.chrg.cpMin = --sel.cpMin;
\r
5226 if (sel.cpMin < 0) break;
\r
5227 tr.lpstrText = name;
\r
5228 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5229 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5233 tr.chrg.cpMin = sel.cpMax;
\r
5234 tr.chrg.cpMax = ++sel.cpMax;
\r
5235 tr.lpstrText = name;
\r
5236 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
5237 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5240 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5241 MessageBeep(MB_ICONEXCLAMATION);
\r
5245 tr.lpstrText = name;
\r
5246 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5248 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5249 MessageBeep(MB_ICONEXCLAMATION);
\r
5252 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
5255 sprintf(buf, "%s %s", command, name);
\r
5256 SetWindowText(hInput, buf);
\r
5257 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5259 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
5260 SetWindowText(hInput, buf);
\r
5261 sel.cpMin = 999999;
\r
5262 sel.cpMax = 999999;
\r
5263 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5269 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5274 switch (message) {
\r
5276 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5279 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
5282 sel.cpMin = 999999;
\r
5283 sel.cpMax = 999999;
\r
5284 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5285 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
5290 if (wParam == '\t') {
\r
5291 if (GetKeyState(VK_SHIFT) < 0) {
\r
5293 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5294 if (buttonDesc[0].hwnd) {
\r
5295 SetFocus(buttonDesc[0].hwnd);
\r
5297 SetFocus(hwndMain);
\r
5301 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
5304 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5306 SendMessage(hInput, message, wParam, lParam);
\r
5310 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5312 return SendMessage(hInput, message, wParam, lParam);
\r
5313 case WM_MBUTTONDOWN:
\r
5314 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5315 case WM_RBUTTONDOWN:
\r
5316 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
5317 /* Move selection here if it was empty */
\r
5319 pt.x = LOWORD(lParam);
\r
5320 pt.y = HIWORD(lParam);
\r
5321 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5322 if (sel.cpMin == sel.cpMax) {
\r
5323 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
5324 sel.cpMax = sel.cpMin;
\r
5325 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5327 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
5330 case WM_RBUTTONUP:
\r
5331 if (GetKeyState(VK_SHIFT) & ~1) {
\r
5332 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5333 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5336 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
5337 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5338 if (sel.cpMin == sel.cpMax) {
\r
5339 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
5340 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
5342 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
5343 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
5345 pt.x = LOWORD(lParam);
\r
5346 pt.y = HIWORD(lParam);
\r
5347 MenuPopup(hwnd, pt, hmenu, -1);
\r
5351 switch (LOWORD(wParam)) {
\r
5352 case IDM_QuickPaste:
\r
5354 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5355 if (sel.cpMin == sel.cpMax) {
\r
5356 MessageBeep(MB_ICONEXCLAMATION);
\r
5359 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5360 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5361 SendMessage(hInput, WM_PASTE, 0, 0);
\r
5366 SendMessage(hwnd, WM_CUT, 0, 0);
\r
5369 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
5372 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5376 int i = LOWORD(wParam) - IDM_CommandX;
\r
5377 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
5378 icsTextMenuEntry[i].command != NULL) {
\r
5379 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
5380 icsTextMenuEntry[i].getname,
\r
5381 icsTextMenuEntry[i].immediate);
\r
5389 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
5392 WNDPROC consoleInputWindowProc;
\r
5395 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5397 char buf[MSG_SIZ];
\r
5399 static BOOL sendNextChar = FALSE;
\r
5400 static BOOL quoteNextChar = FALSE;
\r
5401 InputSource *is = consoleInputSource;
\r
5405 switch (message) {
\r
5407 if (!appData.localLineEditing || sendNextChar) {
\r
5408 is->buf[0] = (CHAR) wParam;
\r
5410 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5411 sendNextChar = FALSE;
\r
5414 if (quoteNextChar) {
\r
5415 buf[0] = (char) wParam;
\r
5416 buf[1] = NULLCHAR;
\r
5417 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
5418 quoteNextChar = FALSE;
\r
5422 case '\r': /* Enter key */
\r
5423 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
5424 if (consoleEcho) SaveInHistory(is->buf);
\r
5425 is->buf[is->count++] = '\n';
\r
5426 is->buf[is->count] = NULLCHAR;
\r
5427 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5428 if (consoleEcho) {
\r
5429 ConsoleOutput(is->buf, is->count, TRUE);
\r
5430 } else if (appData.localLineEditing) {
\r
5431 ConsoleOutput("\n", 1, TRUE);
\r
5434 case '\033': /* Escape key */
\r
5435 SetWindowText(hwnd, "");
\r
5436 cf.cbSize = sizeof(CHARFORMAT);
\r
5437 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
5438 if (consoleEcho) {
\r
5439 cf.crTextColor = textAttribs[ColorNormal].color;
\r
5441 cf.crTextColor = COLOR_ECHOOFF;
\r
5443 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
5444 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
5446 case '\t': /* Tab key */
\r
5447 if (GetKeyState(VK_SHIFT) < 0) {
\r
5449 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
5452 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5453 if (buttonDesc[0].hwnd) {
\r
5454 SetFocus(buttonDesc[0].hwnd);
\r
5456 SetFocus(hwndMain);
\r
5460 case '\023': /* Ctrl+S */
\r
5461 sendNextChar = TRUE;
\r
5463 case '\021': /* Ctrl+Q */
\r
5464 quoteNextChar = TRUE;
\r
5473 GetWindowText(hwnd, buf, MSG_SIZ);
\r
5474 p = PrevInHistory(buf);
\r
5476 SetWindowText(hwnd, p);
\r
5477 sel.cpMin = 999999;
\r
5478 sel.cpMax = 999999;
\r
5479 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5484 p = NextInHistory();
\r
5486 SetWindowText(hwnd, p);
\r
5487 sel.cpMin = 999999;
\r
5488 sel.cpMax = 999999;
\r
5489 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5495 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5499 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
5503 case WM_MBUTTONDOWN:
\r
5504 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5505 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5507 case WM_RBUTTONUP:
\r
5508 if (GetKeyState(VK_SHIFT) & ~1) {
\r
5509 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5510 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5514 hmenu = LoadMenu(hInst, "InputMenu");
\r
5515 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5516 if (sel.cpMin == sel.cpMax) {
\r
5517 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
5518 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
5520 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
5521 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
5523 pt.x = LOWORD(lParam);
\r
5524 pt.y = HIWORD(lParam);
\r
5525 MenuPopup(hwnd, pt, hmenu, -1);
\r
5529 switch (LOWORD(wParam)) {
\r
5531 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
5533 case IDM_SelectAll:
\r
5535 sel.cpMax = -1; /*999999?*/
\r
5536 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5539 SendMessage(hwnd, WM_CUT, 0, 0);
\r
5542 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
5545 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5550 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
5553 #define CO_MAX 100000
\r
5554 #define CO_TRIM 1000
\r
5557 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5559 static HWND hText, hInput, hFocus;
\r
5560 InputSource *is = consoleInputSource;
\r
5562 static int sizeX, sizeY;
\r
5563 int newSizeX, newSizeY;
\r
5566 switch (message) {
\r
5567 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5568 hwndConsole = hDlg;
\r
5569 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
5570 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
5572 consoleTextWindowProc = (WNDPROC)
\r
5573 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
5574 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
5575 consoleInputWindowProc = (WNDPROC)
\r
5576 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
5577 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
5578 Colorize(ColorNormal, TRUE);
\r
5579 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
5580 ChangedConsoleFont();
\r
5581 GetClientRect(hDlg, &rect);
\r
5582 sizeX = rect.right;
\r
5583 sizeY = rect.bottom;
\r
5584 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
5585 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
5586 WINDOWPLACEMENT wp;
\r
5587 EnsureOnScreen(&consoleX, &consoleY);
\r
5588 wp.length = sizeof(WINDOWPLACEMENT);
\r
5590 wp.showCmd = SW_SHOW;
\r
5591 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
5592 wp.rcNormalPosition.left = consoleX;
\r
5593 wp.rcNormalPosition.right = consoleX + consoleW;
\r
5594 wp.rcNormalPosition.top = consoleY;
\r
5595 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
5596 SetWindowPlacement(hDlg, &wp);
\r
5610 if (IsIconic(hDlg)) break;
\r
5611 newSizeX = LOWORD(lParam);
\r
5612 newSizeY = HIWORD(lParam);
\r
5613 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
5614 RECT rectText, rectInput;
\r
5616 int newTextHeight, newTextWidth;
\r
5617 GetWindowRect(hText, &rectText);
\r
5618 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5619 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5620 if (newTextHeight < 0) {
\r
5621 newSizeY += -newTextHeight;
\r
5622 newTextHeight = 0;
\r
5624 SetWindowPos(hText, NULL, 0, 0,
\r
5625 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5626 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
5627 pt.x = rectInput.left;
\r
5628 pt.y = rectInput.top + newSizeY - sizeY;
\r
5629 ScreenToClient(hDlg, &pt);
\r
5630 SetWindowPos(hInput, NULL,
\r
5631 pt.x, pt.y, /* needs client coords */
\r
5632 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
5633 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
5639 case WM_GETMINMAXINFO:
\r
5640 /* Prevent resizing window too small */
\r
5641 mmi = (MINMAXINFO *) lParam;
\r
5642 mmi->ptMinTrackSize.x = 100;
\r
5643 mmi->ptMinTrackSize.y = 100;
\r
5646 return DefWindowProc(hDlg, message, wParam, lParam);
\r
5654 if (hwndConsole) return;
\r
5655 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
5656 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
5661 ConsoleOutput(char* data, int length, int forceVisible)
\r
5666 char buf[CO_MAX+1];
\r
5669 static int delayLF = 0;
\r
5670 CHARRANGE savesel, sel;
\r
5672 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
5680 while (length--) {
\r
5688 } else if (*p == '\007') {
\r
5689 MyPlaySound(&sounds[(int)SoundBell]);
\r
5696 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5697 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
5698 /* Save current selection */
\r
5699 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
5700 exlen = GetWindowTextLength(hText);
\r
5701 /* Find out whether current end of text is visible */
\r
5702 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
5703 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
5704 /* Trim existing text if it's too long */
\r
5705 if (exlen + (q - buf) > CO_MAX) {
\r
5706 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
5709 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5710 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
5712 savesel.cpMin -= trim;
\r
5713 savesel.cpMax -= trim;
\r
5714 if (exlen < 0) exlen = 0;
\r
5715 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
5716 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
5718 /* Append the new text */
\r
5719 sel.cpMin = exlen;
\r
5720 sel.cpMax = exlen;
\r
5721 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5722 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
5723 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
5724 if (forceVisible || exlen == 0 ||
\r
5725 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
5726 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
5727 /* Scroll to make new end of text visible if old end of text
\r
5728 was visible or new text is an echo of user typein */
\r
5729 sel.cpMin = 9999999;
\r
5730 sel.cpMax = 9999999;
\r
5731 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5732 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
5733 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
5734 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
5736 if (savesel.cpMax == exlen || forceVisible) {
\r
5737 /* Move insert point to new end of text if it was at the old
\r
5738 end of text or if the new text is an echo of user typein */
\r
5739 sel.cpMin = 9999999;
\r
5740 sel.cpMax = 9999999;
\r
5741 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5743 /* Restore previous selection */
\r
5744 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
5746 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
5753 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
5754 RECT *rect, char *color)
\r
5758 COLORREF oldFg, oldBg;
\r
5761 if (appData.clockMode) {
\r
5763 sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));
\r
5765 sprintf(buf, "%s: %s", color, TimeString(timeRemaining));
\r
5772 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
5773 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
5775 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
5776 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
5778 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
5780 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
5781 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
5782 rect, str, strlen(str), NULL);
\r
5784 (void) SetTextColor(hdc, oldFg);
\r
5785 (void) SetBkColor(hdc, oldBg);
\r
5786 (void) SelectObject(hdc, oldFont);
\r
5791 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
5796 ResetEvent(ovl->hEvent);
\r
5797 ovl->Offset = ovl->OffsetHigh = 0;
\r
5798 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
5802 err = GetLastError();
\r
5803 if (err == ERROR_IO_PENDING) {
\r
5804 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
5808 err = GetLastError();
\r
5815 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
5820 ResetEvent(ovl->hEvent);
\r
5821 ovl->Offset = ovl->OffsetHigh = 0;
\r
5822 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
5826 err = GetLastError();
\r
5827 if (err == ERROR_IO_PENDING) {
\r
5828 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
5832 err = GetLastError();
\r
5840 InputThread(LPVOID arg)
\r
5845 is = (InputSource *) arg;
\r
5846 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
5847 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
5848 while (is->hThread != NULL) {
\r
5849 is->error = DoReadFile(is->hFile, is->next,
\r
5850 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
5851 &is->count, &ovl);
\r
5852 if (is->error == NO_ERROR) {
\r
5853 is->next += is->count;
\r
5855 if (is->error == ERROR_BROKEN_PIPE) {
\r
5856 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
5859 is->count = (DWORD) -1;
\r
5862 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5863 if (is->count <= 0) break; /* Quit on EOF or error */
\r
5865 CloseHandle(ovl.hEvent);
\r
5866 CloseHandle(is->hFile);
\r
5871 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
5873 NonOvlInputThread(LPVOID arg)
\r
5880 is = (InputSource *) arg;
\r
5881 while (is->hThread != NULL) {
\r
5882 is->error = ReadFile(is->hFile, is->next,
\r
5883 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
5884 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
5885 if (is->error == NO_ERROR) {
\r
5886 /* Change CRLF to LF */
\r
5887 if (is->next > is->buf) {
\r
5889 i = is->count + 1;
\r
5897 if (prev == '\r' && *p == '\n') {
\r
5909 if (is->error == ERROR_BROKEN_PIPE) {
\r
5910 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
5913 is->count = (DWORD) -1;
\r
5916 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5917 if (is->count < 0) break; /* Quit on error */
\r
5919 CloseHandle(is->hFile);
\r
5924 SocketInputThread(LPVOID arg)
\r
5928 is = (InputSource *) arg;
\r
5929 while (is->hThread != NULL) {
\r
5930 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
5931 if ((int)is->count == SOCKET_ERROR) {
\r
5932 is->count = (DWORD) -1;
\r
5933 is->error = WSAGetLastError();
\r
5935 is->error = NO_ERROR;
\r
5936 is->next += is->count;
\r
5937 if (is->count == 0 && is->second == is) {
\r
5938 /* End of file on stderr; quit with no message */
\r
5942 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5943 if (is->count <= 0) break; /* Quit on EOF or error */
\r
5949 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5953 is = (InputSource *) lParam;
\r
5954 if (is->lineByLine) {
\r
5955 /* Feed in lines one by one */
\r
5956 char *p = is->buf;
\r
5958 while (q < is->next) {
\r
5959 if (*q++ == '\n') {
\r
5960 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
5964 /* Move any partial line to the start of the buffer */
\r
5966 while (p < is->next) {
\r
5970 if (is->error != NO_ERROR || is->count == 0) {
\r
5971 /* Notify backend of the error. Note: If there was a partial
\r
5972 line at the end, it is not flushed through. */
\r
5973 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
5976 /* Feed in the whole chunk of input at once */
\r
5977 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
5978 is->next = is->buf;
\r
5982 /*---------------------------------------------------------------------------*\
\r
5984 * Menu enables. Used when setting various modes.
\r
5986 \*---------------------------------------------------------------------------*/
\r
5994 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
5996 while (enab->item > 0) {
\r
5997 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
6002 Enables gnuEnables[] = {
\r
6003 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6004 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6005 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
6006 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
6007 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
6008 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
6009 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6010 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
6011 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
6012 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
6016 Enables icsEnables[] = {
\r
6017 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6018 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6019 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6020 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6021 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6022 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
6023 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
6024 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
6025 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6026 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
6027 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
6028 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
6033 Enables zippyEnables[] = {
\r
6034 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6035 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
6036 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
6041 Enables ncpEnables[] = {
\r
6042 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6043 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6044 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6045 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6046 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6047 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
6048 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
6049 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
6050 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
6051 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
6052 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6053 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6054 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
6055 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
6056 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
6060 Enables trainingOnEnables[] = {
\r
6061 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
6062 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
6063 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
6064 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
6065 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
6066 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
6067 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6068 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
6072 Enables trainingOffEnables[] = {
\r
6073 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
6074 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
6075 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
6076 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
6077 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
6078 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
6079 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6080 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
6084 /* These modify either ncpEnables or gnuEnables */
\r
6085 Enables cmailEnables[] = {
\r
6086 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
6087 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
6088 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
6089 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
6090 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
6091 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6092 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
6096 Enables machineThinkingEnables[] = {
\r
6097 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6098 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
6099 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
6100 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6101 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
6102 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6103 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6104 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6105 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6106 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
6107 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6108 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6109 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6110 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
6111 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6115 Enables userThinkingEnables[] = {
\r
6116 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6117 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
6118 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
6119 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6120 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
6121 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6122 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6123 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6124 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6125 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
6126 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
6127 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
6128 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
6129 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
6130 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
6134 /*---------------------------------------------------------------------------*\
\r
6136 * Front-end interface functions exported by XBoard.
\r
6137 * Functions appear in same order as prototypes in frontend.h.
\r
6139 \*---------------------------------------------------------------------------*/
\r
6143 static UINT prevChecked = 0;
\r
6144 static int prevPausing = 0;
\r
6147 if (pausing != prevPausing) {
\r
6148 prevPausing = pausing;
\r
6149 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
6150 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
6151 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
6154 switch (gameMode) {
\r
6155 case BeginningOfGame:
\r
6156 if (appData.icsActive)
\r
6157 nowChecked = IDM_IcsClient;
\r
6158 else if (appData.noChessProgram)
\r
6159 nowChecked = IDM_EditGame;
\r
6161 nowChecked = IDM_MachineBlack;
\r
6163 case MachinePlaysBlack:
\r
6164 nowChecked = IDM_MachineBlack;
\r
6166 case MachinePlaysWhite:
\r
6167 nowChecked = IDM_MachineWhite;
\r
6169 case TwoMachinesPlay:
\r
6170 nowChecked = IDM_TwoMachines;
\r
6173 nowChecked = IDM_AnalysisMode;
\r
6176 nowChecked = IDM_AnalyzeFile;
\r
6179 nowChecked = IDM_EditGame;
\r
6181 case PlayFromGameFile:
\r
6182 nowChecked = IDM_LoadGame;
\r
6184 case EditPosition:
\r
6185 nowChecked = IDM_EditPosition;
\r
6188 nowChecked = IDM_Training;
\r
6190 case IcsPlayingWhite:
\r
6191 case IcsPlayingBlack:
\r
6192 case IcsObserving:
\r
6194 nowChecked = IDM_IcsClient;
\r
6201 if (prevChecked != 0)
\r
6202 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6203 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
6204 if (nowChecked != 0)
\r
6205 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6206 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
6208 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
6209 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
6210 MF_BYCOMMAND|MF_ENABLED);
\r
6212 (void) EnableMenuItem(GetMenu(hwndMain),
\r
6213 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
6216 prevChecked = nowChecked;
\r
6222 HMENU hmenu = GetMenu(hwndMain);
\r
6223 SetMenuEnables(hmenu, icsEnables);
\r
6224 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
6225 MF_BYPOSITION|MF_ENABLED);
\r
6227 if (appData.zippyPlay) {
\r
6228 SetMenuEnables(hmenu, zippyEnables);
\r
6236 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
6242 HMENU hmenu = GetMenu(hwndMain);
\r
6243 SetMenuEnables(hmenu, ncpEnables);
\r
6244 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
6245 MF_BYPOSITION|MF_GRAYED);
\r
6246 DrawMenuBar(hwndMain);
\r
6252 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
6256 SetTrainingModeOn()
\r
6259 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
6260 for (i = 0; i < N_BUTTONS; i++) {
\r
6261 if (buttonDesc[i].hwnd != NULL)
\r
6262 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
6267 VOID SetTrainingModeOff()
\r
6270 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
6271 for (i = 0; i < N_BUTTONS; i++) {
\r
6272 if (buttonDesc[i].hwnd != NULL)
\r
6273 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
6279 SetUserThinkingEnables()
\r
6281 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
6285 SetMachineThinkingEnables()
\r
6287 HMENU hMenu = GetMenu(hwndMain);
\r
6288 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
6290 SetMenuEnables(hMenu, machineThinkingEnables);
\r
6292 if (gameMode == MachinePlaysBlack) {
\r
6293 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
6294 } else if (gameMode == MachinePlaysWhite) {
\r
6295 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
6296 } else if (gameMode == TwoMachinesPlay) {
\r
6297 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
6303 DisplayTitle(char *str)
\r
6305 char title[MSG_SIZ], *host;
\r
6306 if (str[0] != NULLCHAR) {
\r
6307 strcpy(title, str);
\r
6308 } else if (appData.icsActive) {
\r
6309 if (appData.icsCommPort[0] != NULLCHAR)
\r
6312 host = appData.icsHost;
\r
6313 sprintf(title, "%s: %s", szTitle, host);
\r
6314 } else if (appData.noChessProgram) {
\r
6315 strcpy(title, szTitle);
\r
6317 strcpy(title, szTitle);
\r
6318 strcat(title, ": ");
\r
6319 strcat(title, first.tidy);
\r
6321 SetWindowText(hwndMain, title);
\r
6326 DisplayMessage(char *str1, char *str2)
\r
6330 int remain = MESSAGE_TEXT_MAX - 1;
\r
6333 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
6334 messageText[0] = NULLCHAR;
\r
6336 len = strlen(str1);
\r
6337 if (len > remain) len = remain;
\r
6338 strncpy(messageText, str1, len);
\r
6339 messageText[len] = NULLCHAR;
\r
6342 if (*str2 && remain >= 2) {
\r
6344 strcat(messageText, " ");
\r
6347 len = strlen(str2);
\r
6348 if (len > remain) len = remain;
\r
6349 strncat(messageText, str2, len);
\r
6351 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
6353 if (IsIconic(hwndMain)) return;
\r
6354 hdc = GetDC(hwndMain);
\r
6355 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
6356 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
6357 &messageRect, messageText, strlen(messageText), NULL);
\r
6358 (void) SelectObject(hdc, oldFont);
\r
6359 (void) ReleaseDC(hwndMain, hdc);
\r
6363 DisplayError(char *str, int error)
\r
6365 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
6371 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
6372 NULL, error, LANG_NEUTRAL,
\r
6373 (LPSTR) buf2, MSG_SIZ, NULL);
\r
6375 sprintf(buf, "%s:\n%s", str, buf2);
\r
6377 ErrorMap *em = errmap;
\r
6378 while (em->err != 0 && em->err != error) em++;
\r
6379 if (em->err != 0) {
\r
6380 sprintf(buf, "%s:\n%s", str, em->msg);
\r
6382 sprintf(buf, "%s:\nError code %d", str, error);
\r
6387 ErrorPopUp("Error", buf);
\r
6392 DisplayMoveError(char *str)
\r
6394 fromX = fromY = -1;
\r
6395 ClearHighlights();
\r
6396 DrawPosition(FALSE, NULL);
\r
6397 if (appData.popupMoveErrors) {
\r
6398 ErrorPopUp("Error", str);
\r
6400 DisplayMessage(str, "");
\r
6401 moveErrorMessageUp = TRUE;
\r
6406 DisplayFatalError(char *str, int error, int exitStatus)
\r
6408 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
6410 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
6413 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
6414 NULL, error, LANG_NEUTRAL,
\r
6415 (LPSTR) buf2, MSG_SIZ, NULL);
\r
6417 sprintf(buf, "%s:\n%s", str, buf2);
\r
6419 ErrorMap *em = errmap;
\r
6420 while (em->err != 0 && em->err != error) em++;
\r
6421 if (em->err != 0) {
\r
6422 sprintf(buf, "%s:\n%s", str, em->msg);
\r
6424 sprintf(buf, "%s:\nError code %d", str, error);
\r
6429 if (appData.debugMode) {
\r
6430 fprintf(debugFP, "%s: %s\n", label, str);
\r
6432 if (appData.popupExitMessage) {
\r
6433 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
6434 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
6436 ExitEvent(exitStatus);
\r
6441 DisplayInformation(char *str)
\r
6443 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
6448 DisplayNote(char *str)
\r
6450 ErrorPopUp("Note", str);
\r
6455 char *title, *question, *replyPrefix;
\r
6460 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6462 static QuestionParams *qp;
\r
6463 char reply[MSG_SIZ];
\r
6466 switch (message) {
\r
6467 case WM_INITDIALOG:
\r
6468 qp = (QuestionParams *) lParam;
\r
6469 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
6470 SetWindowText(hDlg, qp->title);
\r
6471 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
6472 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
6476 switch (LOWORD(wParam)) {
\r
6478 strcpy(reply, qp->replyPrefix);
\r
6479 if (*reply) strcat(reply, " ");
\r
6480 len = strlen(reply);
\r
6481 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
6482 strcat(reply, "\n");
\r
6483 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
6484 EndDialog(hDlg, TRUE);
\r
6485 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
6488 EndDialog(hDlg, FALSE);
\r
6499 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
6501 QuestionParams qp;
\r
6505 qp.question = question;
\r
6506 qp.replyPrefix = replyPrefix;
\r
6508 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
6509 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
6510 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
6511 FreeProcInstance(lpProc);
\r
6516 DisplayIcsInteractionTitle(char *str)
\r
6518 char consoleTitle[MSG_SIZ];
\r
6520 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
6521 SetWindowText(hwndConsole, consoleTitle);
\r
6525 DrawPosition(int fullRedraw, Board board)
\r
6527 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
6534 fromX = fromY = -1;
\r
6535 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
6536 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
6537 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
6538 dragInfo.lastpos = dragInfo.pos;
\r
6539 dragInfo.start.x = dragInfo.start.y = -1;
\r
6540 dragInfo.from = dragInfo.start;
\r
6542 DrawPosition(TRUE, NULL);
\r
6548 CommentPopUp(char *title, char *str)
\r
6550 HWND hwnd = GetActiveWindow();
\r
6551 EitherCommentPopUp(0, title, str, FALSE);
\r
6552 SetActiveWindow(hwnd);
\r
6556 CommentPopDown(void)
\r
6558 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
6559 if (commentDialog) {
\r
6560 ShowWindow(commentDialog, SW_HIDE);
\r
6562 commentDialogUp = FALSE;
\r
6566 EditCommentPopUp(int index, char *title, char *str)
\r
6568 EitherCommentPopUp(index, title, str, TRUE);
\r
6575 MyPlaySound(&sounds[(int)SoundMove]);
\r
6578 VOID PlayIcsWinSound()
\r
6580 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
6583 VOID PlayIcsLossSound()
\r
6585 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
6588 VOID PlayIcsDrawSound()
\r
6590 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
6593 VOID PlayIcsUnfinishedSound()
\r
6595 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
6601 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
6609 consoleEcho = TRUE;
\r
6610 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6611 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
6612 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6621 consoleEcho = FALSE;
\r
6622 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6623 /* This works OK: set text and background both to the same color */
\r
6625 cf.crTextColor = COLOR_ECHOOFF;
\r
6626 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6627 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
6630 /* No Raw()...? */
\r
6632 void Colorize(ColorClass cc, int continuation)
\r
6634 currentColorClass = cc;
\r
6635 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6636 consoleCF.crTextColor = textAttribs[cc].color;
\r
6637 consoleCF.dwEffects = textAttribs[cc].effects;
\r
6638 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
6644 static char buf[MSG_SIZ];
\r
6645 DWORD bufsiz = MSG_SIZ;
\r
6647 if (!GetUserName(buf, &bufsiz)) {
\r
6648 /*DisplayError("Error getting user name", GetLastError());*/
\r
6649 strcpy(buf, "User");
\r
6657 static char buf[MSG_SIZ];
\r
6658 DWORD bufsiz = MSG_SIZ;
\r
6660 if (!GetComputerName(buf, &bufsiz)) {
\r
6661 /*DisplayError("Error getting host name", GetLastError());*/
\r
6662 strcpy(buf, "Unknown");
\r
6669 ClockTimerRunning()
\r
6671 return clockTimerEvent != 0;
\r
6677 if (clockTimerEvent == 0) return FALSE;
\r
6678 KillTimer(hwndMain, clockTimerEvent);
\r
6679 clockTimerEvent = 0;
\r
6684 StartClockTimer(long millisec)
\r
6686 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
6687 (UINT) millisec, NULL);
\r
6691 DisplayWhiteClock(long timeRemaining, int highlight)
\r
6694 hdc = GetDC(hwndMain);
\r
6695 if (!IsIconic(hwndMain)) {
\r
6696 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");
\r
6698 if (highlight && iconCurrent == iconBlack) {
\r
6699 iconCurrent = iconWhite;
\r
6700 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6701 if (IsIconic(hwndMain)) {
\r
6702 DrawIcon(hdc, 2, 2, iconCurrent);
\r
6705 (void) ReleaseDC(hwndMain, hdc);
\r
6707 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6711 DisplayBlackClock(long timeRemaining, int highlight)
\r
6714 hdc = GetDC(hwndMain);
\r
6715 if (!IsIconic(hwndMain)) {
\r
6716 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");
\r
6718 if (highlight && iconCurrent == iconWhite) {
\r
6719 iconCurrent = iconBlack;
\r
6720 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6721 if (IsIconic(hwndMain)) {
\r
6722 DrawIcon(hdc, 2, 2, iconCurrent);
\r
6725 (void) ReleaseDC(hwndMain, hdc);
\r
6727 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6732 LoadGameTimerRunning()
\r
6734 return loadGameTimerEvent != 0;
\r
6738 StopLoadGameTimer()
\r
6740 if (loadGameTimerEvent == 0) return FALSE;
\r
6741 KillTimer(hwndMain, loadGameTimerEvent);
\r
6742 loadGameTimerEvent = 0;
\r
6747 StartLoadGameTimer(long millisec)
\r
6749 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
6750 (UINT) millisec, NULL);
\r
6758 char fileTitle[MSG_SIZ];
\r
6760 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
6761 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
6762 appData.oldSaveStyle ? "gam" : "pgn",
\r
6764 "Save Game to File", NULL, fileTitle, NULL);
\r
6766 SaveGame(f, 0, "");
\r
6773 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
6775 if (delayedTimerEvent != 0) {
\r
6776 if (appData.debugMode) {
\r
6777 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
6779 KillTimer(hwndMain, delayedTimerEvent);
\r
6780 delayedTimerEvent = 0;
\r
6781 delayedTimerCallback();
\r
6783 delayedTimerCallback = cb;
\r
6784 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
6785 (UINT) millisec, NULL);
\r
6788 DelayedEventCallback
\r
6791 if (delayedTimerEvent) {
\r
6792 return delayedTimerCallback;
\r
6799 CancelDelayedEvent()
\r
6801 if (delayedTimerEvent) {
\r
6802 KillTimer(hwndMain, delayedTimerEvent);
\r
6803 delayedTimerEvent = 0;
\r
6807 /* Start a child process running the given program.
\r
6808 The process's standard output can be read from "from", and its
\r
6809 standard input can be written to "to".
\r
6810 Exit with fatal error if anything goes wrong.
\r
6811 Returns an opaque pointer that can be used to destroy the process
\r
6815 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
6817 #define BUFSIZE 4096
\r
6819 HANDLE hChildStdinRd, hChildStdinWr,
\r
6820 hChildStdoutRd, hChildStdoutWr;
\r
6821 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
6822 SECURITY_ATTRIBUTES saAttr;
\r
6824 PROCESS_INFORMATION piProcInfo;
\r
6825 STARTUPINFO siStartInfo;
\r
6827 char buf[MSG_SIZ];
\r
6830 if (appData.debugMode) {
\r
6831 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
6836 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
6837 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
6838 saAttr.bInheritHandle = TRUE;
\r
6839 saAttr.lpSecurityDescriptor = NULL;
\r
6842 * The steps for redirecting child's STDOUT:
\r
6843 * 1. Create anonymous pipe to be STDOUT for child.
\r
6844 * 2. Create a noninheritable duplicate of read handle,
\r
6845 * and close the inheritable read handle.
\r
6848 /* Create a pipe for the child's STDOUT. */
\r
6849 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
6850 return GetLastError();
\r
6853 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
6854 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
6855 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
6856 FALSE, /* not inherited */
\r
6857 DUPLICATE_SAME_ACCESS);
\r
6859 return GetLastError();
\r
6861 CloseHandle(hChildStdoutRd);
\r
6864 * The steps for redirecting child's STDIN:
\r
6865 * 1. Create anonymous pipe to be STDIN for child.
\r
6866 * 2. Create a noninheritable duplicate of write handle,
\r
6867 * and close the inheritable write handle.
\r
6870 /* Create a pipe for the child's STDIN. */
\r
6871 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
6872 return GetLastError();
\r
6875 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
6876 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
6877 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
6878 FALSE, /* not inherited */
\r
6879 DUPLICATE_SAME_ACCESS);
\r
6881 return GetLastError();
\r
6883 CloseHandle(hChildStdinWr);
\r
6885 /* Arrange to (1) look in dir for the child .exe file, and
\r
6886 * (2) have dir be the child's working directory. Interpret
\r
6887 * dir relative to the directory WinBoard loaded from. */
\r
6888 GetCurrentDirectory(MSG_SIZ, buf);
\r
6889 SetCurrentDirectory(installDir);
\r
6890 SetCurrentDirectory(dir);
\r
6892 /* Now create the child process. */
\r
6894 siStartInfo.cb = sizeof(STARTUPINFO);
\r
6895 siStartInfo.lpReserved = NULL;
\r
6896 siStartInfo.lpDesktop = NULL;
\r
6897 siStartInfo.lpTitle = NULL;
\r
6898 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
6899 siStartInfo.cbReserved2 = 0;
\r
6900 siStartInfo.lpReserved2 = NULL;
\r
6901 siStartInfo.hStdInput = hChildStdinRd;
\r
6902 siStartInfo.hStdOutput = hChildStdoutWr;
\r
6903 siStartInfo.hStdError = hChildStdoutWr;
\r
6905 fSuccess = CreateProcess(NULL,
\r
6906 cmdLine, /* command line */
\r
6907 NULL, /* process security attributes */
\r
6908 NULL, /* primary thread security attrs */
\r
6909 TRUE, /* handles are inherited */
\r
6910 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
6911 NULL, /* use parent's environment */
\r
6913 &siStartInfo, /* STARTUPINFO pointer */
\r
6914 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
6916 err = GetLastError();
\r
6917 SetCurrentDirectory(buf); /* return to prev directory */
\r
6922 /* Close the handles we don't need in the parent */
\r
6923 CloseHandle(piProcInfo.hThread);
\r
6924 CloseHandle(hChildStdinRd);
\r
6925 CloseHandle(hChildStdoutWr);
\r
6927 /* Prepare return value */
\r
6928 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
6929 cp->kind = CPReal;
\r
6930 cp->hProcess = piProcInfo.hProcess;
\r
6931 cp->pid = piProcInfo.dwProcessId;
\r
6932 cp->hFrom = hChildStdoutRdDup;
\r
6933 cp->hTo = hChildStdinWrDup;
\r
6935 *pr = (void *) cp;
\r
6937 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
6938 2000 where engines sometimes don't see the initial command(s)
\r
6939 from WinBoard and hang. I don't understand how that can happen,
\r
6940 but the Sleep is harmless, so I've put it in. Others have also
\r
6941 reported what may be the same problem, so hopefully this will fix
\r
6942 it for them too. */
\r
6950 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
6954 cp = (ChildProc *) pr;
\r
6955 if (cp == NULL) return;
\r
6957 switch (cp->kind) {
\r
6959 /* TerminateProcess is considered harmful, so... */
\r
6960 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
6961 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
6962 /* The following doesn't work because the chess program
\r
6963 doesn't "have the same console" as WinBoard. Maybe
\r
6964 we could arrange for this even though neither WinBoard
\r
6965 nor the chess program uses a console for stdio? */
\r
6966 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
6967 CloseHandle(cp->hProcess);
\r
6971 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
6975 closesocket(cp->sock);
\r
6980 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
6981 closesocket(cp->sock);
\r
6982 closesocket(cp->sock2);
\r
6990 InterruptChildProcess(ProcRef pr)
\r
6994 cp = (ChildProc *) pr;
\r
6995 if (cp == NULL) return;
\r
6996 switch (cp->kind) {
\r
6998 /* The following doesn't work because the chess program
\r
6999 doesn't "have the same console" as WinBoard. Maybe
\r
7000 we could arrange for this even though neither WinBoard
\r
7001 nor the chess program uses a console for stdio */
\r
7002 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
7007 /* Can't interrupt */
\r
7011 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
7018 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
7020 char cmdLine[MSG_SIZ];
\r
7022 if (port[0] == NULLCHAR) {
\r
7023 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
7025 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
7027 return StartChildProcess(cmdLine, "", pr);
\r
7031 /* Code to open TCP sockets */
\r
7034 OpenTCP(char *host, char *port, ProcRef *pr)
\r
7039 struct sockaddr_in sa, mysa;
\r
7040 struct hostent FAR *hp;
\r
7041 unsigned short uport;
\r
7042 WORD wVersionRequested;
\r
7045 /* Initialize socket DLL */
\r
7046 wVersionRequested = MAKEWORD(1, 1);
\r
7047 err = WSAStartup(wVersionRequested, &wsaData);
\r
7048 if (err != 0) return err;
\r
7051 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7052 err = WSAGetLastError();
\r
7057 /* Bind local address using (mostly) don't-care values.
\r
7059 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7060 mysa.sin_family = AF_INET;
\r
7061 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7062 uport = (unsigned short) 0;
\r
7063 mysa.sin_port = htons(uport);
\r
7064 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7065 == SOCKET_ERROR) {
\r
7066 err = WSAGetLastError();
\r
7071 /* Resolve remote host name */
\r
7072 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7073 if (!(hp = gethostbyname(host))) {
\r
7074 unsigned int b0, b1, b2, b3;
\r
7076 err = WSAGetLastError();
\r
7078 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7079 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7080 hp->h_addrtype = AF_INET;
\r
7082 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7083 hp->h_addr_list[0] = (char *) malloc(4);
\r
7084 hp->h_addr_list[0][0] = (char) b0;
\r
7085 hp->h_addr_list[0][1] = (char) b1;
\r
7086 hp->h_addr_list[0][2] = (char) b2;
\r
7087 hp->h_addr_list[0][3] = (char) b3;
\r
7093 sa.sin_family = hp->h_addrtype;
\r
7094 uport = (unsigned short) atoi(port);
\r
7095 sa.sin_port = htons(uport);
\r
7096 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7098 /* Make connection */
\r
7099 if (connect(s, (struct sockaddr *) &sa,
\r
7100 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7101 err = WSAGetLastError();
\r
7106 /* Prepare return value */
\r
7107 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7108 cp->kind = CPSock;
\r
7110 *pr = (ProcRef *) cp;
\r
7116 OpenCommPort(char *name, ProcRef *pr)
\r
7121 char fullname[MSG_SIZ];
\r
7123 if (*name != '\\')
\r
7124 sprintf(fullname, "\\\\.\\%s", name);
\r
7126 strcpy(fullname, name);
\r
7128 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
7129 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
7130 if (h == (HANDLE) -1) {
\r
7131 return GetLastError();
\r
7135 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
7137 /* Accumulate characters until a 100ms pause, then parse */
\r
7138 ct.ReadIntervalTimeout = 100;
\r
7139 ct.ReadTotalTimeoutMultiplier = 0;
\r
7140 ct.ReadTotalTimeoutConstant = 0;
\r
7141 ct.WriteTotalTimeoutMultiplier = 0;
\r
7142 ct.WriteTotalTimeoutConstant = 0;
\r
7143 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
7145 /* Prepare return value */
\r
7146 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7147 cp->kind = CPComm;
\r
7150 *pr = (ProcRef *) cp;
\r
7156 OpenLoopback(ProcRef *pr)
\r
7158 DisplayFatalError("Not implemented", 0, 1);
\r
7164 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
7169 struct sockaddr_in sa, mysa;
\r
7170 struct hostent FAR *hp;
\r
7171 unsigned short uport;
\r
7172 WORD wVersionRequested;
\r
7175 char stderrPortStr[MSG_SIZ];
\r
7177 /* Initialize socket DLL */
\r
7178 wVersionRequested = MAKEWORD(1, 1);
\r
7179 err = WSAStartup(wVersionRequested, &wsaData);
\r
7180 if (err != 0) return err;
\r
7182 /* Resolve remote host name */
\r
7183 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7184 if (!(hp = gethostbyname(host))) {
\r
7185 unsigned int b0, b1, b2, b3;
\r
7187 err = WSAGetLastError();
\r
7189 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7190 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7191 hp->h_addrtype = AF_INET;
\r
7193 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7194 hp->h_addr_list[0] = (char *) malloc(4);
\r
7195 hp->h_addr_list[0][0] = (char) b0;
\r
7196 hp->h_addr_list[0][1] = (char) b1;
\r
7197 hp->h_addr_list[0][2] = (char) b2;
\r
7198 hp->h_addr_list[0][3] = (char) b3;
\r
7204 sa.sin_family = hp->h_addrtype;
\r
7205 uport = (unsigned short) 514;
\r
7206 sa.sin_port = htons(uport);
\r
7207 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7209 /* Bind local socket to unused "privileged" port address
\r
7211 s = INVALID_SOCKET;
\r
7212 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7213 mysa.sin_family = AF_INET;
\r
7214 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7215 for (fromPort = 1023;; fromPort--) {
\r
7216 if (fromPort < 0) {
\r
7218 return WSAEADDRINUSE;
\r
7220 if (s == INVALID_SOCKET) {
\r
7221 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7222 err = WSAGetLastError();
\r
7227 uport = (unsigned short) fromPort;
\r
7228 mysa.sin_port = htons(uport);
\r
7229 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7230 == SOCKET_ERROR) {
\r
7231 err = WSAGetLastError();
\r
7232 if (err == WSAEADDRINUSE) continue;
\r
7236 if (connect(s, (struct sockaddr *) &sa,
\r
7237 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7238 err = WSAGetLastError();
\r
7239 if (err == WSAEADDRINUSE) {
\r
7250 /* Bind stderr local socket to unused "privileged" port address
\r
7252 s2 = INVALID_SOCKET;
\r
7253 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7254 mysa.sin_family = AF_INET;
\r
7255 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7256 for (fromPort = 1023;; fromPort--) {
\r
7257 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
7258 if (fromPort < 0) {
\r
7259 (void) closesocket(s);
\r
7261 return WSAEADDRINUSE;
\r
7263 if (s2 == INVALID_SOCKET) {
\r
7264 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7265 err = WSAGetLastError();
\r
7271 uport = (unsigned short) fromPort;
\r
7272 mysa.sin_port = htons(uport);
\r
7273 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7274 == SOCKET_ERROR) {
\r
7275 err = WSAGetLastError();
\r
7276 if (err == WSAEADDRINUSE) continue;
\r
7277 (void) closesocket(s);
\r
7281 if (listen(s2, 1) == SOCKET_ERROR) {
\r
7282 err = WSAGetLastError();
\r
7283 if (err == WSAEADDRINUSE) {
\r
7285 s2 = INVALID_SOCKET;
\r
7288 (void) closesocket(s);
\r
7289 (void) closesocket(s2);
\r
7295 prevStderrPort = fromPort; // remember port used
\r
7296 sprintf(stderrPortStr, "%d", fromPort);
\r
7298 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
7299 err = WSAGetLastError();
\r
7300 (void) closesocket(s);
\r
7301 (void) closesocket(s2);
\r
7306 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
7307 err = WSAGetLastError();
\r
7308 (void) closesocket(s);
\r
7309 (void) closesocket(s2);
\r
7313 if (*user == NULLCHAR) user = UserName();
\r
7314 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
7315 err = WSAGetLastError();
\r
7316 (void) closesocket(s);
\r
7317 (void) closesocket(s2);
\r
7321 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
7322 err = WSAGetLastError();
\r
7323 (void) closesocket(s);
\r
7324 (void) closesocket(s2);
\r
7329 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
7330 err = WSAGetLastError();
\r
7331 (void) closesocket(s);
\r
7332 (void) closesocket(s2);
\r
7336 (void) closesocket(s2); /* Stop listening */
\r
7338 /* Prepare return value */
\r
7339 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7340 cp->kind = CPRcmd;
\r
7343 *pr = (ProcRef *) cp;
\r
7350 AddInputSource(ProcRef pr, int lineByLine,
\r
7351 InputCallback func, VOIDSTAR closure)
\r
7353 InputSource *is, *is2;
\r
7354 ChildProc *cp = (ChildProc *) pr;
\r
7356 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
7357 is->lineByLine = lineByLine;
\r
7359 is->closure = closure;
\r
7360 is->second = NULL;
\r
7361 is->next = is->buf;
\r
7362 if (pr == NoProc) {
\r
7363 is->kind = CPReal;
\r
7364 consoleInputSource = is;
\r
7366 is->kind = cp->kind;
\r
7367 switch (cp->kind) {
\r
7369 is->hFile = cp->hFrom;
\r
7370 cp->hFrom = NULL; /* now owned by InputThread */
\r
7372 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
7373 (LPVOID) is, 0, &is->id);
\r
7377 is->hFile = cp->hFrom;
\r
7378 cp->hFrom = NULL; /* now owned by InputThread */
\r
7380 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
7381 (LPVOID) is, 0, &is->id);
\r
7385 is->sock = cp->sock;
\r
7387 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7388 (LPVOID) is, 0, &is->id);
\r
7392 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
7394 is->sock = cp->sock;
\r
7396 is2->sock = cp->sock2;
\r
7397 is2->second = is2;
\r
7399 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7400 (LPVOID) is, 0, &is->id);
\r
7402 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7403 (LPVOID) is2, 0, &is2->id);
\r
7407 return (InputSourceRef) is;
\r
7411 RemoveInputSource(InputSourceRef isr)
\r
7415 is = (InputSource *) isr;
\r
7416 is->hThread = NULL; /* tell thread to stop */
\r
7417 CloseHandle(is->hThread);
\r
7418 if (is->second != NULL) {
\r
7419 is->second->hThread = NULL;
\r
7420 CloseHandle(is->second->hThread);
\r
7426 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
7429 int outCount = SOCKET_ERROR;
\r
7430 ChildProc *cp = (ChildProc *) pr;
\r
7431 static OVERLAPPED ovl;
\r
7433 if (pr == NoProc) {
\r
7434 ConsoleOutput(message, count, FALSE);
\r
7438 if (ovl.hEvent == NULL) {
\r
7439 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7441 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7443 switch (cp->kind) {
\r
7446 outCount = send(cp->sock, message, count, 0);
\r
7447 if (outCount == SOCKET_ERROR) {
\r
7448 *outError = WSAGetLastError();
\r
7450 *outError = NO_ERROR;
\r
7455 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
7456 &dOutCount, NULL)) {
\r
7457 *outError = NO_ERROR;
\r
7458 outCount = (int) dOutCount;
\r
7460 *outError = GetLastError();
\r
7465 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
7466 &dOutCount, &ovl);
\r
7467 if (*outError == NO_ERROR) {
\r
7468 outCount = (int) dOutCount;
\r
7476 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
7479 /* Ignore delay, not implemented for WinBoard */
\r
7480 return OutputToProcess(pr, message, count, outError);
\r
7485 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
7486 char *buf, int count, int error)
\r
7488 DisplayFatalError("Not implemented", 0, 1);
\r
7491 /* see wgamelist.c for Game List functions */
\r
7492 /* see wedittags.c for Edit Tags functions */
\r
7499 char buf[MSG_SIZ];
\r
7502 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
7503 f = fopen(buf, "r");
\r
7505 ProcessICSInitScript(f);
\r
7513 StartAnalysisClock()
\r
7515 if (analysisTimerEvent) return;
\r
7516 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
7517 (UINT) 2000, NULL);
\r
7521 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7523 static HANDLE hwndText;
\r
7525 static int sizeX, sizeY;
\r
7526 int newSizeX, newSizeY, flags;
\r
7529 switch (message) {
\r
7530 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7531 /* Initialize the dialog items */
\r
7532 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
7533 SetWindowText(hDlg, analysisTitle);
\r
7534 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
7535 /* Size and position the dialog */
\r
7536 if (!analysisDialog) {
\r
7537 analysisDialog = hDlg;
\r
7538 flags = SWP_NOZORDER;
\r
7539 GetClientRect(hDlg, &rect);
\r
7540 sizeX = rect.right;
\r
7541 sizeY = rect.bottom;
\r
7542 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
7543 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
7544 WINDOWPLACEMENT wp;
\r
7545 EnsureOnScreen(&analysisX, &analysisY);
\r
7546 wp.length = sizeof(WINDOWPLACEMENT);
\r
7548 wp.showCmd = SW_SHOW;
\r
7549 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7550 wp.rcNormalPosition.left = analysisX;
\r
7551 wp.rcNormalPosition.right = analysisX + analysisW;
\r
7552 wp.rcNormalPosition.top = analysisY;
\r
7553 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
7554 SetWindowPlacement(hDlg, &wp);
\r
7556 GetClientRect(hDlg, &rect);
\r
7557 newSizeX = rect.right;
\r
7558 newSizeY = rect.bottom;
\r
7559 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7560 newSizeX, newSizeY);
\r
7567 case WM_COMMAND: /* message: received a command */
\r
7568 switch (LOWORD(wParam)) {
\r
7578 newSizeX = LOWORD(lParam);
\r
7579 newSizeY = HIWORD(lParam);
\r
7580 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7585 case WM_GETMINMAXINFO:
\r
7586 /* Prevent resizing window too small */
\r
7587 mmi = (MINMAXINFO *) lParam;
\r
7588 mmi->ptMinTrackSize.x = 100;
\r
7589 mmi->ptMinTrackSize.y = 100;
\r
7596 AnalysisPopUp(char* title, char* str)
\r
7601 if (str == NULL) str = "";
\r
7602 p = (char *) malloc(2 * strlen(str) + 2);
\r
7605 if (*str == '\n') *q++ = '\r';
\r
7609 if (analysisText != NULL) free(analysisText);
\r
7612 if (analysisDialog) {
\r
7613 SetWindowText(analysisDialog, title);
\r
7614 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
7615 ShowWindow(analysisDialog, SW_SHOW);
\r
7617 analysisTitle = title;
\r
7618 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
7619 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
7620 hwndMain, (DLGPROC)lpProc);
\r
7621 FreeProcInstance(lpProc);
\r
7623 analysisDialogUp = TRUE;
\r
7629 if (analysisDialog) {
\r
7630 ShowWindow(analysisDialog, SW_HIDE);
\r
7632 analysisDialogUp = FALSE;
\r
7637 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
7639 highlightInfo.sq[0].x = fromX;
\r
7640 highlightInfo.sq[0].y = fromY;
\r
7641 highlightInfo.sq[1].x = toX;
\r
7642 highlightInfo.sq[1].y = toY;
\r
7648 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
7649 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
7653 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
7655 premoveHighlightInfo.sq[0].x = fromX;
\r
7656 premoveHighlightInfo.sq[0].y = fromY;
\r
7657 premoveHighlightInfo.sq[1].x = toX;
\r
7658 premoveHighlightInfo.sq[1].y = toY;
\r
7662 ClearPremoveHighlights()
\r
7664 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
7665 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
7669 ShutDownFrontEnd()
\r
7671 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
7672 DeleteClipboardTempFiles();
\r
7678 if (IsIconic(hwndMain))
\r
7679 ShowWindow(hwndMain, SW_RESTORE);
\r
7681 SetActiveWindow(hwndMain);
\r
7685 * Prototypes for animation support routines
\r
7687 static void ScreenSquare(int column, int row, POINT * pt);
\r
7688 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
7689 POINT frames[], int * nFrames);
\r
7695 AnimateMove(board, fromX, fromY, toX, toY)
\r
7702 ChessSquare piece;
\r
7703 POINT start, finish, mid;
\r
7704 POINT frames[kFactor * 2 + 1];
\r
7707 if (!appData.animate) return;
\r
7708 if (doingSizing) return;
\r
7709 if (fromY < 0 || fromX < 0) return;
\r
7710 piece = board[fromY][fromX];
\r
7711 if (piece >= EmptySquare) return;
\r
7713 ScreenSquare(fromX, fromY, &start);
\r
7714 ScreenSquare(toX, toY, &finish);
\r
7716 /* All pieces except knights move in straight line */
\r
7717 if (piece != WhiteKnight && piece != BlackKnight) {
\r
7718 mid.x = start.x + (finish.x - start.x) / 2;
\r
7719 mid.y = start.y + (finish.y - start.y) / 2;
\r
7721 /* Knight: make diagonal movement then straight */
\r
7722 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
7723 mid.x = start.x + (finish.x - start.x) / 2;
\r
7727 mid.y = start.y + (finish.y - start.y) / 2;
\r
7731 /* Don't use as many frames for very short moves */
\r
7732 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
7733 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
7735 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
7737 animInfo.from.x = fromX;
\r
7738 animInfo.from.y = fromY;
\r
7739 animInfo.to.x = toX;
\r
7740 animInfo.to.y = toY;
\r
7741 animInfo.lastpos = start;
\r
7742 animInfo.piece = piece;
\r
7743 for (n = 0; n < nFrames; n++) {
\r
7744 animInfo.pos = frames[n];
\r
7745 DrawPosition(FALSE, NULL);
\r
7746 animInfo.lastpos = animInfo.pos;
\r
7747 Sleep(appData.animSpeed);
\r
7749 animInfo.pos = finish;
\r
7750 DrawPosition(FALSE, NULL);
\r
7751 animInfo.piece = EmptySquare;
\r
7754 /* Convert board position to corner of screen rect and color */
\r
7757 ScreenSquare(column, row, pt)
\r
7758 int column; int row; POINT * pt;
\r
7761 pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
7762 pt->y = lineGap + row * (squareSize + lineGap);
\r
7764 pt->x = lineGap + column * (squareSize + lineGap);
\r
7765 pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
7769 /* Generate a series of frame coords from start->mid->finish.
\r
7770 The movement rate doubles until the half way point is
\r
7771 reached, then halves back down to the final destination,
\r
7772 which gives a nice slow in/out effect. The algorithmn
\r
7773 may seem to generate too many intermediates for short
\r
7774 moves, but remember that the purpose is to attract the
\r
7775 viewers attention to the piece about to be moved and
\r
7776 then to where it ends up. Too few frames would be less
\r
7780 Tween(start, mid, finish, factor, frames, nFrames)
\r
7781 POINT * start; POINT * mid;
\r
7782 POINT * finish; int factor;
\r
7783 POINT frames[]; int * nFrames;
\r
7785 int n, fraction = 1, count = 0;
\r
7787 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
7788 for (n = 0; n < factor; n++)
\r
7790 for (n = 0; n < factor; n++) {
\r
7791 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
7792 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
7794 fraction = fraction / 2;
\r
7798 frames[count] = *mid;
\r
7801 /* Slow out, stepping 1/2, then 1/4, ... */
\r
7803 for (n = 0; n < factor; n++) {
\r
7804 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
7805 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
7807 fraction = fraction * 2;
\r
7813 HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current)
\r
7815 /* Currently not implemented in WinBoard */
\r