2 * WinBoard.c -- Windows NT front end to XBoard
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
\r
6 * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
\r
8 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
9 * which was written and is copyrighted by Wayne Christopher.
\r
11 * The following terms apply to Digital Equipment Corporation's copyright
\r
12 * interest in XBoard:
\r
13 * ------------------------------------------------------------------------
\r
14 * All Rights Reserved
\r
16 * Permission to use, copy, modify, and distribute this software and its
\r
17 * documentation for any purpose and without fee is hereby granted,
\r
18 * provided that the above copyright notice appear in all copies and that
\r
19 * both that copyright notice and this permission notice appear in
\r
20 * supporting documentation, and that the name of Digital not be
\r
21 * used in advertising or publicity pertaining to distribution of the
\r
22 * software without specific, written prior permission.
\r
24 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
25 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
26 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
27 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
28 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
29 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
31 * ------------------------------------------------------------------------
\r
33 * The following terms apply to the enhanced version of XBoard distributed
\r
34 * by the Free Software Foundation:
\r
35 * ------------------------------------------------------------------------
\r
36 * This program is free software; you can redistribute it and/or modify
\r
37 * it under the terms of the GNU General Public License as published by
\r
38 * the Free Software Foundation; either version 2 of the License, or
\r
39 * (at your option) any later version.
\r
41 * This program is distributed in the hope that it will be useful,
\r
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
44 * GNU General Public License for more details.
\r
46 * You should have received a copy of the GNU General Public License
\r
47 * along with this program; if not, write to the Free Software
\r
48 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
49 * ------------------------------------------------------------------------
\r
54 #include <windows.h>
\r
55 #include <winuser.h>
\r
56 #include <winsock.h>
\r
61 #include <sys/stat.h>
\r
64 #include <commdlg.h>
\r
66 #include <richedit.h>
\r
67 #include <mmsystem.h>
\r
75 #include "winboard.h"
\r
76 #include "frontend.h"
\r
77 #include "backend.h"
\r
79 #include "wclipbrd.h"
\r
80 #include "wgamelist.h"
\r
81 #include "wedittags.h"
\r
82 #include "woptions.h"
\r
83 #include "wsockerr.h"
\r
84 #include "defaults.h"
\r
88 POINT pos; /* window coordinates of current pos */
\r
89 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
90 POINT from; /* board coordinates of the piece's orig pos */
\r
91 POINT to; /* board coordinates of the piece's new pos */
\r
94 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
97 POINT start; /* window coordinates of start pos */
\r
98 POINT pos; /* window coordinates of current pos */
\r
99 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
100 POINT from; /* board coordinates of the piece's orig pos */
\r
103 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
106 POINT sq[2]; /* board coordinates of from, to squares */
\r
109 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
110 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
112 /* Window class names */
\r
113 char szAppName[] = "WinBoard";
\r
114 char szConsoleName[] = "WBConsole";
\r
116 /* Title bar text */
\r
117 char szTitle[] = "WinBoard";
\r
118 char szConsoleTitle[] = "ICS Interaction";
\r
121 char *settingsFileName;
\r
122 BOOLEAN saveSettingsOnExit;
\r
123 char installDir[MSG_SIZ];
\r
125 BoardSize boardSize;
\r
126 BOOLEAN chessProgram;
\r
127 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
128 static int squareSize, lineGap;
\r
129 static int winWidth, winHeight;
\r
130 static RECT messageRect, whiteRect, blackRect;
\r
131 static char messageText[MESSAGE_TEXT_MAX];
\r
132 static int clockTimerEvent = 0;
\r
133 static int loadGameTimerEvent = 0;
\r
134 static int analysisTimerEvent = 0;
\r
135 static DelayedEventCallback delayedTimerCallback;
\r
136 static int delayedTimerEvent = 0;
\r
137 static int buttonCount = 2;
\r
138 char *icsTextMenuString;
\r
140 char *firstChessProgramNames;
\r
141 char *secondChessProgramNames;
\r
143 #define ARG_MAX 20000
\r
145 #define PALETTESIZE 256
\r
147 HINSTANCE hInst; /* current instance */
\r
148 HWND hwndMain = NULL; /* root window*/
\r
149 HWND hwndConsole = NULL;
\r
150 BOOLEAN alwaysOnTop = FALSE;
\r
152 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
153 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
155 ColorClass currentColorClass;
\r
157 HWND hCommPort = NULL; /* currently open comm port */
\r
158 static HWND hwndPause; /* pause button */
\r
159 static HBITMAP pieceBitmap[3][(int) WhiteKing + 1];
\r
160 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
161 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
162 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
163 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
164 static HPEN gridPen = NULL;
\r
165 static HPEN highlightPen = NULL;
\r
166 static HPEN premovePen = NULL;
\r
167 static NPLOGPALETTE pLogPal;
\r
168 static BOOL paletteChanged = FALSE;
\r
169 static HICON iconWhite, iconBlack, iconCurrent;
\r
170 static int doingSizing = FALSE;
\r
171 static int lastSizing = 0;
\r
172 static int prevStderrPort;
\r
174 #if __GNUC__ && !defined(_winmajor)
\r
175 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
177 #define oldDialog (_winmajor < 4)
\r
180 char *defaultTextAttribs[] =
\r
182 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
183 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
193 int cliWidth, cliHeight;
\r
196 SizeInfo sizeInfo[] =
\r
198 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
199 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
200 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
201 { "petite", 33, 1, 1, 1, 0, 0 },
\r
202 { "slim", 37, 2, 1, 0, 0, 0 },
\r
203 { "small", 40, 2, 1, 0, 0, 0 },
\r
204 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
205 { "middling", 49, 2, 0, 0, 0, 0 },
\r
206 { "average", 54, 2, 0, 0, 0, 0 },
\r
207 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
208 { "medium", 64, 3, 0, 0, 0, 0 },
\r
209 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
210 { "large", 80, 3, 0, 0, 0, 0 },
\r
211 { "big", 87, 3, 0, 0, 0, 0 },
\r
212 { "huge", 95, 3, 0, 0, 0, 0 },
\r
213 { "giant", 108, 3, 0, 0, 0, 0 },
\r
214 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
215 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
216 { NULL, 0, 0, 0, 0, 0, 0 }
\r
219 #define MF(x) {x, {0, }, {0, }, 0}
\r
220 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
222 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY),
\r
223 MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY),
\r
224 MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY) },
\r
225 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY),
\r
226 MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY),
\r
227 MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY) },
\r
228 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY),
\r
229 MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY),
\r
230 MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY) },
\r
231 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE),
\r
232 MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE),
\r
233 MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE) },
\r
234 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM),
\r
235 MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM),
\r
236 MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM) },
\r
237 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL),
\r
238 MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL),
\r
239 MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL) },
\r
240 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE),
\r
241 MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE),
\r
242 MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE) },
\r
243 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING),
\r
244 MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING),
\r
245 MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING) },
\r
246 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE),
\r
247 MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE),
\r
248 MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE) },
\r
249 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE),
\r
250 MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE),
\r
251 MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE) },
\r
252 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM),
\r
253 MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM),
\r
254 MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM) },
\r
255 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY),
\r
256 MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY),
\r
257 MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY) },
\r
258 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE),
\r
259 MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE),
\r
260 MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE) },
\r
261 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG),
\r
262 MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG),
\r
263 MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG) },
\r
264 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE),
\r
265 MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE),
\r
266 MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE) },
\r
267 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT),
\r
268 MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT),
\r
269 MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT) },
\r
270 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL),
\r
271 MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL),
\r
272 MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL) },
\r
273 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC),
\r
274 MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC),
\r
275 MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC) },
\r
278 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
287 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
288 #define N_BUTTONS 5
\r
290 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
292 {"<<", IDM_ToStart, NULL, NULL},
\r
293 {"<", IDM_Backward, NULL, NULL},
\r
294 {"P", IDM_Pause, NULL, NULL},
\r
295 {">", IDM_Forward, NULL, NULL},
\r
296 {">>", IDM_ToEnd, NULL, NULL},
\r
299 int tinyLayout = 0, smallLayout = 0;
\r
300 #define MENU_BAR_ITEMS 6
\r
301 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
302 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
303 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
307 MySound sounds[(int)NSoundClasses];
\r
308 MyTextAttribs textAttribs[(int)NColorClasses];
\r
310 MyColorizeAttribs colorizeAttribs[] = {
\r
311 { (COLORREF)0, 0, "Shout Text" },
\r
312 { (COLORREF)0, 0, "SShout/CShout" },
\r
313 { (COLORREF)0, 0, "Channel 1 Text" },
\r
314 { (COLORREF)0, 0, "Channel Text" },
\r
315 { (COLORREF)0, 0, "Kibitz Text" },
\r
316 { (COLORREF)0, 0, "Tell Text" },
\r
317 { (COLORREF)0, 0, "Challenge Text" },
\r
318 { (COLORREF)0, 0, "Request Text" },
\r
319 { (COLORREF)0, 0, "Seek Text" },
\r
320 { (COLORREF)0, 0, "Normal Text" },
\r
321 { (COLORREF)0, 0, "None" }
\r
326 static char *commentTitle;
\r
327 static char *commentText;
\r
328 static int commentIndex;
\r
329 static Boolean editComment = FALSE;
\r
330 HWND commentDialog = NULL;
\r
331 BOOLEAN commentDialogUp = FALSE;
\r
332 static int commentX, commentY, commentH, commentW;
\r
334 static char *analysisTitle;
\r
335 static char *analysisText;
\r
336 HWND analysisDialog = NULL;
\r
337 BOOLEAN analysisDialogUp = FALSE;
\r
338 static int analysisX, analysisY, analysisH, analysisW;
\r
340 char errorTitle[MSG_SIZ];
\r
341 char errorMessage[2*MSG_SIZ];
\r
342 HWND errorDialog = NULL;
\r
343 BOOLEAN moveErrorMessageUp = FALSE;
\r
344 BOOLEAN consoleEcho = TRUE;
\r
345 CHARFORMAT consoleCF;
\r
346 COLORREF consoleBackgroundColor;
\r
348 char *programVersion;
\r
354 typedef int CPKind;
\r
363 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
366 #define INPUT_SOURCE_BUF_SIZE 4096
\r
368 typedef struct _InputSource {
\r
375 char buf[INPUT_SOURCE_BUF_SIZE];
\r
379 InputCallback func;
\r
380 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
384 InputSource *consoleInputSource;
\r
389 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
390 VOID ConsoleCreate();
\r
392 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
393 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
394 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
395 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
397 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
398 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
399 void ParseIcsTextMenu(char *icsTextMenuString);
\r
400 VOID PopUpMoveDialog(char firstchar);
\r
401 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
404 * Setting "frozen" should disable all user input other than deleting
\r
405 * the window. We do this while engines are initializing themselves.
\r
407 static int frozen = 0;
\r
408 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
414 if (frozen) return;
\r
416 hmenu = GetMenu(hwndMain);
\r
417 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
418 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
420 DrawMenuBar(hwndMain);
\r
423 /* Undo a FreezeUI */
\r
429 if (!frozen) return;
\r
431 hmenu = GetMenu(hwndMain);
\r
432 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
433 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
435 DrawMenuBar(hwndMain);
\r
438 /*---------------------------------------------------------------------------*\
\r
442 \*---------------------------------------------------------------------------*/
\r
445 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
446 LPSTR lpCmdLine, int nCmdShow)
\r
449 HANDLE hAccelMain, hAccelNoAlt;
\r
453 LoadLibrary("RICHED32.DLL");
\r
454 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
456 if (!InitApplication(hInstance)) {
\r
459 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
463 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
464 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
466 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
468 while (GetMessage(&msg, /* message structure */
\r
469 NULL, /* handle of window receiving the message */
\r
470 0, /* lowest message to examine */
\r
471 0)) /* highest message to examine */
\r
473 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
474 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
475 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
476 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
477 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
478 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
479 TranslateMessage(&msg); /* Translates virtual key codes */
\r
480 DispatchMessage(&msg); /* Dispatches message to window */
\r
485 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
488 /*---------------------------------------------------------------------------*\
\r
490 * Initialization functions
\r
492 \*---------------------------------------------------------------------------*/
\r
495 InitApplication(HINSTANCE hInstance)
\r
499 /* Fill in window class structure with parameters that describe the */
\r
502 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
503 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
504 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
505 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
506 wc.hInstance = hInstance; /* Owner of this class */
\r
507 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
508 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
509 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
510 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
511 wc.lpszClassName = szAppName; /* Name to register as */
\r
513 /* Register the window class and return success/failure code. */
\r
514 if (!RegisterClass(&wc)) return FALSE;
\r
516 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
517 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
519 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
520 wc.hInstance = hInstance;
\r
521 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
522 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
523 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
524 wc.lpszMenuName = NULL;
\r
525 wc.lpszClassName = szConsoleName;
\r
527 if (!RegisterClass(&wc)) return FALSE;
\r
532 /* Set by InitInstance, used by EnsureOnScreen */
\r
533 int screenHeight, screenWidth;
\r
536 EnsureOnScreen(int *x, int *y)
\r
538 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
539 if (*x > screenWidth - 32) *x = 0;
\r
540 if (*y > screenHeight - 32) *y = 0;
\r
544 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
546 HWND hwnd; /* Main window handle. */
\r
548 WINDOWPLACEMENT wp;
\r
551 hInst = hInstance; /* Store instance handle in our global variable */
\r
553 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
554 *filepart = NULLCHAR;
\r
556 GetCurrentDirectory(MSG_SIZ, installDir);
\r
558 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
559 if (appData.debugMode) {
\r
560 debugFP = fopen("winboard.debug", "w");
\r
561 setbuf(debugFP, NULL);
\r
566 /* Create a main window for this application instance. */
\r
567 hwnd = CreateWindow(szAppName, szTitle,
\r
568 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
569 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
570 NULL, NULL, hInstance, NULL);
\r
573 /* If window could not be created, return "failure" */
\r
578 iconWhite = LoadIcon(hInstance, "icon_white");
\r
579 iconBlack = LoadIcon(hInstance, "icon_black");
\r
580 iconCurrent = iconWhite;
\r
581 InitDrawingColors();
\r
582 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
583 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
584 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
585 /* Compute window size for each board size, and use the largest
\r
586 size that fits on this screen as the default. */
\r
587 InitDrawingSizes((BoardSize)ibs, 0);
\r
588 if (boardSize == (BoardSize)-1 &&
\r
589 winHeight <= screenHeight && winWidth <= screenWidth) {
\r
590 boardSize = (BoardSize)ibs;
\r
593 InitDrawingSizes(boardSize, 0);
\r
595 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
597 /* Make a console window if needed */
\r
598 if (appData.icsActive) {
\r
604 /* Make the window visible; update its client area; and return "success" */
\r
605 EnsureOnScreen(&boardX, &boardY);
\r
606 wp.length = sizeof(WINDOWPLACEMENT);
\r
608 wp.showCmd = nCmdShow;
\r
609 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
610 wp.rcNormalPosition.left = boardX;
\r
611 wp.rcNormalPosition.right = boardX + winWidth;
\r
612 wp.rcNormalPosition.top = boardY;
\r
613 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
614 SetWindowPlacement(hwndMain, &wp);
\r
616 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
617 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
620 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
621 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
623 ShowWindow(hwndConsole, nCmdShow);
\r
625 UpdateWindow(hwnd);
\r
633 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
634 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
635 ArgSettingsFilename
\r
643 String *pString; // ArgString
\r
644 int *pInt; // ArgInt
\r
645 float *pFloat; // ArgFloat
\r
646 Boolean *pBoolean; // ArgBoolean
\r
647 COLORREF *pColor; // ArgColor
\r
648 ColorClass cc; // ArgAttribs
\r
649 String *pFilename; // ArgFilename
\r
650 BoardSize *pBoardSize; // ArgBoardSize
\r
651 int whichFont; // ArgFont
\r
652 DCB *pDCB; // ArgCommSettings
\r
653 String *pFilename; // ArgSettingsFilename
\r
661 ArgDescriptor argDescriptors[] = {
\r
662 /* positional arguments */
\r
663 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
664 { "", ArgNone, NULL },
\r
665 /* keyword arguments */
\r
666 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
667 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
668 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
669 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
670 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
671 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
672 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
673 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
674 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
675 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
676 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
677 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
678 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
679 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
680 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
681 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
682 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
683 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
685 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
687 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
689 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
690 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
692 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
693 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
694 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
695 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
696 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
697 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
698 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
699 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
700 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
701 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
702 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
703 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
704 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
705 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
706 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
707 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
708 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
709 /*!!bitmapDirectory?*/
\r
710 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
711 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
712 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
713 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
714 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
715 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
716 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
717 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
718 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
719 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
720 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
721 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
722 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
723 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
724 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
725 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
726 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
727 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
728 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
729 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
730 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
731 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
732 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
733 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
734 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
735 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
736 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
737 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
738 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
739 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
740 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
741 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
742 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
743 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
744 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
745 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
746 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
747 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
748 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
749 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
750 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
751 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
752 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
753 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
754 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
755 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
756 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
757 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
758 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
759 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
760 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
761 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
762 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
763 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
764 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
765 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
766 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
767 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
768 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
769 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
770 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
771 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
772 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
773 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
774 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
775 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
776 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
777 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
778 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
779 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
780 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
781 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
782 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
783 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
784 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
785 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
786 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
787 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
788 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
789 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
790 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
791 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
792 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
793 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
794 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
795 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
796 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
797 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
798 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
799 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
800 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
801 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
802 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
803 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
804 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
805 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
806 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
807 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
808 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
809 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
810 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
811 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
812 TRUE }, /* must come after all fonts */
\r
813 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
814 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
815 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
816 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
817 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
818 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
819 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
820 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
821 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
822 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
823 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
824 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
825 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
826 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
827 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
828 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
829 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
830 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
831 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
832 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
833 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
834 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
835 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
836 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
837 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
838 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
839 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
840 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
841 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
842 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
843 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
845 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
846 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
848 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
849 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
850 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
851 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
852 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
853 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
854 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
855 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
856 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
857 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
858 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
859 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
860 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
861 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
862 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
863 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
864 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
865 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
866 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
867 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
868 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
869 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
870 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
871 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
872 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
873 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
874 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
875 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
876 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
877 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
878 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
879 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
880 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
881 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
882 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
883 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
884 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
885 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
886 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
887 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
888 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
889 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
890 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
891 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
892 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
893 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
894 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
895 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
896 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
897 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
898 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
899 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
900 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
901 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
902 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
903 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
904 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
905 { "highlightLastMove", ArgBoolean,
\r
906 (LPVOID) &appData.highlightLastMove, TRUE },
\r
907 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
908 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
909 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
910 { "highlightDragging", ArgBoolean,
\r
911 (LPVOID) &appData.highlightDragging, TRUE },
\r
912 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
913 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
914 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
915 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
916 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
917 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
918 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
919 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
920 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
921 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
922 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
923 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
924 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
925 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
926 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
927 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
928 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
929 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
930 { "soundShout", ArgFilename,
\r
931 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
932 { "soundSShout", ArgFilename,
\r
933 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
934 { "soundChannel1", ArgFilename,
\r
935 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
936 { "soundChannel", ArgFilename,
\r
937 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
938 { "soundKibitz", ArgFilename,
\r
939 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
940 { "soundTell", ArgFilename,
\r
941 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
942 { "soundChallenge", ArgFilename,
\r
943 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
944 { "soundRequest", ArgFilename,
\r
945 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
946 { "soundSeek", ArgFilename,
\r
947 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
948 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
949 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
950 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
951 { "soundIcsLoss", ArgFilename,
\r
952 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
953 { "soundIcsDraw", ArgFilename,
\r
954 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
955 { "soundIcsUnfinished", ArgFilename,
\r
956 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
957 { "soundIcsAlarm", ArgFilename,
\r
958 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
959 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
960 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
961 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
962 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
963 { "reuseChessPrograms", ArgBoolean,
\r
964 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
965 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
966 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
967 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
968 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
969 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
970 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
971 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
972 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
973 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
974 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
975 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
976 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
977 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
978 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
979 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
980 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
981 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
982 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
983 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
984 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
985 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
986 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
987 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
988 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
989 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
990 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
991 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
992 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
993 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
994 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
995 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
996 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
997 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
998 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
999 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1000 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1001 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1003 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1005 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1006 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1007 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1008 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion,
\r
1010 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,
\r
1012 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1013 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1014 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1015 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1017 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1018 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1019 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1020 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1021 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1022 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1023 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1024 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1025 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1026 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1027 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1028 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1029 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1031 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1032 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1033 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1034 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1035 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1036 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1037 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1039 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1040 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1041 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1042 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1043 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1044 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1045 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1046 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1047 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1048 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1049 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1050 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1051 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1052 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1053 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1054 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1055 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1056 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1058 { NULL, ArgNone, NULL, FALSE }
\r
1062 /* Kludge for indirection files on command line */
\r
1063 char* lastIndirectionFilename;
\r
1064 ArgDescriptor argDescriptorIndirection =
\r
1065 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1069 ExitArgError(char *msg, char *badArg)
\r
1071 char buf[MSG_SIZ];
\r
1073 sprintf(buf, "%s %s", msg, badArg);
\r
1074 DisplayFatalError(buf, 0, 2);
\r
1078 /* Command line font name parser. NULL name means do nothing.
\r
1079 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1080 For backward compatibility, syntax without the colon is also
\r
1081 accepted, but font names with digits in them won't work in that case.
\r
1084 ParseFontName(char *name, MyFontParams *mfp)
\r
1087 if (name == NULL) return;
\r
1089 q = strchr(p, ':');
\r
1091 if (q - p >= sizeof(mfp->faceName))
\r
1092 ExitArgError("Font name too long:", name);
\r
1093 memcpy(mfp->faceName, p, q - p);
\r
1094 mfp->faceName[q - p] = NULLCHAR;
\r
1097 q = mfp->faceName;
\r
1098 while (*p && !isdigit(*p)) {
\r
1100 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1101 ExitArgError("Font name too long:", name);
\r
1103 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1106 if (!*p) ExitArgError("Font point size missing:", name);
\r
1107 mfp->pointSize = (float) atof(p);
\r
1108 mfp->bold = (strchr(p, 'b') != NULL);
\r
1109 mfp->italic = (strchr(p, 'i') != NULL);
\r
1110 mfp->underline = (strchr(p, 'u') != NULL);
\r
1111 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1114 /* Color name parser.
\r
1115 X version accepts X color names, but this one
\r
1116 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1118 ParseColorName(char *name)
\r
1120 int red, green, blue, count;
\r
1121 char buf[MSG_SIZ];
\r
1123 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1125 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1126 &red, &green, &blue);
\r
1129 sprintf(buf, "Can't parse color name %s", name);
\r
1130 DisplayError(buf, 0);
\r
1131 return RGB(0, 0, 0);
\r
1133 return PALETTERGB(red, green, blue);
\r
1137 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1139 char *e = argValue;
\r
1143 if (*e == 'b') eff |= CFE_BOLD;
\r
1144 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1145 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1146 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1147 else if (*e == '#' || isdigit(*e)) break;
\r
1151 *color = ParseColorName(e);
\r
1156 ParseBoardSize(char *name)
\r
1158 BoardSize bs = SizeTiny;
\r
1159 while (sizeInfo[bs].name != NULL) {
\r
1160 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1163 ExitArgError("Unrecognized board size value", name);
\r
1164 return bs; /* not reached */
\r
1169 StringGet(void *getClosure)
\r
1171 char **p = (char **) getClosure;
\r
1176 FileGet(void *getClosure)
\r
1179 FILE* f = (FILE*) getClosure;
\r
1188 /* Parse settings file named "name". If file found, return the
\r
1189 full name in fullname and return TRUE; else return FALSE */
\r
1191 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1196 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1197 f = fopen(fullname, "r");
\r
1199 ParseArgs(FileGet, f);
\r
1208 ParseArgs(GetFunc get, void *cl)
\r
1210 char argName[ARG_MAX];
\r
1211 char argValue[ARG_MAX];
\r
1212 ArgDescriptor *ad;
\r
1221 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1222 if (ch == NULLCHAR) break;
\r
1224 /* Comment to end of line */
\r
1226 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1228 } else if (ch == '/' || ch == '-') {
\r
1231 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1232 ch != '\n' && ch != '\t') {
\r
1238 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1239 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1241 if (ad->argName == NULL)
\r
1242 ExitArgError("Unrecognized argument", argName);
\r
1244 } else if (ch == '@') {
\r
1245 /* Indirection file */
\r
1246 ad = &argDescriptorIndirection;
\r
1249 /* Positional argument */
\r
1250 ad = &argDescriptors[posarg++];
\r
1251 strcpy(argName, ad->argName);
\r
1254 if (ad->argType == ArgTrue) {
\r
1255 *(Boolean *) ad->argLoc = TRUE;
\r
1258 if (ad->argType == ArgFalse) {
\r
1259 *(Boolean *) ad->argLoc = FALSE;
\r
1263 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1264 if (ch == NULLCHAR || ch == '\n') {
\r
1265 ExitArgError("No value provided for argument", argName);
\r
1269 // Quoting with { }. No characters have to (or can) be escaped.
\r
1270 // Thus the string cannot contain a '}' character.
\r
1290 } else if (ch == '\'' || ch == '"') {
\r
1291 // Quoting with ' ' or " ", with \ as escape character.
\r
1292 // Inconvenient for long strings that may contain Windows filenames.
\r
1309 if (ch == start) {
\r
1318 if (ad->argType == ArgFilename
\r
1319 || ad->argType == ArgSettingsFilename) {
\r
1325 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1349 for (i = 0; i < 3; i++) {
\r
1350 if (ch >= '0' && ch <= '7') {
\r
1351 octval = octval*8 + (ch - '0');
\r
1358 *q++ = (char) octval;
\r
1369 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1376 switch (ad->argType) {
\r
1378 *(int *) ad->argLoc = atoi(argValue);
\r
1382 *(float *) ad->argLoc = (float) atof(argValue);
\r
1387 *(char **) ad->argLoc = strdup(argValue);
\r
1390 case ArgSettingsFilename:
\r
1392 char fullname[MSG_SIZ];
\r
1393 if (ParseSettingsFile(argValue, fullname)) {
\r
1394 if (ad->argLoc != NULL) {
\r
1395 *(char **) ad->argLoc = strdup(fullname);
\r
1398 if (ad->argLoc != NULL) {
\r
1400 ExitArgError("Failed to open indirection file", argValue);
\r
1407 switch (argValue[0]) {
\r
1410 *(Boolean *) ad->argLoc = TRUE;
\r
1414 *(Boolean *) ad->argLoc = FALSE;
\r
1417 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1423 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1426 case ArgAttribs: {
\r
1427 ColorClass cc = (ColorClass)ad->argLoc;
\r
1428 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1432 case ArgBoardSize:
\r
1433 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1437 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1440 case ArgCommSettings:
\r
1441 ParseCommSettings(argValue, &dcb);
\r
1445 ExitArgError("Unrecognized argument", argValue);
\r
1452 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1454 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1455 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1458 lf->lfEscapement = 0;
\r
1459 lf->lfOrientation = 0;
\r
1460 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1461 lf->lfItalic = mfp->italic;
\r
1462 lf->lfUnderline = mfp->underline;
\r
1463 lf->lfStrikeOut = mfp->strikeout;
\r
1464 lf->lfCharSet = DEFAULT_CHARSET;
\r
1465 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1466 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1467 lf->lfQuality = DEFAULT_QUALITY;
\r
1468 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1469 strcpy(lf->lfFaceName, mfp->faceName);
\r
1473 CreateFontInMF(MyFont *mf)
\r
1475 LFfromMFP(&mf->lf, &mf->mfp);
\r
1476 if (mf->hf) DeleteObject(mf->hf);
\r
1477 mf->hf = CreateFontIndirect(&mf->lf);
\r
1481 SetDefaultTextAttribs()
\r
1484 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1485 ParseAttribs(&textAttribs[cc].color,
\r
1486 &textAttribs[cc].effects,
\r
1487 defaultTextAttribs[cc]);
\r
1492 SetDefaultSounds()
\r
1496 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1497 textAttribs[cc].sound.name = strdup("");
\r
1498 textAttribs[cc].sound.data = NULL;
\r
1500 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1501 sounds[sc].name = strdup("");
\r
1502 sounds[sc].data = NULL;
\r
1504 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1512 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1513 MyLoadSound(&textAttribs[cc].sound);
\r
1515 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1516 MyLoadSound(&sounds[sc]);
\r
1521 InitAppData(LPSTR lpCmdLine)
\r
1524 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1527 programName = szAppName;
\r
1529 /* Initialize to defaults */
\r
1530 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1531 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1532 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1533 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1534 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1535 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1536 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1537 SetDefaultTextAttribs();
\r
1538 SetDefaultSounds();
\r
1539 appData.movesPerSession = MOVES_PER_SESSION;
\r
1540 appData.initString = INIT_STRING;
\r
1541 appData.secondInitString = INIT_STRING;
\r
1542 appData.firstComputerString = COMPUTER_STRING;
\r
1543 appData.secondComputerString = COMPUTER_STRING;
\r
1544 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1545 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1546 appData.firstPlaysBlack = FALSE;
\r
1547 appData.noChessProgram = FALSE;
\r
1548 chessProgram = FALSE;
\r
1549 appData.firstHost = FIRST_HOST;
\r
1550 appData.secondHost = SECOND_HOST;
\r
1551 appData.firstDirectory = FIRST_DIRECTORY;
\r
1552 appData.secondDirectory = SECOND_DIRECTORY;
\r
1553 appData.bitmapDirectory = "";
\r
1554 appData.remoteShell = REMOTE_SHELL;
\r
1555 appData.remoteUser = "";
\r
1556 appData.timeDelay = TIME_DELAY;
\r
1557 appData.timeControl = TIME_CONTROL;
\r
1558 appData.timeIncrement = TIME_INCREMENT;
\r
1559 appData.icsActive = FALSE;
\r
1560 appData.icsHost = "";
\r
1561 appData.icsPort = ICS_PORT;
\r
1562 appData.icsCommPort = ICS_COMM_PORT;
\r
1563 appData.icsLogon = ICS_LOGON;
\r
1564 appData.icsHelper = "";
\r
1565 appData.useTelnet = FALSE;
\r
1566 appData.telnetProgram = TELNET_PROGRAM;
\r
1567 appData.gateway = "";
\r
1568 appData.loadGameFile = "";
\r
1569 appData.loadGameIndex = 0;
\r
1570 appData.saveGameFile = "";
\r
1571 appData.autoSaveGames = FALSE;
\r
1572 appData.loadPositionFile = "";
\r
1573 appData.loadPositionIndex = 1;
\r
1574 appData.savePositionFile = "";
\r
1575 appData.matchMode = FALSE;
\r
1576 appData.matchGames = 0;
\r
1577 appData.monoMode = FALSE;
\r
1578 appData.debugMode = FALSE;
\r
1579 appData.clockMode = TRUE;
\r
1580 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1581 appData.Iconic = FALSE; /*unused*/
\r
1582 appData.searchTime = "";
\r
1583 appData.searchDepth = 0;
\r
1584 appData.showCoords = FALSE;
\r
1585 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1586 appData.autoCallFlag = FALSE;
\r
1587 appData.flipView = FALSE;
\r
1588 appData.autoFlipView = TRUE;
\r
1589 appData.cmailGameName = "";
\r
1590 appData.alwaysPromoteToQueen = FALSE;
\r
1591 appData.oldSaveStyle = FALSE;
\r
1592 appData.quietPlay = FALSE;
\r
1593 appData.showThinking = FALSE;
\r
1594 appData.ponderNextMove = TRUE;
\r
1595 appData.periodicUpdates = TRUE;
\r
1596 appData.popupExitMessage = TRUE;
\r
1597 appData.popupMoveErrors = FALSE;
\r
1598 appData.autoObserve = FALSE;
\r
1599 appData.autoComment = FALSE;
\r
1600 appData.animate = TRUE;
\r
1601 appData.animSpeed = 10;
\r
1602 appData.animateDragging = TRUE;
\r
1603 appData.highlightLastMove = TRUE;
\r
1604 appData.getMoveList = TRUE;
\r
1605 appData.testLegality = TRUE;
\r
1606 appData.premove = TRUE;
\r
1607 appData.premoveWhite = FALSE;
\r
1608 appData.premoveWhiteText = "";
\r
1609 appData.premoveBlack = FALSE;
\r
1610 appData.premoveBlackText = "";
\r
1611 appData.icsAlarm = TRUE;
\r
1612 appData.icsAlarmTime = 5000;
\r
1613 appData.autoRaiseBoard = TRUE;
\r
1614 appData.localLineEditing = TRUE;
\r
1615 appData.colorize = TRUE;
\r
1616 appData.reuseFirst = TRUE;
\r
1617 appData.reuseSecond = TRUE;
\r
1618 appData.blindfold = FALSE;
\r
1619 dcb.DCBlength = sizeof(DCB);
\r
1620 dcb.BaudRate = 9600;
\r
1621 dcb.fBinary = TRUE;
\r
1622 dcb.fParity = FALSE;
\r
1623 dcb.fOutxCtsFlow = FALSE;
\r
1624 dcb.fOutxDsrFlow = FALSE;
\r
1625 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1626 dcb.fDsrSensitivity = FALSE;
\r
1627 dcb.fTXContinueOnXoff = TRUE;
\r
1628 dcb.fOutX = FALSE;
\r
1630 dcb.fNull = FALSE;
\r
1631 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1632 dcb.fAbortOnError = FALSE;
\r
1633 dcb.wReserved = 0;
\r
1635 dcb.Parity = SPACEPARITY;
\r
1636 dcb.StopBits = ONESTOPBIT;
\r
1637 settingsFileName = SETTINGS_FILE;
\r
1638 saveSettingsOnExit = TRUE;
\r
1639 boardX = CW_USEDEFAULT;
\r
1640 boardY = CW_USEDEFAULT;
\r
1641 consoleX = CW_USEDEFAULT;
\r
1642 consoleY = CW_USEDEFAULT;
\r
1643 consoleW = CW_USEDEFAULT;
\r
1644 consoleH = CW_USEDEFAULT;
\r
1645 analysisX = CW_USEDEFAULT;
\r
1646 analysisY = CW_USEDEFAULT;
\r
1647 analysisW = CW_USEDEFAULT;
\r
1648 analysisH = CW_USEDEFAULT;
\r
1649 commentX = CW_USEDEFAULT;
\r
1650 commentY = CW_USEDEFAULT;
\r
1651 commentW = CW_USEDEFAULT;
\r
1652 commentH = CW_USEDEFAULT;
\r
1653 editTagsX = CW_USEDEFAULT;
\r
1654 editTagsY = CW_USEDEFAULT;
\r
1655 editTagsW = CW_USEDEFAULT;
\r
1656 editTagsH = CW_USEDEFAULT;
\r
1657 gameListX = CW_USEDEFAULT;
\r
1658 gameListY = CW_USEDEFAULT;
\r
1659 gameListW = CW_USEDEFAULT;
\r
1660 gameListH = CW_USEDEFAULT;
\r
1661 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1662 icsNames = ICS_NAMES;
\r
1663 firstChessProgramNames = FCP_NAMES;
\r
1664 secondChessProgramNames = SCP_NAMES;
\r
1665 appData.initialMode = "";
\r
1666 appData.variant = "normal";
\r
1667 appData.firstProtocolVersion = PROTOVER;
\r
1668 appData.secondProtocolVersion = PROTOVER;
\r
1669 appData.showButtonBar = TRUE;
\r
1671 appData.zippyTalk = ZIPPY_TALK;
\r
1672 appData.zippyPlay = ZIPPY_PLAY;
\r
1673 appData.zippyLines = ZIPPY_LINES;
\r
1674 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1675 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1676 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1677 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1678 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1679 appData.zippyUseI = ZIPPY_USE_I;
\r
1680 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1681 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1682 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1683 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1684 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1685 appData.zippyAbort = ZIPPY_ABORT;
\r
1686 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1687 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1688 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1691 /* Point font array elements to structures and
\r
1692 parse default font names */
\r
1693 for (i=0; i<NUM_FONTS; i++) {
\r
1694 for (j=0; j<NUM_SIZES; j++) {
\r
1695 font[j][i] = &fontRec[j][i];
\r
1696 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1700 /* Parse default settings file if any */
\r
1701 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1702 settingsFileName = strdup(buf);
\r
1705 /* Parse command line */
\r
1706 ParseArgs(StringGet, &lpCmdLine);
\r
1708 /* Propagate options that affect others */
\r
1709 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1710 if (appData.icsActive || appData.noChessProgram) {
\r
1711 chessProgram = FALSE; /* not local chess program mode */
\r
1714 /* Open startup dialog if needed */
\r
1715 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1716 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1717 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1718 *appData.secondChessProgram == NULLCHAR))) {
\r
1721 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1722 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1723 FreeProcInstance(lpProc);
\r
1726 /* Make sure save files land in the right (?) directory */
\r
1727 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1728 appData.saveGameFile = strdup(buf);
\r
1730 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1731 appData.savePositionFile = strdup(buf);
\r
1734 /* Finish initialization for fonts and sounds */
\r
1735 for (i=0; i<NUM_FONTS; i++) {
\r
1736 for (j=0; j<NUM_SIZES; j++) {
\r
1737 CreateFontInMF(font[j][i]);
\r
1740 /* xboard, and older WinBoards, controlled the move sound with the
\r
1741 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1742 always turn the option on (so that the backend will call us),
\r
1743 then let the user turn the sound off by setting it to silence if
\r
1744 desired. To accommodate old winboard.ini files saved by old
\r
1745 versions of WinBoard, we also turn off the sound if the option
\r
1746 was initially set to false. */
\r
1747 if (!appData.ringBellAfterMoves) {
\r
1748 sounds[(int)SoundMove].name = strdup("");
\r
1749 appData.ringBellAfterMoves = TRUE;
\r
1751 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1752 SetCurrentDirectory(installDir);
\r
1754 SetCurrentDirectory(currDir);
\r
1756 p = icsTextMenuString;
\r
1757 if (p[0] == '@') {
\r
1758 FILE* f = fopen(p + 1, "r");
\r
1760 DisplayFatalError(p + 1, errno, 2);
\r
1763 i = fread(buf, 1, sizeof(buf)-1, f);
\r
1765 buf[i] = NULLCHAR;
\r
1768 ParseIcsTextMenu(strdup(p));
\r
1775 HMENU hmenu = GetMenu(hwndMain);
\r
1777 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1778 MF_BYCOMMAND|((appData.icsActive &&
\r
1779 *appData.icsCommPort != NULLCHAR) ?
\r
1780 MF_ENABLED : MF_GRAYED));
\r
1781 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1782 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1783 MF_CHECKED : MF_UNCHECKED));
\r
1788 SaveSettings(char* name)
\r
1791 ArgDescriptor *ad;
\r
1792 WINDOWPLACEMENT wp;
\r
1793 char dir[MSG_SIZ];
\r
1795 if (!hwndMain) return;
\r
1797 GetCurrentDirectory(MSG_SIZ, dir);
\r
1798 SetCurrentDirectory(installDir);
\r
1799 f = fopen(name, "w");
\r
1800 SetCurrentDirectory(dir);
\r
1802 DisplayError(name, errno);
\r
1805 fprintf(f, ";\n");
\r
1806 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
1807 fprintf(f, ";\n");
\r
1808 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
1809 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
1810 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
1811 fprintf(f, ";\n");
\r
1813 wp.length = sizeof(WINDOWPLACEMENT);
\r
1814 GetWindowPlacement(hwndMain, &wp);
\r
1815 boardX = wp.rcNormalPosition.left;
\r
1816 boardY = wp.rcNormalPosition.top;
\r
1818 if (hwndConsole) {
\r
1819 GetWindowPlacement(hwndConsole, &wp);
\r
1820 consoleX = wp.rcNormalPosition.left;
\r
1821 consoleY = wp.rcNormalPosition.top;
\r
1822 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1823 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1826 if (analysisDialog) {
\r
1827 GetWindowPlacement(analysisDialog, &wp);
\r
1828 analysisX = wp.rcNormalPosition.left;
\r
1829 analysisY = wp.rcNormalPosition.top;
\r
1830 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1831 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1834 if (commentDialog) {
\r
1835 GetWindowPlacement(commentDialog, &wp);
\r
1836 commentX = wp.rcNormalPosition.left;
\r
1837 commentY = wp.rcNormalPosition.top;
\r
1838 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1839 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1842 if (editTagsDialog) {
\r
1843 GetWindowPlacement(editTagsDialog, &wp);
\r
1844 editTagsX = wp.rcNormalPosition.left;
\r
1845 editTagsY = wp.rcNormalPosition.top;
\r
1846 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1847 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1850 if (gameListDialog) {
\r
1851 GetWindowPlacement(gameListDialog, &wp);
\r
1852 gameListX = wp.rcNormalPosition.left;
\r
1853 gameListY = wp.rcNormalPosition.top;
\r
1854 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1855 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1858 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
1859 if (!ad->save) continue;
\r
1860 switch (ad->argType) {
\r
1863 char *p = *(char **)ad->argLoc;
\r
1864 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
1865 /* Quote multiline values or \-containing values
\r
1866 with { } if possible */
\r
1867 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
1869 /* Else quote with " " */
\r
1870 fprintf(f, "/%s=\"", ad->argName);
\r
1872 if (*p == '\n') fprintf(f, "\n");
\r
1873 else if (*p == '\r') fprintf(f, "\\r");
\r
1874 else if (*p == '\t') fprintf(f, "\\t");
\r
1875 else if (*p == '\b') fprintf(f, "\\b");
\r
1876 else if (*p == '\f') fprintf(f, "\\f");
\r
1877 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
1878 else if (*p == '\"') fprintf(f, "\\\"");
\r
1879 else if (*p == '\\') fprintf(f, "\\\\");
\r
1883 fprintf(f, "\"\n");
\r
1888 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
1891 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
1894 fprintf(f, "/%s=%s\n", ad->argName,
\r
1895 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
1898 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1901 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1905 COLORREF color = *(COLORREF *)ad->argLoc;
\r
1906 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
1907 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1912 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1913 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
1914 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1915 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1916 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1917 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1918 (ta->effects) ? " " : "",
\r
1919 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1923 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
1924 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
1926 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
1929 case ArgBoardSize:
\r
1930 fprintf(f, "/%s=%s\n", ad->argName,
\r
1931 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
1936 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1937 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1938 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1939 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
1940 ad->argName, mfp->faceName, mfp->pointSize,
\r
1941 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1942 mfp->bold ? "b" : "",
\r
1943 mfp->italic ? "i" : "",
\r
1944 mfp->underline ? "u" : "",
\r
1945 mfp->strikeout ? "s" : "");
\r
1949 case ArgCommSettings:
\r
1950 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
1958 /*---------------------------------------------------------------------------*\
\r
1960 * GDI board drawing routines
\r
1962 \*---------------------------------------------------------------------------*/
\r
1965 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
1969 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
1970 if (gameInfo.event &&
\r
1971 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
1972 strcmp(name, "k80s") == 0) {
\r
1973 strcpy(name, "tim");
\r
1975 return LoadBitmap(hinst, name);
\r
1979 /* Insert a color into the program's logical palette
\r
1980 structure. This code assumes the given color is
\r
1981 the result of the RGB or PALETTERGB macro, and it
\r
1982 knows how those macros work (which is documented).
\r
1985 InsertInPalette(COLORREF color)
\r
1987 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
1989 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
1990 DisplayFatalError("Too many colors", 0, 1);
\r
1991 pLogPal->palNumEntries--;
\r
1995 pe->peFlags = (char) 0;
\r
1996 pe->peRed = (char) (0xFF & color);
\r
1997 pe->peGreen = (char) (0xFF & (color >> 8));
\r
1998 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2004 InitDrawingColors()
\r
2006 if (pLogPal == NULL) {
\r
2007 /* Allocate enough memory for a logical palette with
\r
2008 * PALETTESIZE entries and set the size and version fields
\r
2009 * of the logical palette structure.
\r
2011 pLogPal = (NPLOGPALETTE)
\r
2012 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2013 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2014 pLogPal->palVersion = 0x300;
\r
2016 pLogPal->palNumEntries = 0;
\r
2018 InsertInPalette(lightSquareColor);
\r
2019 InsertInPalette(darkSquareColor);
\r
2020 InsertInPalette(whitePieceColor);
\r
2021 InsertInPalette(blackPieceColor);
\r
2022 InsertInPalette(highlightSquareColor);
\r
2023 InsertInPalette(premoveHighlightColor);
\r
2025 /* create a logical color palette according the information
\r
2026 * in the LOGPALETTE structure.
\r
2028 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2030 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2031 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2032 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2033 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2034 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2039 BoardWidth(int boardSize)
\r
2041 return (BOARD_SIZE + 1) * sizeInfo[boardSize].lineGap +
\r
2042 BOARD_SIZE * sizeInfo[boardSize].squareSize;
\r
2045 /* Respond to board resize by dragging edge */
\r
2047 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2049 BoardSize newSize = NUM_SIZES - 1;
\r
2050 static int recurse = 0;
\r
2051 if (IsIconic(hwndMain)) return;
\r
2052 if (recurse > 0) return;
\r
2054 while (newSize > 0 &&
\r
2055 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2056 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2059 boardSize = newSize;
\r
2060 InitDrawingSizes(boardSize, flags);
\r
2067 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2069 int i, boardWidth;
\r
2070 ChessSquare piece;
\r
2071 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2073 SIZE clockSize, messageSize;
\r
2075 char buf[MSG_SIZ];
\r
2077 HMENU hmenu = GetMenu(hwndMain);
\r
2078 RECT crect, wrect;
\r
2080 LOGBRUSH logbrush;
\r
2082 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2083 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2084 squareSize = sizeInfo[boardSize].squareSize;
\r
2085 lineGap = sizeInfo[boardSize].lineGap;
\r
2087 if (tinyLayout != oldTinyLayout) {
\r
2088 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2090 style &= ~WS_SYSMENU;
\r
2091 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2092 "&Minimize\tCtrl+F4");
\r
2094 style |= WS_SYSMENU;
\r
2095 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2097 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2099 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2100 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2101 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2103 DrawMenuBar(hwndMain);
\r
2106 boardWidth = BoardWidth(boardSize);
\r
2108 /* Get text area sizes */
\r
2109 hdc = GetDC(hwndMain);
\r
2110 if (appData.clockMode) {
\r
2111 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2113 sprintf(buf, "White");
\r
2115 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2116 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2117 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2118 str = "We only care about the height here";
\r
2119 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2120 SelectObject(hdc, oldFont);
\r
2121 ReleaseDC(hwndMain, hdc);
\r
2123 /* Compute where everything goes */
\r
2124 whiteRect.left = OUTER_MARGIN;
\r
2125 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2126 whiteRect.top = OUTER_MARGIN;
\r
2127 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2129 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2130 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2131 blackRect.top = whiteRect.top;
\r
2132 blackRect.bottom = whiteRect.bottom;
\r
2134 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2135 if (appData.showButtonBar) {
\r
2136 messageRect.right = blackRect.right
\r
2137 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2139 messageRect.right = blackRect.right;
\r
2141 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2142 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2144 boardRect.left = whiteRect.left;
\r
2145 boardRect.right = boardRect.left + boardWidth;
\r
2146 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2147 boardRect.bottom = boardRect.top + boardWidth;
\r
2149 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2150 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2151 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2152 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2153 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2154 GetWindowRect(hwndMain, &wrect);
\r
2155 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2156 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2157 /* compensate if menu bar wrapped */
\r
2158 GetClientRect(hwndMain, &crect);
\r
2159 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2160 winHeight += offby;
\r
2162 case WMSZ_TOPLEFT:
\r
2163 SetWindowPos(hwndMain, NULL,
\r
2164 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2165 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2168 case WMSZ_TOPRIGHT:
\r
2170 SetWindowPos(hwndMain, NULL,
\r
2171 wrect.left, wrect.bottom - winHeight,
\r
2172 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2175 case WMSZ_BOTTOMLEFT:
\r
2177 SetWindowPos(hwndMain, NULL,
\r
2178 wrect.right - winWidth, wrect.top,
\r
2179 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2182 case WMSZ_BOTTOMRIGHT:
\r
2186 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2187 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2192 for (i = 0; i < N_BUTTONS; i++) {
\r
2193 if (buttonDesc[i].hwnd != NULL) {
\r
2194 DestroyWindow(buttonDesc[i].hwnd);
\r
2195 buttonDesc[i].hwnd = NULL;
\r
2197 if (appData.showButtonBar) {
\r
2198 buttonDesc[i].hwnd =
\r
2199 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2200 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2201 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2202 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2203 (HMENU) buttonDesc[i].id,
\r
2204 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2206 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2207 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2208 MAKELPARAM(FALSE, 0));
\r
2210 if (buttonDesc[i].id == IDM_Pause)
\r
2211 hwndPause = buttonDesc[i].hwnd;
\r
2212 buttonDesc[i].wndproc = (WNDPROC)
\r
2213 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2216 if (gridPen != NULL) DeleteObject(gridPen);
\r
2217 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2218 if (premovePen != NULL) DeleteObject(premovePen);
\r
2219 if (lineGap != 0) {
\r
2220 logbrush.lbStyle = BS_SOLID;
\r
2221 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2223 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2224 lineGap, &logbrush, 0, NULL);
\r
2225 logbrush.lbColor = highlightSquareColor;
\r
2227 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2228 lineGap, &logbrush, 0, NULL);
\r
2230 logbrush.lbColor = premoveHighlightColor;
\r
2232 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2233 lineGap, &logbrush, 0, NULL);
\r
2235 for (i = 0; i < BOARD_SIZE + 1; i++) {
\r
2236 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2237 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2;
\r
2238 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2239 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2240 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2241 BOARD_SIZE * (squareSize + lineGap);
\r
2242 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x =
\r
2243 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left +
\r
2244 lineGap / 2 + (i * (squareSize + lineGap));
\r
2245 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y =
\r
2246 boardRect.top + BOARD_SIZE * (squareSize + lineGap);
\r
2247 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2251 if (boardSize == oldBoardSize) return;
\r
2252 oldBoardSize = boardSize;
\r
2253 oldTinyLayout = tinyLayout;
\r
2255 /* Load piece bitmaps for this board size */
\r
2256 for (i=0; i<=2; i++) {
\r
2257 for (piece = WhitePawn;
\r
2258 (int) piece <= (int) WhiteKing;
\r
2259 piece = (ChessSquare) ((int) piece + 1)) {
\r
2260 if (pieceBitmap[i][piece] != NULL)
\r
2261 DeleteObject(pieceBitmap[i][piece]);
\r
2265 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2266 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2267 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2268 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2269 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2270 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2271 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2272 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2273 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2274 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2275 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2276 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2277 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2278 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2279 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2280 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2281 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2282 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2287 PieceBitmap(ChessSquare p, int kind)
\r
2289 if ((int) p >= (int) BlackPawn)
\r
2290 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2292 return pieceBitmap[kind][(int) p];
\r
2295 /***************************************************************/
\r
2297 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2298 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2300 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2301 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2305 SquareToPos(int row, int column, int * x, int * y)
\r
2308 *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
2309 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2311 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2312 *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
2317 DrawCoordsOnDC(HDC hdc)
\r
2319 static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'};
\r
2320 static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'};
\r
2321 char str[2] = { NULLCHAR, NULLCHAR };
\r
2322 int oldMode, oldAlign, x, y, start, i;
\r
2326 if (!appData.showCoords)
\r
2329 start = flipView ? 0 : 8;
\r
2331 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2332 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2333 oldAlign = GetTextAlign(hdc);
\r
2334 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2336 y = boardRect.top + lineGap;
\r
2337 x = boardRect.left + lineGap;
\r
2339 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2340 for (i = 0; i < 8; i++) {
\r
2341 str[0] = files[start + i];
\r
2342 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2343 y += squareSize + lineGap;
\r
2346 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2347 for (i = 0; i < 8; i++) {
\r
2348 str[0] = ranks[start + i];
\r
2349 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2350 x += squareSize + lineGap;
\r
2353 SelectObject(hdc, oldBrush);
\r
2354 SetBkMode(hdc, oldMode);
\r
2355 SetTextAlign(hdc, oldAlign);
\r
2356 SelectObject(hdc, oldFont);
\r
2360 DrawGridOnDC(HDC hdc)
\r
2364 if (lineGap != 0) {
\r
2365 oldPen = SelectObject(hdc, gridPen);
\r
2366 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2);
\r
2367 SelectObject(hdc, oldPen);
\r
2371 #define HIGHLIGHT_PEN 0
\r
2372 #define PREMOVE_PEN 1
\r
2375 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2378 HPEN oldPen, hPen;
\r
2379 if (lineGap == 0) return;
\r
2381 x1 = boardRect.left +
\r
2382 lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap);
\r
2383 y1 = boardRect.top +
\r
2384 lineGap/2 + y * (squareSize + lineGap);
\r
2386 x1 = boardRect.left +
\r
2387 lineGap/2 + x * (squareSize + lineGap);
\r
2388 y1 = boardRect.top +
\r
2389 lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap);
\r
2391 hPen = pen ? premovePen : highlightPen;
\r
2392 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2393 MoveToEx(hdc, x1, y1, NULL);
\r
2394 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2395 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2396 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2397 LineTo(hdc, x1, y1);
\r
2398 SelectObject(hdc, oldPen);
\r
2402 DrawHighlightsOnDC(HDC hdc)
\r
2405 for (i=0; i<2; i++) {
\r
2406 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
2407 DrawHighlightOnDC(hdc, TRUE,
\r
2408 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
2411 for (i=0; i<2; i++) {
\r
2412 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2413 premoveHighlightInfo.sq[i].y >= 0) {
\r
2414 DrawHighlightOnDC(hdc, TRUE,
\r
2415 premoveHighlightInfo.sq[i].x,
\r
2416 premoveHighlightInfo.sq[i].y,
\r
2422 /* Note: sqcolor is used only in monoMode */
\r
2423 /* Note that this code is largely duplicated in woptions.c,
\r
2424 function DrawSampleSquare, so that needs to be updated too */
\r
2426 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2428 HBITMAP oldBitmap;
\r
2431 if (appData.blindfold) return;
\r
2433 if (appData.monoMode) {
\r
2434 SelectObject(tmphdc, PieceBitmap(piece,
\r
2435 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2436 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2437 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2440 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2441 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2442 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2444 /* Use black piece color for outline of white pieces */
\r
2445 /* Not sure this looks really good (though xboard does it).
\r
2446 Maybe better to have another selectable color, default black */
\r
2447 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
2448 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2449 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2451 /* Use black for outline of white pieces */
\r
2452 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2453 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
2457 /* Use white piece color for details of black pieces */
\r
2458 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
2459 WHITE_PIECE ones aren't always the right shape. */
\r
2460 /* Not sure this looks really good (though xboard does it).
\r
2461 Maybe better to have another selectable color, default medium gray? */
\r
2462 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
2463 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
2464 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2465 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2466 SelectObject(hdc, blackPieceBrush);
\r
2467 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2469 /* Use square color for details of black pieces */
\r
2470 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2471 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2472 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2475 SelectObject(hdc, oldBrush);
\r
2476 SelectObject(tmphdc, oldBitmap);
\r
2481 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
2483 int row, column, x, y, square_color, piece_color;
\r
2484 ChessSquare piece;
\r
2487 for (row = 0; row < BOARD_SIZE; row++) {
\r
2488 for (column = 0; column < BOARD_SIZE; column++) {
\r
2490 SquareToPos(row, column, &x, &y);
\r
2492 piece = board[row][column];
\r
2494 square_color = ((column + row) % 2) == 1;
\r
2495 piece_color = (int) piece < (int) BlackPawn;
\r
2497 if (appData.monoMode) {
\r
2498 if (piece == EmptySquare) {
\r
2499 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
2500 square_color ? WHITENESS : BLACKNESS);
\r
2502 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
2505 oldBrush = SelectObject(hdc, square_color ?
\r
2506 lightSquareBrush : darkSquareBrush);
\r
2507 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
2508 SelectObject(hdc, oldBrush);
\r
2509 if (piece != EmptySquare)
\r
2510 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
2516 #define MAX_CLIPS 200 /* more than enough */
\r
2519 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
2521 static Board lastReq, lastDrawn;
\r
2522 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
2523 static int lastDrawnFlipView = 0;
\r
2524 static int lastReqValid = 0, lastDrawnValid = 0;
\r
2525 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
2528 HBITMAP bufferBitmap;
\r
2529 HBITMAP oldBitmap;
\r
2531 HRGN clips[MAX_CLIPS];
\r
2532 ChessSquare dragged_piece = EmptySquare;
\r
2534 /* I'm undecided on this - this function figures out whether a full
\r
2535 * repaint is necessary on its own, so there's no real reason to have the
\r
2536 * caller tell it that. I think this can safely be set to FALSE - but
\r
2537 * if we trust the callers not to request full repaints unnessesarily, then
\r
2538 * we could skip some clipping work. In other words, only request a full
\r
2539 * redraw when the majority of pieces have changed positions (ie. flip,
\r
2540 * gamestart and similar) --Hawk
\r
2542 Boolean fullrepaint = repaint;
\r
2544 if (board == NULL) {
\r
2545 if (!lastReqValid) {
\r
2550 CopyBoard(lastReq, board);
\r
2554 if (doingSizing) {
\r
2558 if (IsIconic(hwndMain)) {
\r
2562 if (hdc == NULL) {
\r
2563 hdc = GetDC(hwndMain);
\r
2564 if (!appData.monoMode) {
\r
2565 SelectPalette(hdc, hPal, FALSE);
\r
2566 RealizePalette(hdc);
\r
2570 releaseDC = FALSE;
\r
2574 fprintf(debugFP, "*******************************\n"
\r
2576 "dragInfo.from (%d,%d)\n"
\r
2577 "dragInfo.start (%d,%d)\n"
\r
2578 "dragInfo.pos (%d,%d)\n"
\r
2579 "dragInfo.lastpos (%d,%d)\n",
\r
2580 repaint ? "TRUE" : "FALSE",
\r
2581 dragInfo.from.x, dragInfo.from.y,
\r
2582 dragInfo.start.x, dragInfo.start.y,
\r
2583 dragInfo.pos.x, dragInfo.pos.y,
\r
2584 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
2585 fprintf(debugFP, "prev: ");
\r
2586 for (row = 0; row < 8; row++) {
\r
2587 for (column = 0; column < 8; column++) {
\r
2588 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
2591 fprintf(debugFP, "\n");
\r
2592 fprintf(debugFP, "board: ");
\r
2593 for (row = 0; row < 8; row++) {
\r
2594 for (column = 0; column < 8; column++) {
\r
2595 fprintf(debugFP, "%d ", board[row][column]);
\r
2598 fprintf(debugFP, "\n");
\r
2602 /* Create some work-DCs */
\r
2603 hdcmem = CreateCompatibleDC(hdc);
\r
2604 tmphdc = CreateCompatibleDC(hdc);
\r
2606 /* Figure out which squares need updating by comparing the
\r
2607 * newest board with the last drawn board and checking if
\r
2608 * flipping has changed.
\r
2610 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
2611 for (row = 0; row < 8; row++) {
\r
2612 for (column = 0; column < 8; column++) {
\r
2613 if (lastDrawn[row][column] != board[row][column]) {
\r
2614 SquareToPos(row, column, &x, &y);
\r
2615 clips[num_clips++] =
\r
2616 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
2620 for (i=0; i<2; i++) {
\r
2621 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
2622 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
2623 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
2624 lastDrawnHighlight.sq[i].y >= 0) {
\r
2625 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
2626 lastDrawnHighlight.sq[i].x, &x, &y);
\r
2627 clips[num_clips++] =
\r
2628 CreateRectRgn(x - lineGap, y - lineGap,
\r
2629 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2631 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
2632 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
2633 clips[num_clips++] =
\r
2634 CreateRectRgn(x - lineGap, y - lineGap,
\r
2635 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2639 for (i=0; i<2; i++) {
\r
2640 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
2641 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
2642 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
2643 lastDrawnPremove.sq[i].y >= 0) {
\r
2644 SquareToPos(lastDrawnPremove.sq[i].y,
\r
2645 lastDrawnPremove.sq[i].x, &x, &y);
\r
2646 clips[num_clips++] =
\r
2647 CreateRectRgn(x - lineGap, y - lineGap,
\r
2648 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2650 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2651 premoveHighlightInfo.sq[i].y >= 0) {
\r
2652 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
2653 premoveHighlightInfo.sq[i].x, &x, &y);
\r
2654 clips[num_clips++] =
\r
2655 CreateRectRgn(x - lineGap, y - lineGap,
\r
2656 x + squareSize + lineGap, y + squareSize + lineGap);
\r
2661 fullrepaint = TRUE;
\r
2664 /* Create a buffer bitmap - this is the actual bitmap
\r
2665 * being written to. When all the work is done, we can
\r
2666 * copy it to the real DC (the screen). This avoids
\r
2667 * the problems with flickering.
\r
2669 GetClientRect(hwndMain, &Rect);
\r
2670 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
2671 Rect.bottom-Rect.top+1);
\r
2672 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
2673 if (!appData.monoMode) {
\r
2674 SelectPalette(hdcmem, hPal, FALSE);
\r
2677 /* Create clips for dragging */
\r
2678 if (!fullrepaint) {
\r
2679 if (dragInfo.from.x >= 0) {
\r
2680 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
2681 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2683 if (dragInfo.start.x >= 0) {
\r
2684 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
2685 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2687 if (dragInfo.pos.x >= 0) {
\r
2688 x = dragInfo.pos.x - squareSize / 2;
\r
2689 y = dragInfo.pos.y - squareSize / 2;
\r
2690 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2692 if (dragInfo.lastpos.x >= 0) {
\r
2693 x = dragInfo.lastpos.x - squareSize / 2;
\r
2694 y = dragInfo.lastpos.y - squareSize / 2;
\r
2695 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
2699 /* If dragging is in progress, we temporarely remove the piece */
\r
2700 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
2701 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
2702 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
2705 /* Are we animating a move?
\r
2707 * - remove the piece from the board (temporarely)
\r
2708 * - calculate the clipping region
\r
2710 if (!fullrepaint) {
\r
2711 if (animInfo.piece != EmptySquare) {
\r
2712 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
2713 x = boardRect.left + animInfo.lastpos.x;
\r
2714 y = boardRect.top + animInfo.lastpos.y;
\r
2715 x2 = boardRect.left + animInfo.pos.x;
\r
2716 y2 = boardRect.top + animInfo.pos.y;
\r
2717 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
2718 /* Slight kludge. The real problem is that after AnimateMove is
\r
2719 done, the position on the screen does not match lastDrawn.
\r
2720 This currently causes trouble only on e.p. captures in
\r
2721 atomic, where the piece moves to an empty square and then
\r
2722 explodes. The old and new positions both had an empty square
\r
2723 at the destination, but animation has drawn a piece there and
\r
2724 we have to remember to erase it. */
\r
2725 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
2729 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
2730 if (num_clips == 0)
\r
2731 fullrepaint = TRUE;
\r
2733 /* Set clipping on the memory DC */
\r
2734 if (!fullrepaint) {
\r
2735 SelectClipRgn(hdcmem, clips[0]);
\r
2736 for (x = 1; x < num_clips; x++) {
\r
2737 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
2738 abort(); // this should never ever happen!
\r
2742 /* Do all the drawing to the memory DC */
\r
2743 DrawGridOnDC(hdcmem);
\r
2744 DrawHighlightsOnDC(hdcmem);
\r
2745 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
2746 DrawCoordsOnDC(hdcmem);
\r
2748 /* Put the dragged piece back into place and draw it */
\r
2749 if (dragged_piece != EmptySquare) {
\r
2750 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
2751 x = dragInfo.pos.x - squareSize / 2;
\r
2752 y = dragInfo.pos.y - squareSize / 2;
\r
2753 DrawPieceOnDC(hdcmem, dragged_piece,
\r
2754 ((int) dragged_piece < (int) BlackPawn),
\r
2755 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
2758 /* Put the animated piece back into place and draw it */
\r
2759 if (animInfo.piece != EmptySquare) {
\r
2760 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
2761 x = boardRect.left + animInfo.pos.x;
\r
2762 y = boardRect.top + animInfo.pos.y;
\r
2763 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
2764 ((int) animInfo.piece < (int) BlackPawn),
\r
2765 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
2768 /* Release the bufferBitmap by selecting in the old bitmap
\r
2769 * and delete the memory DC
\r
2771 SelectObject(hdcmem, oldBitmap);
\r
2774 /* Set clipping on the target DC */
\r
2775 if (!fullrepaint) {
\r
2776 SelectClipRgn(hdc, clips[0]);
\r
2777 for (x = 1; x < num_clips; x++) {
\r
2778 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
2779 abort(); // this should never ever happen!
\r
2783 /* Copy the new bitmap onto the screen in one go.
\r
2784 * This way we avoid any flickering
\r
2786 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
2787 BitBlt(hdc, boardRect.left, boardRect.top,
\r
2788 boardRect.right - boardRect.left,
\r
2789 boardRect.bottom - boardRect.top,
\r
2790 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
2791 SelectObject(tmphdc, oldBitmap);
\r
2793 /* Massive cleanup */
\r
2794 for (x = 0; x < num_clips; x++)
\r
2795 DeleteObject(clips[x]);
\r
2798 DeleteObject(bufferBitmap);
\r
2801 ReleaseDC(hwndMain, hdc);
\r
2803 if (lastDrawnFlipView != flipView) {
\r
2805 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
2807 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
2810 CopyBoard(lastDrawn, board);
\r
2811 lastDrawnHighlight = highlightInfo;
\r
2812 lastDrawnPremove = premoveHighlightInfo;
\r
2813 lastDrawnFlipView = flipView;
\r
2814 lastDrawnValid = 1;
\r
2818 /*---------------------------------------------------------------------------*\
\r
2819 | CLIENT PAINT PROCEDURE
\r
2820 | This is the main event-handler for the WM_PAINT message.
\r
2822 \*---------------------------------------------------------------------------*/
\r
2824 PaintProc(HWND hwnd)
\r
2830 if(hdc = BeginPaint(hwnd, &ps)) {
\r
2831 if (IsIconic(hwnd)) {
\r
2832 DrawIcon(hdc, 2, 2, iconCurrent);
\r
2834 if (!appData.monoMode) {
\r
2835 SelectPalette(hdc, hPal, FALSE);
\r
2836 RealizePalette(hdc);
\r
2838 HDCDrawPosition(hdc, 1, NULL);
\r
2840 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2841 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
2842 ETO_CLIPPED|ETO_OPAQUE,
\r
2843 &messageRect, messageText, strlen(messageText), NULL);
\r
2844 SelectObject(hdc, oldFont);
\r
2845 DisplayBothClocks();
\r
2847 EndPaint(hwnd,&ps);
\r
2855 * If the user selects on a border boundary, return -1; if off the board,
\r
2856 * return -2. Otherwise map the event coordinate to the square.
\r
2857 * The offset boardRect.left or boardRect.top must already have been
\r
2858 * subtracted from x.
\r
2861 EventToSquare(int x)
\r
2868 if ((x % (squareSize + lineGap)) >= squareSize)
\r
2870 x /= (squareSize + lineGap);
\r
2871 if (x >= BOARD_SIZE)
\r
2882 DropEnable dropEnables[] = {
\r
2883 { 'P', DP_Pawn, "Pawn" },
\r
2884 { 'N', DP_Knight, "Knight" },
\r
2885 { 'B', DP_Bishop, "Bishop" },
\r
2886 { 'R', DP_Rook, "Rook" },
\r
2887 { 'Q', DP_Queen, "Queen" },
\r
2891 SetupDropMenu(HMENU hmenu)
\r
2893 int i, count, enable;
\r
2895 extern char white_holding[], black_holding[];
\r
2896 char item[MSG_SIZ];
\r
2898 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
2899 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
2900 dropEnables[i].piece);
\r
2902 while (p && *p++ == dropEnables[i].piece) count++;
\r
2903 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
2904 enable = count > 0 || !appData.testLegality
\r
2905 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
2906 && !appData.icsActive);
\r
2907 ModifyMenu(hmenu, dropEnables[i].command,
\r
2908 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
2909 dropEnables[i].command, item);
\r
2913 static int fromX = -1, fromY = -1, toX, toY;
\r
2915 /* Event handler for mouse messages */
\r
2917 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
2921 static int recursive = 0;
\r
2923 BOOLEAN saveAnimate;
\r
2924 static BOOLEAN sameAgain = FALSE;
\r
2927 if (message == WM_MBUTTONUP) {
\r
2928 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
2929 to the middle button: we simulate pressing the left button too!
\r
2931 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
2932 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
2938 pt.x = LOWORD(lParam);
\r
2939 pt.y = HIWORD(lParam);
\r
2940 x = EventToSquare(pt.x - boardRect.left);
\r
2941 y = EventToSquare(pt.y - boardRect.top);
\r
2942 if (!flipView && y >= 0) {
\r
2943 y = BOARD_SIZE - 1 - y;
\r
2945 if (flipView && x >= 0) {
\r
2946 x = BOARD_SIZE - 1 - x;
\r
2949 switch (message) {
\r
2950 case WM_LBUTTONDOWN:
\r
2952 sameAgain = FALSE;
\r
2954 /* Downclick vertically off board; check if on clock */
\r
2955 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
2956 if (gameMode == EditPosition) {
\r
2957 SetWhiteToPlayEvent();
\r
2958 } else if (gameMode == IcsPlayingBlack ||
\r
2959 gameMode == MachinePlaysWhite) {
\r
2962 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
2963 if (gameMode == EditPosition) {
\r
2964 SetBlackToPlayEvent();
\r
2965 } else if (gameMode == IcsPlayingWhite ||
\r
2966 gameMode == MachinePlaysBlack) {
\r
2970 if (!appData.highlightLastMove) {
\r
2971 ClearHighlights();
\r
2972 DrawPosition(FALSE, NULL);
\r
2974 fromX = fromY = -1;
\r
2975 dragInfo.start.x = dragInfo.start.y = -1;
\r
2976 dragInfo.from = dragInfo.start;
\r
2978 } else if (x < 0 || y < 0) {
\r
2980 } else if (fromX == x && fromY == y) {
\r
2981 /* Downclick on same square again */
\r
2982 ClearHighlights();
\r
2983 DrawPosition(FALSE, NULL);
\r
2984 sameAgain = TRUE;
\r
2985 } else if (fromX != -1) {
\r
2986 /* Downclick on different square */
\r
2987 ChessSquare pdown, pup;
\r
2988 pdown = boards[currentMove][fromY][fromX];
\r
2989 pup = boards[currentMove][y][x];
\r
2990 if (gameMode == EditPosition ||
\r
2991 !((WhitePawn <= pdown && pdown <= WhiteKing &&
\r
2992 WhitePawn <= pup && pup <= WhiteKing) ||
\r
2993 (BlackPawn <= pdown && pdown <= BlackKing &&
\r
2994 BlackPawn <= pup && pup <= BlackKing))) {
\r
2995 /* EditPosition, empty square, or different color piece;
\r
2996 click-click move is possible */
\r
2999 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
3000 if (appData.alwaysPromoteToQueen) {
\r
3001 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3002 if (!appData.highlightLastMove) {
\r
3003 ClearHighlights();
\r
3004 DrawPosition(FALSE, NULL);
\r
3007 SetHighlights(fromX, fromY, toX, toY);
\r
3008 DrawPosition(FALSE, NULL);
\r
3009 PromotionPopup(hwnd);
\r
3011 } else { /* not a promotion */
\r
3012 if (appData.animate || appData.highlightLastMove) {
\r
3013 SetHighlights(fromX, fromY, toX, toY);
\r
3015 ClearHighlights();
\r
3017 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3018 if (appData.animate && !appData.highlightLastMove) {
\r
3019 ClearHighlights();
\r
3020 DrawPosition(FALSE, NULL);
\r
3023 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3024 fromX = fromY = -1;
\r
3027 ClearHighlights();
\r
3028 DrawPosition(FALSE, NULL);
\r
3030 /* First downclick, or restart on a square with same color piece */
\r
3031 if (!frozen && OKToStartUserMove(x, y)) {
\r
3034 dragInfo.lastpos = pt;
\r
3035 dragInfo.from.x = fromX;
\r
3036 dragInfo.from.y = fromY;
\r
3037 dragInfo.start = dragInfo.from;
\r
3038 SetCapture(hwndMain);
\r
3040 fromX = fromY = -1;
\r
3041 dragInfo.start.x = dragInfo.start.y = -1;
\r
3042 dragInfo.from = dragInfo.start;
\r
3046 case WM_LBUTTONUP:
\r
3048 if (fromX == -1) break;
\r
3049 if (x == fromX && y == fromY) {
\r
3050 dragInfo.from.x = dragInfo.from.y = -1;
\r
3051 /* Upclick on same square */
\r
3053 /* Clicked same square twice: abort click-click move */
\r
3054 fromX = fromY = -1;
\r
3056 ClearPremoveHighlights();
\r
3058 /* First square clicked: start click-click move */
\r
3059 SetHighlights(fromX, fromY, -1, -1);
\r
3061 DrawPosition(FALSE, NULL);
\r
3062 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
3063 /* Errant click; ignore */
\r
3066 /* Finish drag move */
\r
3067 dragInfo.from.x = dragInfo.from.y = -1;
\r
3070 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
3071 appData.animate = appData.animate && !appData.animateDragging;
\r
3072 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
3073 if (appData.alwaysPromoteToQueen) {
\r
3074 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3076 DrawPosition(FALSE, NULL);
\r
3077 PromotionPopup(hwnd);
\r
3080 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3082 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3083 appData.animate = saveAnimate;
\r
3084 fromX = fromY = -1;
\r
3085 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
3086 ClearHighlights();
\r
3088 if (appData.animate || appData.animateDragging ||
\r
3089 appData.highlightDragging || gotPremove) {
\r
3090 DrawPosition(FALSE, NULL);
\r
3093 dragInfo.start.x = dragInfo.start.y = -1;
\r
3094 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
3097 case WM_MOUSEMOVE:
\r
3098 if ((appData.animateDragging || appData.highlightDragging)
\r
3099 && (wParam & MK_LBUTTON)
\r
3100 && dragInfo.from.x >= 0) {
\r
3101 if (appData.animateDragging) {
\r
3102 dragInfo.pos = pt;
\r
3104 if (appData.highlightDragging) {
\r
3105 SetHighlights(fromX, fromY, x, y);
\r
3107 DrawPosition(FALSE, NULL);
\r
3108 dragInfo.lastpos = dragInfo.pos;
\r
3111 case WM_MOUSEWHEEL:
\r
3112 /* Mouse Wheel is being rolled forward
\r
3113 * Play moves forward
\r
3115 if((short)HIWORD(wParam) > 0 ) ForwardEvent();
\r
3116 /* Mouse Wheel is being rolled backward
\r
3117 * Play moves backward
\r
3119 if((short)HIWORD(wParam) < 0 ) BackwardEvent();
\r
3121 case WM_MBUTTONDOWN:
\r
3122 case WM_RBUTTONDOWN:
\r
3125 fromX = fromY = -1;
\r
3126 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
3127 dragInfo.start.x = dragInfo.start.y = -1;
\r
3128 dragInfo.from = dragInfo.start;
\r
3129 dragInfo.lastpos = dragInfo.pos;
\r
3130 if (appData.highlightDragging) {
\r
3131 ClearHighlights();
\r
3133 DrawPosition(TRUE, NULL);
\r
3135 switch (gameMode) {
\r
3136 case EditPosition:
\r
3137 case IcsExamining:
\r
3138 if (x < 0 || y < 0) break;
\r
3141 if (message == WM_MBUTTONDOWN) {
\r
3142 buttonCount = 3; /* even if system didn't think so */
\r
3143 if (wParam & MK_SHIFT)
\r
3144 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3146 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3147 } else { /* message == WM_RBUTTONDOWN */
\r
3149 if (buttonCount == 3) {
\r
3150 if (wParam & MK_SHIFT)
\r
3151 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3153 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3155 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3158 /* Just have one menu, on the right button. Windows users don't
\r
3159 think to try the middle one, and sometimes other software steals
\r
3160 it, or it doesn't really exist. */
\r
3161 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3165 case IcsPlayingWhite:
\r
3166 case IcsPlayingBlack:
\r
3168 case MachinePlaysWhite:
\r
3169 case MachinePlaysBlack:
\r
3170 if (appData.testLegality &&
\r
3171 gameInfo.variant != VariantBughouse &&
\r
3172 gameInfo.variant != VariantCrazyhouse) break;
\r
3173 if (x < 0 || y < 0) break;
\r
3176 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
3177 SetupDropMenu(hmenu);
\r
3178 MenuPopup(hwnd, pt, hmenu, -1);
\r
3189 /* Preprocess messages for buttons in main window */
\r
3191 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3193 int id = GetWindowLong(hwnd, GWL_ID);
\r
3196 for (i=0; i<N_BUTTONS; i++) {
\r
3197 if (buttonDesc[i].id == id) break;
\r
3199 if (i == N_BUTTONS) return 0;
\r
3200 switch (message) {
\r
3205 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
3206 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
3213 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
3216 if (appData.icsActive) {
\r
3217 if (GetKeyState(VK_SHIFT) < 0) {
\r
3219 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3220 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3224 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3225 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3232 if (appData.icsActive) {
\r
3233 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3234 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3236 SendMessage(h, WM_CHAR, wParam, lParam);
\r
3238 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
3239 PopUpMoveDialog((char)wParam);
\r
3245 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
3248 /* Process messages for Promotion dialog box */
\r
3250 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
3254 switch (message) {
\r
3255 case WM_INITDIALOG: /* message: initialize dialog box */
\r
3256 /* Center the dialog over the application window */
\r
3257 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
3258 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
3259 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
3260 gameInfo.variant == VariantGiveaway) ?
\r
3261 SW_SHOW : SW_HIDE);
\r
3264 case WM_COMMAND: /* message: received a command */
\r
3265 switch (LOWORD(wParam)) {
\r
3267 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3268 ClearHighlights();
\r
3269 DrawPosition(FALSE, NULL);
\r
3289 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3290 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
3291 if (!appData.highlightLastMove) {
\r
3292 ClearHighlights();
\r
3293 DrawPosition(FALSE, NULL);
\r
3300 /* Pop up promotion dialog */
\r
3302 PromotionPopup(HWND hwnd)
\r
3306 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
3307 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
3308 hwnd, (DLGPROC)lpProc);
\r
3309 FreeProcInstance(lpProc);
\r
3312 /* Toggle ShowThinking */
\r
3314 ToggleShowThinking()
\r
3316 ShowThinkingEvent(!appData.showThinking);
\r
3320 LoadGameDialog(HWND hwnd, char* title)
\r
3324 char fileTitle[MSG_SIZ];
\r
3325 f = OpenFileDialog(hwnd, FALSE, "",
\r
3326 appData.oldSaveStyle ? "gam" : "pgn",
\r
3328 title, &number, fileTitle, NULL);
\r
3330 cmailMsgLoaded = FALSE;
\r
3331 if (number == 0) {
\r
3332 int error = GameListBuild(f);
\r
3334 DisplayError("Cannot build game list", error);
\r
3335 } else if (!ListEmpty(&gameList) &&
\r
3336 ((ListGame *) gameList.tailPred)->number > 1) {
\r
3337 GameListPopUp(f, fileTitle);
\r
3340 GameListDestroy();
\r
3343 LoadGame(f, number, fileTitle, FALSE);
\r
3348 ChangedConsoleFont()
\r
3351 CHARRANGE tmpsel, sel;
\r
3352 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
3353 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3354 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3357 cfmt.cbSize = sizeof(CHARFORMAT);
\r
3358 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
3359 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
3360 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
3361 * size. This was undocumented in the version of MSVC++ that I had
\r
3362 * when I wrote the code, but is apparently documented now.
\r
3364 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
3365 cfmt.bCharSet = f->lf.lfCharSet;
\r
3366 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
3367 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
3368 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
3369 /* Why are the following seemingly needed too? */
\r
3370 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
3371 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
3372 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
3374 tmpsel.cpMax = -1; /*999999?*/
\r
3375 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
3376 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
3377 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
3378 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
3380 paraf.cbSize = sizeof(paraf);
\r
3381 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
3382 paraf.dxStartIndent = 0;
\r
3383 paraf.dxOffset = WRAP_INDENT;
\r
3384 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
3385 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
3388 /*---------------------------------------------------------------------------*\
\r
3390 * Window Proc for main window
\r
3392 \*---------------------------------------------------------------------------*/
\r
3394 /* Process messages for main window, etc. */
\r
3396 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3399 int wmId, wmEvent;
\r
3403 char fileTitle[MSG_SIZ];
\r
3405 switch (message) {
\r
3407 case WM_PAINT: /* message: repaint portion of window */
\r
3411 case WM_ERASEBKGND:
\r
3412 if (IsIconic(hwnd)) {
\r
3413 /* Cheat; change the message */
\r
3414 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
3416 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
3420 case WM_LBUTTONDOWN:
\r
3421 case WM_MBUTTONDOWN:
\r
3422 case WM_RBUTTONDOWN:
\r
3423 case WM_LBUTTONUP:
\r
3424 case WM_MBUTTONUP:
\r
3425 case WM_RBUTTONUP:
\r
3426 case WM_MOUSEMOVE:
\r
3427 case WM_MOUSEWHEEL:
\r
3428 MouseEvent(hwnd, message, wParam, lParam);
\r
3433 if (appData.icsActive) {
\r
3434 if (wParam == '\t') {
\r
3435 if (GetKeyState(VK_SHIFT) < 0) {
\r
3437 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3438 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3442 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3443 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3447 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3448 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3450 SendMessage(h, message, wParam, lParam);
\r
3452 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
3453 PopUpMoveDialog((char)wParam);
\r
3457 case WM_PALETTECHANGED:
\r
3458 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
3460 HDC hdc = GetDC(hwndMain);
\r
3461 SelectPalette(hdc, hPal, TRUE);
\r
3462 nnew = RealizePalette(hdc);
\r
3464 paletteChanged = TRUE;
\r
3466 UpdateColors(hdc);
\r
3468 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
3471 ReleaseDC(hwnd, hdc);
\r
3475 case WM_QUERYNEWPALETTE:
\r
3476 if (!appData.monoMode /*&& paletteChanged*/) {
\r
3478 HDC hdc = GetDC(hwndMain);
\r
3479 paletteChanged = FALSE;
\r
3480 SelectPalette(hdc, hPal, FALSE);
\r
3481 nnew = RealizePalette(hdc);
\r
3483 InvalidateRect(hwnd, &boardRect, FALSE);
\r
3485 ReleaseDC(hwnd, hdc);
\r
3490 case WM_COMMAND: /* message: command from application menu */
\r
3491 wmId = LOWORD(wParam);
\r
3492 wmEvent = HIWORD(wParam);
\r
3497 AnalysisPopDown();
\r
3500 case IDM_LoadGame:
\r
3501 LoadGameDialog(hwnd, "Load Game from File");
\r
3504 case IDM_LoadNextGame:
\r
3508 case IDM_LoadPrevGame:
\r
3512 case IDM_ReloadGame:
\r
3516 case IDM_LoadPosition:
\r
3517 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
3518 Reset(FALSE, TRUE);
\r
3521 f = OpenFileDialog(hwnd, FALSE, "",
\r
3522 appData.oldSaveStyle ? "pos" : "fen",
\r
3524 "Load Position from File", &number, fileTitle, NULL);
\r
3526 LoadPosition(f, number, fileTitle);
\r
3530 case IDM_LoadNextPosition:
\r
3531 ReloadPosition(1);
\r
3534 case IDM_LoadPrevPosition:
\r
3535 ReloadPosition(-1);
\r
3538 case IDM_ReloadPosition:
\r
3539 ReloadPosition(0);
\r
3542 case IDM_SaveGame:
\r
3543 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
3544 f = OpenFileDialog(hwnd, TRUE, defName,
\r
3545 appData.oldSaveStyle ? "gam" : "pgn",
\r
3547 "Save Game to File", NULL, fileTitle, NULL);
\r
3549 SaveGame(f, 0, "");
\r
3553 case IDM_SavePosition:
\r
3554 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
3555 f = OpenFileDialog(hwnd, TRUE, defName,
\r
3556 appData.oldSaveStyle ? "pos" : "fen",
\r
3558 "Save Position to File", NULL, fileTitle, NULL);
\r
3560 SavePosition(f, 0, "");
\r
3564 case IDM_CopyGame:
\r
3565 CopyGameToClipboard();
\r
3568 case IDM_PasteGame:
\r
3569 PasteGameFromClipboard();
\r
3572 case IDM_CopyPosition:
\r
3573 CopyFENToClipboard();
\r
3576 case IDM_PastePosition:
\r
3577 PasteFENFromClipboard();
\r
3580 case IDM_MailMove:
\r
3584 case IDM_ReloadCMailMsg:
\r
3585 Reset(TRUE, TRUE);
\r
3586 ReloadCmailMsgEvent(FALSE);
\r
3589 case IDM_Minimize:
\r
3590 ShowWindow(hwnd, SW_MINIMIZE);
\r
3597 case IDM_MachineWhite:
\r
3598 MachineWhiteEvent();
\r
3600 * refresh the tags dialog only if it's visible
\r
3602 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
3604 tags = PGNTags(&gameInfo);
\r
3605 TagsPopUp(tags, CmailMsg());
\r
3610 case IDM_MachineBlack:
\r
3611 MachineBlackEvent();
\r
3613 * refresh the tags dialog only if it's visible
\r
3615 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
3617 tags = PGNTags(&gameInfo);
\r
3618 TagsPopUp(tags, CmailMsg());
\r
3623 case IDM_TwoMachines:
\r
3624 TwoMachinesEvent();
\r
3626 * refresh the tags dialog only if it's visible
\r
3628 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
3630 tags = PGNTags(&gameInfo);
\r
3631 TagsPopUp(tags, CmailMsg());
\r
3636 case IDM_AnalysisMode:
\r
3637 if (!first.analysisSupport) {
\r
3638 char buf[MSG_SIZ];
\r
3639 sprintf(buf, "%s does not support analysis", first.tidy);
\r
3640 DisplayError(buf, 0);
\r
3642 if (!appData.showThinking) ToggleShowThinking();
\r
3643 AnalyzeModeEvent();
\r
3647 case IDM_AnalyzeFile:
\r
3648 if (!first.analysisSupport) {
\r
3649 char buf[MSG_SIZ];
\r
3650 sprintf(buf, "%s does not support analysis", first.tidy);
\r
3651 DisplayError(buf, 0);
\r
3653 if (!appData.showThinking) ToggleShowThinking();
\r
3654 AnalyzeFileEvent();
\r
3655 LoadGameDialog(hwnd, "Analyze Game from File");
\r
3656 AnalysisPeriodicEvent(1);
\r
3660 case IDM_IcsClient:
\r
3664 case IDM_EditGame:
\r
3668 case IDM_EditPosition:
\r
3669 EditPositionEvent();
\r
3672 case IDM_Training:
\r
3676 case IDM_ShowGameList:
\r
3677 ShowGameListProc();
\r
3680 case IDM_EditTags:
\r
3684 case IDM_EditComment:
\r
3685 if (commentDialogUp && editComment) {
\r
3688 EditCommentEvent();
\r
3708 case IDM_CallFlag:
\r
3728 case IDM_StopObserving:
\r
3729 StopObservingEvent();
\r
3732 case IDM_StopExamining:
\r
3733 StopExaminingEvent();
\r
3736 case IDM_TypeInMove:
\r
3737 PopUpMoveDialog('\000');
\r
3740 case IDM_Backward:
\r
3742 SetFocus(hwndMain);
\r
3747 SetFocus(hwndMain);
\r
3752 SetFocus(hwndMain);
\r
3757 SetFocus(hwndMain);
\r
3764 case IDM_TruncateGame:
\r
3765 TruncateGameEvent();
\r
3772 case IDM_RetractMove:
\r
3773 RetractMoveEvent();
\r
3776 case IDM_FlipView:
\r
3777 flipView = !flipView;
\r
3778 DrawPosition(FALSE, NULL);
\r
3781 case IDM_GeneralOptions:
\r
3782 GeneralOptionsPopup(hwnd);
\r
3785 case IDM_BoardOptions:
\r
3786 BoardOptionsPopup(hwnd);
\r
3789 case IDM_IcsOptions:
\r
3790 IcsOptionsPopup(hwnd);
\r
3794 FontsOptionsPopup(hwnd);
\r
3798 SoundOptionsPopup(hwnd);
\r
3801 case IDM_CommPort:
\r
3802 CommPortOptionsPopup(hwnd);
\r
3805 case IDM_LoadOptions:
\r
3806 LoadOptionsPopup(hwnd);
\r
3809 case IDM_SaveOptions:
\r
3810 SaveOptionsPopup(hwnd);
\r
3813 case IDM_TimeControl:
\r
3814 TimeControlOptionsPopup(hwnd);
\r
3817 case IDM_SaveSettings:
\r
3818 SaveSettings(settingsFileName);
\r
3821 case IDM_SaveSettingsOnExit:
\r
3822 saveSettingsOnExit = !saveSettingsOnExit;
\r
3823 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
3824 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
3825 MF_CHECKED : MF_UNCHECKED));
\r
3836 case IDM_AboutGame:
\r
3841 appData.debugMode = !appData.debugMode;
\r
3842 if (appData.debugMode) {
\r
3843 char dir[MSG_SIZ];
\r
3844 GetCurrentDirectory(MSG_SIZ, dir);
\r
3845 SetCurrentDirectory(installDir);
\r
3846 debugFP = fopen("WinBoard.debug", "w");
\r
3847 SetCurrentDirectory(dir);
\r
3848 setbuf(debugFP, NULL);
\r
3855 case IDM_HELPCONTENTS:
\r
3856 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
3857 MessageBox (GetFocus(),
\r
3858 "Unable to activate help",
\r
3859 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3863 case IDM_HELPSEARCH:
\r
3864 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
3865 MessageBox (GetFocus(),
\r
3866 "Unable to activate help",
\r
3867 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3871 case IDM_HELPHELP:
\r
3872 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
3873 MessageBox (GetFocus(),
\r
3874 "Unable to activate help",
\r
3875 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3880 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
3882 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
3883 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
3884 FreeProcInstance(lpProc);
\r
3887 case IDM_DirectCommand1:
\r
3888 AskQuestionEvent("Direct Command",
\r
3889 "Send to chess program:", "", "1");
\r
3891 case IDM_DirectCommand2:
\r
3892 AskQuestionEvent("Direct Command",
\r
3893 "Send to second chess program:", "", "2");
\r
3896 case EP_WhitePawn:
\r
3897 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
3898 fromX = fromY = -1;
\r
3901 case EP_WhiteKnight:
\r
3902 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
3903 fromX = fromY = -1;
\r
3906 case EP_WhiteBishop:
\r
3907 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
3908 fromX = fromY = -1;
\r
3911 case EP_WhiteRook:
\r
3912 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
3913 fromX = fromY = -1;
\r
3916 case EP_WhiteQueen:
\r
3917 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
3918 fromX = fromY = -1;
\r
3921 case EP_WhiteKing:
\r
3922 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
3923 fromX = fromY = -1;
\r
3926 case EP_BlackPawn:
\r
3927 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
3928 fromX = fromY = -1;
\r
3931 case EP_BlackKnight:
\r
3932 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
3933 fromX = fromY = -1;
\r
3936 case EP_BlackBishop:
\r
3937 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
3938 fromX = fromY = -1;
\r
3941 case EP_BlackRook:
\r
3942 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
3943 fromX = fromY = -1;
\r
3946 case EP_BlackQueen:
\r
3947 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
3948 fromX = fromY = -1;
\r
3951 case EP_BlackKing:
\r
3952 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
3953 fromX = fromY = -1;
\r
3956 case EP_EmptySquare:
\r
3957 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
3958 fromX = fromY = -1;
\r
3961 case EP_ClearBoard:
\r
3962 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
3963 fromX = fromY = -1;
\r
3967 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
3968 fromX = fromY = -1;
\r
3972 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
3973 fromX = fromY = -1;
\r
3977 DropMenuEvent(WhitePawn, fromX, fromY);
\r
3978 fromX = fromY = -1;
\r
3982 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
3983 fromX = fromY = -1;
\r
3987 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
3988 fromX = fromY = -1;
\r
3992 DropMenuEvent(WhiteRook, fromX, fromY);
\r
3993 fromX = fromY = -1;
\r
3997 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
3998 fromX = fromY = -1;
\r
4002 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4008 case CLOCK_TIMER_ID:
\r
4009 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
4010 clockTimerEvent = 0;
\r
4011 DecrementClocks(); /* call into back end */
\r
4013 case LOAD_GAME_TIMER_ID:
\r
4014 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
4015 loadGameTimerEvent = 0;
\r
4016 AutoPlayGameLoop(); /* call into back end */
\r
4018 case ANALYSIS_TIMER_ID:
\r
4019 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
4020 appData.periodicUpdates) {
\r
4021 AnalysisPeriodicEvent(0);
\r
4023 KillTimer(hwnd, analysisTimerEvent);
\r
4024 analysisTimerEvent = 0;
\r
4027 case DELAYED_TIMER_ID:
\r
4028 KillTimer(hwnd, delayedTimerEvent);
\r
4029 delayedTimerEvent = 0;
\r
4030 delayedTimerCallback();
\r
4035 case WM_USER_Input:
\r
4036 InputEvent(hwnd, message, wParam, lParam);
\r
4039 case WM_ENTERSIZEMOVE:
\r
4040 if (hwnd == hwndMain) {
\r
4041 doingSizing = TRUE;
\r
4047 if (hwnd == hwndMain) {
\r
4048 lastSizing = wParam;
\r
4052 case WM_EXITSIZEMOVE:
\r
4053 if (hwnd == hwndMain) {
\r
4055 doingSizing = FALSE;
\r
4056 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4057 GetClientRect(hwnd, &client);
\r
4058 ResizeBoard(client.right, client.bottom, lastSizing);
\r
4063 case WM_DESTROY: /* message: window being destroyed */
\r
4064 PostQuitMessage(0);
\r
4068 if (hwnd == hwndMain) {
\r
4073 default: /* Passes it on if unprocessed */
\r
4074 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4079 /*---------------------------------------------------------------------------*\
\r
4081 * Misc utility routines
\r
4083 \*---------------------------------------------------------------------------*/
\r
4086 * Decent random number generator, at least not as bad as Windows
\r
4087 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
4089 unsigned int randstate;
\r
4094 randstate = randstate * 1664525 + 1013904223;
\r
4095 return (int) randstate & 0x7fffffff;
\r
4099 mysrandom(unsigned int seed)
\r
4106 * returns TRUE if user selects a different color, FALSE otherwise
\r
4110 ChangeColor(HWND hwnd, COLORREF *which)
\r
4112 static BOOL firstTime = TRUE;
\r
4113 static DWORD customColors[16];
\r
4115 COLORREF newcolor;
\r
4120 /* Make initial colors in use available as custom colors */
\r
4121 /* Should we put the compiled-in defaults here instead? */
\r
4123 customColors[i++] = lightSquareColor & 0xffffff;
\r
4124 customColors[i++] = darkSquareColor & 0xffffff;
\r
4125 customColors[i++] = whitePieceColor & 0xffffff;
\r
4126 customColors[i++] = blackPieceColor & 0xffffff;
\r
4127 customColors[i++] = highlightSquareColor & 0xffffff;
\r
4128 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
4130 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
4131 customColors[i++] = textAttribs[ccl].color;
\r
4133 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
4134 firstTime = FALSE;
\r
4137 cc.lStructSize = sizeof(cc);
\r
4138 cc.hwndOwner = hwnd;
\r
4139 cc.hInstance = NULL;
\r
4140 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
4141 cc.lpCustColors = (LPDWORD) customColors;
\r
4142 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
4144 if (!ChooseColor(&cc)) return FALSE;
\r
4146 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
4147 if (newcolor == *which) return FALSE;
\r
4148 *which = newcolor;
\r
4152 InitDrawingColors();
\r
4153 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4158 MyLoadSound(MySound *ms)
\r
4164 if (ms->data) free(ms->data);
\r
4167 switch (ms->name[0]) {
\r
4173 /* System sound from Control Panel. Don't preload here. */
\r
4177 if (ms->name[1] == NULLCHAR) {
\r
4178 /* "!" alone = silence */
\r
4181 /* Builtin wave resource. Error if not found. */
\r
4182 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
4183 if (h == NULL) break;
\r
4184 ms->data = (void *)LoadResource(hInst, h);
\r
4185 if (h == NULL) break;
\r
4190 /* .wav file. Error if not found. */
\r
4191 f = fopen(ms->name, "rb");
\r
4192 if (f == NULL) break;
\r
4193 if (fstat(fileno(f), &st) < 0) break;
\r
4194 ms->data = malloc(st.st_size);
\r
4195 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
4201 char buf[MSG_SIZ];
\r
4202 sprintf(buf, "Error loading sound %s", ms->name);
\r
4203 DisplayError(buf, GetLastError());
\r
4209 MyPlaySound(MySound *ms)
\r
4211 BOOLEAN ok = FALSE;
\r
4212 switch (ms->name[0]) {
\r
4218 /* System sound from Control Panel (deprecated feature).
\r
4219 "$" alone or an unset sound name gets default beep (still in use). */
\r
4220 if (ms->name[1]) {
\r
4221 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
4223 if (!ok) ok = MessageBeep(MB_OK);
\r
4226 /* Builtin wave resource, or "!" alone for silence */
\r
4227 if (ms->name[1]) {
\r
4228 if (ms->data == NULL) return FALSE;
\r
4229 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4235 /* .wav file. Error if not found. */
\r
4236 if (ms->data == NULL) return FALSE;
\r
4237 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4240 /* Don't print an error: this can happen innocently if the sound driver
\r
4241 is busy; for instance, if another instance of WinBoard is playing
\r
4242 a sound at about the same time. */
\r
4245 char buf[MSG_SIZ];
\r
4246 sprintf(buf, "Error playing sound %s", ms->name);
\r
4247 DisplayError(buf, GetLastError());
\r
4255 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4258 OPENFILENAME *ofn;
\r
4259 static UINT *number; /* gross that this is static */
\r
4261 switch (message) {
\r
4262 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4263 /* Center the dialog over the application window */
\r
4264 ofn = (OPENFILENAME *) lParam;
\r
4265 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
4266 number = (UINT *) ofn->lCustData;
\r
4267 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
4271 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4272 return FALSE; /* Allow for further processing */
\r
4275 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
4276 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
4278 return FALSE; /* Allow for further processing */
\r
4284 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
4286 static UINT *number;
\r
4287 OPENFILENAME *ofname;
\r
4290 case WM_INITDIALOG:
\r
4291 ofname = (OPENFILENAME *)lParam;
\r
4292 number = (UINT *)(ofname->lCustData);
\r
4295 ofnot = (OFNOTIFY *)lParam;
\r
4296 if (ofnot->hdr.code == CDN_FILEOK) {
\r
4297 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
4306 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
4307 char *nameFilt, char *dlgTitle, UINT *number,
\r
4308 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
4310 OPENFILENAME openFileName;
\r
4311 char buf1[MSG_SIZ];
\r
4314 if (fileName == NULL) fileName = buf1;
\r
4315 if (defName == NULL) {
\r
4316 strcpy(fileName, "*.");
\r
4317 strcat(fileName, defExt);
\r
4319 strcpy(fileName, defName);
\r
4321 if (fileTitle) strcpy(fileTitle, "");
\r
4322 if (number) *number = 0;
\r
4324 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
4325 openFileName.hwndOwner = hwnd;
\r
4326 openFileName.hInstance = (HANDLE) hInst;
\r
4327 openFileName.lpstrFilter = nameFilt;
\r
4328 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
4329 openFileName.nMaxCustFilter = 0L;
\r
4330 openFileName.nFilterIndex = 1L;
\r
4331 openFileName.lpstrFile = fileName;
\r
4332 openFileName.nMaxFile = MSG_SIZ;
\r
4333 openFileName.lpstrFileTitle = fileTitle;
\r
4334 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
4335 openFileName.lpstrInitialDir = NULL;
\r
4336 openFileName.lpstrTitle = dlgTitle;
\r
4337 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
4338 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
4339 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
4340 | (oldDialog ? 0 : OFN_EXPLORER);
\r
4341 openFileName.nFileOffset = 0;
\r
4342 openFileName.nFileExtension = 0;
\r
4343 openFileName.lpstrDefExt = defExt;
\r
4344 openFileName.lCustData = (LONG) number;
\r
4345 openFileName.lpfnHook = oldDialog ?
\r
4346 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
4347 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
4349 if (write ? GetSaveFileName(&openFileName) :
\r
4350 GetOpenFileName(&openFileName)) {
\r
4351 /* open the file */
\r
4352 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
4354 MessageBox(hwnd, "File open failed", NULL,
\r
4355 MB_OK|MB_ICONEXCLAMATION);
\r
4359 int err = CommDlgExtendedError();
\r
4360 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
4369 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
4371 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
4374 * Get the first pop-up menu in the menu template. This is the
\r
4375 * menu that TrackPopupMenu displays.
\r
4377 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
4379 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
4382 * TrackPopup uses screen coordinates, so convert the
\r
4383 * coordinates of the mouse click to screen coordinates.
\r
4385 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
4387 /* Draw and track the floating pop-up menu. */
\r
4388 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
4389 pt.x, pt.y, 0, hwnd, NULL);
\r
4391 /* Destroy the menu.*/
\r
4392 DestroyMenu(hmenu);
\r
4397 int sizeX, sizeY, newSizeX, newSizeY;
\r
4399 } ResizeEditPlusButtonsClosure;
\r
4402 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
4404 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
4408 if (hChild == cl->hText) return TRUE;
\r
4409 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
4410 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
4411 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
4412 ScreenToClient(cl->hDlg, &pt);
\r
4413 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
4414 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
4418 /* Resize a dialog that has a (rich) edit field filling most of
\r
4419 the top, with a row of buttons below */
\r
4421 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
4424 int newTextHeight, newTextWidth;
\r
4425 ResizeEditPlusButtonsClosure cl;
\r
4427 /*if (IsIconic(hDlg)) return;*/
\r
4428 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
4430 cl.hdwp = BeginDeferWindowPos(8);
\r
4432 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
4433 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
4434 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
4435 if (newTextHeight < 0) {
\r
4436 newSizeY += -newTextHeight;
\r
4437 newTextHeight = 0;
\r
4439 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
4440 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
4446 cl.newSizeX = newSizeX;
\r
4447 cl.newSizeY = newSizeY;
\r
4448 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
4450 EndDeferWindowPos(cl.hdwp);
\r
4453 /* Center one window over another */
\r
4454 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
4456 RECT rChild, rParent;
\r
4457 int wChild, hChild, wParent, hParent;
\r
4458 int wScreen, hScreen, xNew, yNew;
\r
4461 /* Get the Height and Width of the child window */
\r
4462 GetWindowRect (hwndChild, &rChild);
\r
4463 wChild = rChild.right - rChild.left;
\r
4464 hChild = rChild.bottom - rChild.top;
\r
4466 /* Get the Height and Width of the parent window */
\r
4467 GetWindowRect (hwndParent, &rParent);
\r
4468 wParent = rParent.right - rParent.left;
\r
4469 hParent = rParent.bottom - rParent.top;
\r
4471 /* Get the display limits */
\r
4472 hdc = GetDC (hwndChild);
\r
4473 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
4474 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
4475 ReleaseDC(hwndChild, hdc);
\r
4477 /* Calculate new X position, then adjust for screen */
\r
4478 xNew = rParent.left + ((wParent - wChild) /2);
\r
4481 } else if ((xNew+wChild) > wScreen) {
\r
4482 xNew = wScreen - wChild;
\r
4485 /* Calculate new Y position, then adjust for screen */
\r
4486 yNew = rParent.top + ((hParent - hChild) /2);
\r
4489 } else if ((yNew+hChild) > hScreen) {
\r
4490 yNew = hScreen - hChild;
\r
4493 /* Set it, and return */
\r
4494 return SetWindowPos (hwndChild, NULL,
\r
4495 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
4498 /*---------------------------------------------------------------------------*\
\r
4500 * Startup Dialog functions
\r
4502 \*---------------------------------------------------------------------------*/
\r
4504 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
4506 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
4508 while (*cd != NULL) {
\r
4509 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
4515 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
4517 char buf1[ARG_MAX];
\r
4520 if (str[0] == '@') {
\r
4521 FILE* f = fopen(str + 1, "r");
\r
4523 DisplayFatalError(str + 1, errno, 2);
\r
4526 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
4528 buf1[len] = NULLCHAR;
\r
4532 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
4535 char buf[MSG_SIZ];
\r
4536 char *end = strchr(str, '\n');
\r
4537 if (end == NULL) return;
\r
4538 memcpy(buf, str, end - str);
\r
4539 buf[end - str] = NULLCHAR;
\r
4540 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
4546 SetStartupDialogEnables(HWND hDlg)
\r
4548 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
4549 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
4550 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
4551 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
4552 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
4553 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
4554 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
4555 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
4556 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
4557 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
4558 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
4559 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
4560 IsDlgButtonChecked(hDlg, OPT_View));
\r
4564 QuoteForFilename(char *filename)
\r
4566 int dquote, space;
\r
4567 dquote = strchr(filename, '"') != NULL;
\r
4568 space = strchr(filename, ' ') != NULL;
\r
4569 if (dquote || space) {
\r
4581 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
4583 char buf[MSG_SIZ];
\r
4586 InitComboStringsFromOption(hwndCombo, nthnames);
\r
4587 q = QuoteForFilename(nthcp);
\r
4588 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
4589 if (*nthdir != NULLCHAR) {
\r
4590 q = QuoteForFilename(nthdir);
\r
4591 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
4593 if (*nthcp == NULLCHAR) {
\r
4594 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
4595 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
4596 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
4597 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
4602 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4604 char buf[MSG_SIZ];
\r
4608 switch (message) {
\r
4609 case WM_INITDIALOG:
\r
4610 /* Center the dialog */
\r
4611 CenterWindow (hDlg, GetDesktopWindow());
\r
4612 /* Initialize the dialog items */
\r
4613 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
4614 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
4615 firstChessProgramNames);
\r
4616 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
4617 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
4618 secondChessProgramNames);
\r
4619 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
4620 InitComboStringsFromOption(hwndCombo, icsNames);
\r
4621 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
4622 if (*appData.icsHelper != NULLCHAR) {
\r
4623 char *q = QuoteForFilename(appData.icsHelper);
\r
4624 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
4626 if (*appData.icsHost == NULLCHAR) {
\r
4627 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
4628 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
4629 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
4630 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
4631 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
4633 if (chessProgram) {
\r
4634 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
4635 } else if (appData.icsActive) {
\r
4636 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
4637 } else if (appData.noChessProgram) {
\r
4638 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
4640 SetStartupDialogEnables(hDlg);
\r
4644 switch (LOWORD(wParam)) {
\r
4646 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
4647 strcpy(buf, "/fcp=");
\r
4648 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4650 ParseArgs(StringGet, &p);
\r
4651 strcpy(buf, "/scp=");
\r
4652 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4654 ParseArgs(StringGet, &p);
\r
4655 appData.noChessProgram = FALSE;
\r
4656 appData.icsActive = FALSE;
\r
4657 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
4658 strcpy(buf, "/ics /icshost=");
\r
4659 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4661 ParseArgs(StringGet, &p);
\r
4662 if (appData.zippyPlay) {
\r
4663 strcpy(buf, "/fcp=");
\r
4664 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4666 ParseArgs(StringGet, &p);
\r
4668 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
4669 appData.noChessProgram = TRUE;
\r
4670 appData.icsActive = FALSE;
\r
4672 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
4673 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
4676 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
4677 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
4679 ParseArgs(StringGet, &p);
\r
4681 EndDialog(hDlg, TRUE);
\r
4688 case IDM_HELPCONTENTS:
\r
4689 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
4690 MessageBox (GetFocus(),
\r
4691 "Unable to activate help",
\r
4692 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4697 SetStartupDialogEnables(hDlg);
\r
4705 /*---------------------------------------------------------------------------*\
\r
4707 * About box dialog functions
\r
4709 \*---------------------------------------------------------------------------*/
\r
4711 /* Process messages for "About" dialog box */
\r
4713 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4715 switch (message) {
\r
4716 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4717 /* Center the dialog over the application window */
\r
4718 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4719 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
4722 case WM_COMMAND: /* message: received a command */
\r
4723 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
4724 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
4725 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4733 /*---------------------------------------------------------------------------*\
\r
4735 * Comment Dialog functions
\r
4737 \*---------------------------------------------------------------------------*/
\r
4740 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4742 static HANDLE hwndText = NULL;
\r
4743 int len, newSizeX, newSizeY, flags;
\r
4744 static int sizeX, sizeY;
\r
4749 switch (message) {
\r
4750 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4751 /* Initialize the dialog items */
\r
4752 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
4753 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
4754 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
4755 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
4756 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
4757 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
4758 SetWindowText(hDlg, commentTitle);
\r
4759 if (editComment) {
\r
4760 SetFocus(hwndText);
\r
4762 SetFocus(GetDlgItem(hDlg, IDOK));
\r
4764 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
4765 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
4766 MAKELPARAM(FALSE, 0));
\r
4767 /* Size and position the dialog */
\r
4768 if (!commentDialog) {
\r
4769 commentDialog = hDlg;
\r
4770 flags = SWP_NOZORDER;
\r
4771 GetClientRect(hDlg, &rect);
\r
4772 sizeX = rect.right;
\r
4773 sizeY = rect.bottom;
\r
4774 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
4775 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
4776 WINDOWPLACEMENT wp;
\r
4777 EnsureOnScreen(&commentX, &commentY);
\r
4778 wp.length = sizeof(WINDOWPLACEMENT);
\r
4780 wp.showCmd = SW_SHOW;
\r
4781 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
4782 wp.rcNormalPosition.left = commentX;
\r
4783 wp.rcNormalPosition.right = commentX + commentW;
\r
4784 wp.rcNormalPosition.top = commentY;
\r
4785 wp.rcNormalPosition.bottom = commentY + commentH;
\r
4786 SetWindowPlacement(hDlg, &wp);
\r
4788 GetClientRect(hDlg, &rect);
\r
4789 newSizeX = rect.right;
\r
4790 newSizeY = rect.bottom;
\r
4791 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
4792 newSizeX, newSizeY);
\r
4799 case WM_COMMAND: /* message: received a command */
\r
4800 switch (LOWORD(wParam)) {
\r
4802 if (editComment) {
\r
4804 /* Read changed options from the dialog box */
\r
4805 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
4806 len = GetWindowTextLength(hwndText);
\r
4807 str = (char *) malloc(len + 1);
\r
4808 GetWindowText(hwndText, str, len + 1);
\r
4817 ReplaceComment(commentIndex, str);
\r
4824 case OPT_CancelComment:
\r
4828 case OPT_ClearComment:
\r
4829 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
4832 case OPT_EditComment:
\r
4833 EditCommentEvent();
\r
4842 newSizeX = LOWORD(lParam);
\r
4843 newSizeY = HIWORD(lParam);
\r
4844 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
4849 case WM_GETMINMAXINFO:
\r
4850 /* Prevent resizing window too small */
\r
4851 mmi = (MINMAXINFO *) lParam;
\r
4852 mmi->ptMinTrackSize.x = 100;
\r
4853 mmi->ptMinTrackSize.y = 100;
\r
4860 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
4865 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
4867 if (str == NULL) str = "";
\r
4868 p = (char *) malloc(2 * strlen(str) + 2);
\r
4871 if (*str == '\n') *q++ = '\r';
\r
4875 if (commentText != NULL) free(commentText);
\r
4877 commentIndex = index;
\r
4878 commentTitle = title;
\r
4880 editComment = edit;
\r
4882 if (commentDialog) {
\r
4883 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
4884 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
4886 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
4887 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
4888 hwndMain, (DLGPROC)lpProc);
\r
4889 FreeProcInstance(lpProc);
\r
4891 commentDialogUp = TRUE;
\r
4895 /*---------------------------------------------------------------------------*\
\r
4897 * Type-in move dialog functions
\r
4899 \*---------------------------------------------------------------------------*/
\r
4902 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4904 char move[MSG_SIZ];
\r
4906 ChessMove moveType;
\r
4907 int fromX, fromY, toX, toY;
\r
4910 switch (message) {
\r
4911 case WM_INITDIALOG:
\r
4912 move[0] = (char) lParam;
\r
4913 move[1] = NULLCHAR;
\r
4914 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4915 hInput = GetDlgItem(hDlg, OPT_Move);
\r
4916 SetWindowText(hInput, move);
\r
4918 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
4922 switch (LOWORD(wParam)) {
\r
4924 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
4925 gameMode != Training) {
\r
4926 DisplayMoveError("Displayed move is not current");
\r
4928 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
4929 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
4930 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
4931 if (gameMode != Training)
\r
4932 forwardMostMove = currentMove;
\r
4933 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4935 DisplayMoveError("Could not parse move");
\r
4938 EndDialog(hDlg, TRUE);
\r
4941 EndDialog(hDlg, FALSE);
\r
4952 PopUpMoveDialog(char firstchar)
\r
4956 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
4957 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
4958 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
4959 gameMode == EditPosition || gameMode == IcsExamining ||
\r
4960 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
4961 gameMode == Training) {
\r
4962 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
4963 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
4964 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
4965 FreeProcInstance(lpProc);
\r
4969 /*---------------------------------------------------------------------------*\
\r
4973 \*---------------------------------------------------------------------------*/
\r
4975 /* Nonmodal error box */
\r
4976 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
4977 WPARAM wParam, LPARAM lParam);
\r
4980 ErrorPopUp(char *title, char *content)
\r
4984 BOOLEAN modal = hwndMain == NULL;
\r
5002 strncpy(errorTitle, title, sizeof(errorTitle));
\r
5003 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
5006 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
5008 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
5009 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
5010 hwndMain, (DLGPROC)lpProc);
\r
5011 FreeProcInstance(lpProc);
\r
5018 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
5019 if (errorDialog == NULL) return;
\r
5020 DestroyWindow(errorDialog);
\r
5021 errorDialog = NULL;
\r
5025 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5030 switch (message) {
\r
5031 case WM_INITDIALOG:
\r
5032 GetWindowRect(hDlg, &rChild);
\r
5033 SetWindowPos(hDlg, NULL, rChild.left,
\r
5034 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
5035 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
5036 errorDialog = hDlg;
\r
5037 SetWindowText(hDlg, errorTitle);
\r
5038 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
5039 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
5043 switch (LOWORD(wParam)) {
\r
5046 if (errorDialog == hDlg) errorDialog = NULL;
\r
5047 DestroyWindow(hDlg);
\r
5058 /*---------------------------------------------------------------------------*\
\r
5060 * Ics Interaction console functions
\r
5062 \*---------------------------------------------------------------------------*/
\r
5064 #define HISTORY_SIZE 64
\r
5065 static char *history[HISTORY_SIZE];
\r
5066 int histIn = 0, histP = 0;
\r
5069 SaveInHistory(char *cmd)
\r
5071 if (history[histIn] != NULL) {
\r
5072 free(history[histIn]);
\r
5073 history[histIn] = NULL;
\r
5075 if (*cmd == NULLCHAR) return;
\r
5076 history[histIn] = StrSave(cmd);
\r
5077 histIn = (histIn + 1) % HISTORY_SIZE;
\r
5078 if (history[histIn] != NULL) {
\r
5079 free(history[histIn]);
\r
5080 history[histIn] = NULL;
\r
5086 PrevInHistory(char *cmd)
\r
5089 if (histP == histIn) {
\r
5090 if (history[histIn] != NULL) free(history[histIn]);
\r
5091 history[histIn] = StrSave(cmd);
\r
5093 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
5094 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
5096 return history[histP];
\r
5102 if (histP == histIn) return NULL;
\r
5103 histP = (histP + 1) % HISTORY_SIZE;
\r
5104 return history[histP];
\r
5111 BOOLEAN immediate;
\r
5112 } IcsTextMenuEntry;
\r
5113 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
5114 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
5117 ParseIcsTextMenu(char *icsTextMenuString)
\r
5120 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
5121 char *p = icsTextMenuString;
\r
5122 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5125 if (e->command != NULL) {
\r
5127 e->command = NULL;
\r
5131 e = icsTextMenuEntry;
\r
5132 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5133 if (*p == ';' || *p == '\n') {
\r
5134 e->item = strdup("-");
\r
5135 e->command = NULL;
\r
5137 } else if (*p == '-') {
\r
5138 e->item = strdup("-");
\r
5139 e->command = NULL;
\r
5143 char *q, *r, *s, *t;
\r
5145 q = strchr(p, ',');
\r
5146 if (q == NULL) break;
\r
5148 r = strchr(q + 1, ',');
\r
5149 if (r == NULL) break;
\r
5151 s = strchr(r + 1, ',');
\r
5152 if (s == NULL) break;
\r
5155 t = strchr(s + 1, c);
\r
5158 t = strchr(s + 1, c);
\r
5160 if (t != NULL) *t = NULLCHAR;
\r
5161 e->item = strdup(p);
\r
5162 e->command = strdup(q + 1);
\r
5163 e->getname = *(r + 1) != '0';
\r
5164 e->immediate = *(s + 1) != '0';
\r
5168 if (t == NULL) break;
\r
5177 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
5181 hmenu = LoadMenu(hInst, "TextMenu");
\r
5182 h = GetSubMenu(hmenu, 0);
\r
5184 if (strcmp(e->item, "-") == 0) {
\r
5185 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
5187 if (e->item[0] == '|') {
\r
5188 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
5189 IDM_CommandX + i, &e->item[1]);
\r
5191 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
5200 WNDPROC consoleTextWindowProc;
\r
5203 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
5205 char buf[MSG_SIZ], name[MSG_SIZ];
\r
5206 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5210 SetWindowText(hInput, command);
\r
5212 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5214 sel.cpMin = 999999;
\r
5215 sel.cpMax = 999999;
\r
5216 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5221 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5222 if (sel.cpMin == sel.cpMax) {
\r
5223 /* Expand to surrounding word */
\r
5226 tr.chrg.cpMax = sel.cpMin;
\r
5227 tr.chrg.cpMin = --sel.cpMin;
\r
5228 if (sel.cpMin < 0) break;
\r
5229 tr.lpstrText = name;
\r
5230 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5231 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5235 tr.chrg.cpMin = sel.cpMax;
\r
5236 tr.chrg.cpMax = ++sel.cpMax;
\r
5237 tr.lpstrText = name;
\r
5238 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
5239 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5242 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5243 MessageBeep(MB_ICONEXCLAMATION);
\r
5247 tr.lpstrText = name;
\r
5248 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5250 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5251 MessageBeep(MB_ICONEXCLAMATION);
\r
5254 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
5257 sprintf(buf, "%s %s", command, name);
\r
5258 SetWindowText(hInput, buf);
\r
5259 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5261 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
5262 SetWindowText(hInput, buf);
\r
5263 sel.cpMin = 999999;
\r
5264 sel.cpMax = 999999;
\r
5265 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5271 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5276 switch (message) {
\r
5278 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5281 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
5284 sel.cpMin = 999999;
\r
5285 sel.cpMax = 999999;
\r
5286 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5287 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
5292 if (wParam == '\t') {
\r
5293 if (GetKeyState(VK_SHIFT) < 0) {
\r
5295 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5296 if (buttonDesc[0].hwnd) {
\r
5297 SetFocus(buttonDesc[0].hwnd);
\r
5299 SetFocus(hwndMain);
\r
5303 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
5306 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5308 SendMessage(hInput, message, wParam, lParam);
\r
5312 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5314 return SendMessage(hInput, message, wParam, lParam);
\r
5315 case WM_MBUTTONDOWN:
\r
5316 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5317 case WM_RBUTTONDOWN:
\r
5318 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
5319 /* Move selection here if it was empty */
\r
5321 pt.x = LOWORD(lParam);
\r
5322 pt.y = HIWORD(lParam);
\r
5323 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5324 if (sel.cpMin == sel.cpMax) {
\r
5325 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
5326 sel.cpMax = sel.cpMin;
\r
5327 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5329 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
5332 case WM_RBUTTONUP:
\r
5333 if (GetKeyState(VK_SHIFT) & ~1) {
\r
5334 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5335 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5338 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
5339 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5340 if (sel.cpMin == sel.cpMax) {
\r
5341 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
5342 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
5344 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
5345 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
5347 pt.x = LOWORD(lParam);
\r
5348 pt.y = HIWORD(lParam);
\r
5349 MenuPopup(hwnd, pt, hmenu, -1);
\r
5353 switch (LOWORD(wParam)) {
\r
5354 case IDM_QuickPaste:
\r
5356 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5357 if (sel.cpMin == sel.cpMax) {
\r
5358 MessageBeep(MB_ICONEXCLAMATION);
\r
5361 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5362 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5363 SendMessage(hInput, WM_PASTE, 0, 0);
\r
5368 SendMessage(hwnd, WM_CUT, 0, 0);
\r
5371 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
5374 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5378 int i = LOWORD(wParam) - IDM_CommandX;
\r
5379 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
5380 icsTextMenuEntry[i].command != NULL) {
\r
5381 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
5382 icsTextMenuEntry[i].getname,
\r
5383 icsTextMenuEntry[i].immediate);
\r
5391 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
5394 WNDPROC consoleInputWindowProc;
\r
5397 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5399 char buf[MSG_SIZ];
\r
5401 static BOOL sendNextChar = FALSE;
\r
5402 static BOOL quoteNextChar = FALSE;
\r
5403 InputSource *is = consoleInputSource;
\r
5407 switch (message) {
\r
5409 if (!appData.localLineEditing || sendNextChar) {
\r
5410 is->buf[0] = (CHAR) wParam;
\r
5412 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5413 sendNextChar = FALSE;
\r
5416 if (quoteNextChar) {
\r
5417 buf[0] = (char) wParam;
\r
5418 buf[1] = NULLCHAR;
\r
5419 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
5420 quoteNextChar = FALSE;
\r
5424 case '\r': /* Enter key */
\r
5425 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
5426 if (consoleEcho) SaveInHistory(is->buf);
\r
5427 is->buf[is->count++] = '\n';
\r
5428 is->buf[is->count] = NULLCHAR;
\r
5429 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5430 if (consoleEcho) {
\r
5431 ConsoleOutput(is->buf, is->count, TRUE);
\r
5432 } else if (appData.localLineEditing) {
\r
5433 ConsoleOutput("\n", 1, TRUE);
\r
5436 case '\033': /* Escape key */
\r
5437 SetWindowText(hwnd, "");
\r
5438 cf.cbSize = sizeof(CHARFORMAT);
\r
5439 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
5440 if (consoleEcho) {
\r
5441 cf.crTextColor = textAttribs[ColorNormal].color;
\r
5443 cf.crTextColor = COLOR_ECHOOFF;
\r
5445 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
5446 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
5448 case '\t': /* Tab key */
\r
5449 if (GetKeyState(VK_SHIFT) < 0) {
\r
5451 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
5454 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5455 if (buttonDesc[0].hwnd) {
\r
5456 SetFocus(buttonDesc[0].hwnd);
\r
5458 SetFocus(hwndMain);
\r
5462 case '\023': /* Ctrl+S */
\r
5463 sendNextChar = TRUE;
\r
5465 case '\021': /* Ctrl+Q */
\r
5466 quoteNextChar = TRUE;
\r
5475 GetWindowText(hwnd, buf, MSG_SIZ);
\r
5476 p = PrevInHistory(buf);
\r
5478 SetWindowText(hwnd, p);
\r
5479 sel.cpMin = 999999;
\r
5480 sel.cpMax = 999999;
\r
5481 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5486 p = NextInHistory();
\r
5488 SetWindowText(hwnd, p);
\r
5489 sel.cpMin = 999999;
\r
5490 sel.cpMax = 999999;
\r
5491 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5497 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5501 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
5505 case WM_MBUTTONDOWN:
\r
5506 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5507 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5509 case WM_RBUTTONUP:
\r
5510 if (GetKeyState(VK_SHIFT) & ~1) {
\r
5511 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5512 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5516 hmenu = LoadMenu(hInst, "InputMenu");
\r
5517 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5518 if (sel.cpMin == sel.cpMax) {
\r
5519 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
5520 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
5522 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
5523 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
5525 pt.x = LOWORD(lParam);
\r
5526 pt.y = HIWORD(lParam);
\r
5527 MenuPopup(hwnd, pt, hmenu, -1);
\r
5531 switch (LOWORD(wParam)) {
\r
5533 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
5535 case IDM_SelectAll:
\r
5537 sel.cpMax = -1; /*999999?*/
\r
5538 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5541 SendMessage(hwnd, WM_CUT, 0, 0);
\r
5544 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
5547 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5552 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
5555 #define CO_MAX 100000
\r
5556 #define CO_TRIM 1000
\r
5559 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5561 static HWND hText, hInput, hFocus;
\r
5562 InputSource *is = consoleInputSource;
\r
5564 static int sizeX, sizeY;
\r
5565 int newSizeX, newSizeY;
\r
5568 switch (message) {
\r
5569 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5570 hwndConsole = hDlg;
\r
5571 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
5572 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
5574 consoleTextWindowProc = (WNDPROC)
\r
5575 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
5576 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
5577 consoleInputWindowProc = (WNDPROC)
\r
5578 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
5579 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
5580 Colorize(ColorNormal, TRUE);
\r
5581 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
5582 ChangedConsoleFont();
\r
5583 GetClientRect(hDlg, &rect);
\r
5584 sizeX = rect.right;
\r
5585 sizeY = rect.bottom;
\r
5586 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
5587 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
5588 WINDOWPLACEMENT wp;
\r
5589 EnsureOnScreen(&consoleX, &consoleY);
\r
5590 wp.length = sizeof(WINDOWPLACEMENT);
\r
5592 wp.showCmd = SW_SHOW;
\r
5593 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
5594 wp.rcNormalPosition.left = consoleX;
\r
5595 wp.rcNormalPosition.right = consoleX + consoleW;
\r
5596 wp.rcNormalPosition.top = consoleY;
\r
5597 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
5598 SetWindowPlacement(hDlg, &wp);
\r
5612 if (IsIconic(hDlg)) break;
\r
5613 newSizeX = LOWORD(lParam);
\r
5614 newSizeY = HIWORD(lParam);
\r
5615 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
5616 RECT rectText, rectInput;
\r
5618 int newTextHeight, newTextWidth;
\r
5619 GetWindowRect(hText, &rectText);
\r
5620 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5621 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5622 if (newTextHeight < 0) {
\r
5623 newSizeY += -newTextHeight;
\r
5624 newTextHeight = 0;
\r
5626 SetWindowPos(hText, NULL, 0, 0,
\r
5627 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5628 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
5629 pt.x = rectInput.left;
\r
5630 pt.y = rectInput.top + newSizeY - sizeY;
\r
5631 ScreenToClient(hDlg, &pt);
\r
5632 SetWindowPos(hInput, NULL,
\r
5633 pt.x, pt.y, /* needs client coords */
\r
5634 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
5635 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
5641 case WM_GETMINMAXINFO:
\r
5642 /* Prevent resizing window too small */
\r
5643 mmi = (MINMAXINFO *) lParam;
\r
5644 mmi->ptMinTrackSize.x = 100;
\r
5645 mmi->ptMinTrackSize.y = 100;
\r
5648 return DefWindowProc(hDlg, message, wParam, lParam);
\r
5656 if (hwndConsole) return;
\r
5657 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
5658 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
5663 ConsoleOutput(char* data, int length, int forceVisible)
\r
5668 char buf[CO_MAX+1];
\r
5671 static int delayLF = 0;
\r
5672 CHARRANGE savesel, sel;
\r
5674 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
5682 while (length--) {
\r
5690 } else if (*p == '\007') {
\r
5691 MyPlaySound(&sounds[(int)SoundBell]);
\r
5698 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5699 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
5700 /* Save current selection */
\r
5701 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
5702 exlen = GetWindowTextLength(hText);
\r
5703 /* Find out whether current end of text is visible */
\r
5704 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
5705 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
5706 /* Trim existing text if it's too long */
\r
5707 if (exlen + (q - buf) > CO_MAX) {
\r
5708 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
5711 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5712 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
5714 savesel.cpMin -= trim;
\r
5715 savesel.cpMax -= trim;
\r
5716 if (exlen < 0) exlen = 0;
\r
5717 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
5718 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
5720 /* Append the new text */
\r
5721 sel.cpMin = exlen;
\r
5722 sel.cpMax = exlen;
\r
5723 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5724 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
5725 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
5726 if (forceVisible || exlen == 0 ||
\r
5727 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
5728 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
5729 /* Scroll to make new end of text visible if old end of text
\r
5730 was visible or new text is an echo of user typein */
\r
5731 sel.cpMin = 9999999;
\r
5732 sel.cpMax = 9999999;
\r
5733 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5734 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
5735 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
5736 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
5738 if (savesel.cpMax == exlen || forceVisible) {
\r
5739 /* Move insert point to new end of text if it was at the old
\r
5740 end of text or if the new text is an echo of user typein */
\r
5741 sel.cpMin = 9999999;
\r
5742 sel.cpMax = 9999999;
\r
5743 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5745 /* Restore previous selection */
\r
5746 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
5748 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
5755 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
5756 RECT *rect, char *color)
\r
5760 COLORREF oldFg, oldBg;
\r
5763 if (appData.clockMode) {
\r
5765 sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));
\r
5767 sprintf(buf, "%s: %s", color, TimeString(timeRemaining));
\r
5774 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
5775 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
5777 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
5778 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
5780 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
5782 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
5783 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
5784 rect, str, strlen(str), NULL);
\r
5786 (void) SetTextColor(hdc, oldFg);
\r
5787 (void) SetBkColor(hdc, oldBg);
\r
5788 (void) SelectObject(hdc, oldFont);
\r
5793 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
5798 ResetEvent(ovl->hEvent);
\r
5799 ovl->Offset = ovl->OffsetHigh = 0;
\r
5800 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
5804 err = GetLastError();
\r
5805 if (err == ERROR_IO_PENDING) {
\r
5806 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
5810 err = GetLastError();
\r
5817 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
5822 ResetEvent(ovl->hEvent);
\r
5823 ovl->Offset = ovl->OffsetHigh = 0;
\r
5824 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
5828 err = GetLastError();
\r
5829 if (err == ERROR_IO_PENDING) {
\r
5830 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
5834 err = GetLastError();
\r
5842 InputThread(LPVOID arg)
\r
5847 is = (InputSource *) arg;
\r
5848 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
5849 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
5850 while (is->hThread != NULL) {
\r
5851 is->error = DoReadFile(is->hFile, is->next,
\r
5852 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
5853 &is->count, &ovl);
\r
5854 if (is->error == NO_ERROR) {
\r
5855 is->next += is->count;
\r
5857 if (is->error == ERROR_BROKEN_PIPE) {
\r
5858 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
5861 is->count = (DWORD) -1;
\r
5864 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5865 if (is->count <= 0) break; /* Quit on EOF or error */
\r
5867 CloseHandle(ovl.hEvent);
\r
5868 CloseHandle(is->hFile);
\r
5873 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
5875 NonOvlInputThread(LPVOID arg)
\r
5882 is = (InputSource *) arg;
\r
5883 while (is->hThread != NULL) {
\r
5884 is->error = ReadFile(is->hFile, is->next,
\r
5885 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
5886 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
5887 if (is->error == NO_ERROR) {
\r
5888 /* Change CRLF to LF */
\r
5889 if (is->next > is->buf) {
\r
5891 i = is->count + 1;
\r
5899 if (prev == '\r' && *p == '\n') {
\r
5911 if (is->error == ERROR_BROKEN_PIPE) {
\r
5912 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
5915 is->count = (DWORD) -1;
\r
5918 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5919 if (is->count < 0) break; /* Quit on error */
\r
5921 CloseHandle(is->hFile);
\r
5926 SocketInputThread(LPVOID arg)
\r
5930 is = (InputSource *) arg;
\r
5931 while (is->hThread != NULL) {
\r
5932 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
5933 if ((int)is->count == SOCKET_ERROR) {
\r
5934 is->count = (DWORD) -1;
\r
5935 is->error = WSAGetLastError();
\r
5937 is->error = NO_ERROR;
\r
5938 is->next += is->count;
\r
5939 if (is->count == 0 && is->second == is) {
\r
5940 /* End of file on stderr; quit with no message */
\r
5944 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5945 if (is->count <= 0) break; /* Quit on EOF or error */
\r
5951 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5955 is = (InputSource *) lParam;
\r
5956 if (is->lineByLine) {
\r
5957 /* Feed in lines one by one */
\r
5958 char *p = is->buf;
\r
5960 while (q < is->next) {
\r
5961 if (*q++ == '\n') {
\r
5962 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
5966 /* Move any partial line to the start of the buffer */
\r
5968 while (p < is->next) {
\r
5972 if (is->error != NO_ERROR || is->count == 0) {
\r
5973 /* Notify backend of the error. Note: If there was a partial
\r
5974 line at the end, it is not flushed through. */
\r
5975 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
5978 /* Feed in the whole chunk of input at once */
\r
5979 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
5980 is->next = is->buf;
\r
5984 /*---------------------------------------------------------------------------*\
\r
5986 * Menu enables. Used when setting various modes.
\r
5988 \*---------------------------------------------------------------------------*/
\r
5996 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
5998 while (enab->item > 0) {
\r
5999 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
6004 Enables gnuEnables[] = {
\r
6005 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6006 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6007 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
6008 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
6009 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
6010 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
6011 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6012 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
6013 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
6014 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
6018 Enables icsEnables[] = {
\r
6019 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6020 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6021 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6022 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6023 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6024 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
6025 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
6026 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
6027 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6028 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
6029 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
6030 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
6035 Enables zippyEnables[] = {
\r
6036 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6037 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
6038 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
6043 Enables ncpEnables[] = {
\r
6044 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6045 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6046 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6047 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6048 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6049 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
6050 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
6051 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
6052 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
6053 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
6054 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6055 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6056 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
6057 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
6058 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
6062 Enables trainingOnEnables[] = {
\r
6063 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
6064 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
6065 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
6066 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
6067 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
6068 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
6069 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6070 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
6074 Enables trainingOffEnables[] = {
\r
6075 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
6076 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
6077 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
6078 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
6079 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
6080 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
6081 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6082 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
6086 /* These modify either ncpEnables or gnuEnables */
\r
6087 Enables cmailEnables[] = {
\r
6088 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
6089 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
6090 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
6091 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
6092 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
6093 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6094 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
6098 Enables machineThinkingEnables[] = {
\r
6099 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6100 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
6101 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
6102 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6103 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
6104 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6105 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6106 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6107 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6108 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
6109 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6110 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6111 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6112 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
6113 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6117 Enables userThinkingEnables[] = {
\r
6118 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6119 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
6120 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
6121 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6122 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
6123 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6124 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6125 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6126 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6127 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
6128 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
6129 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
6130 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
6131 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
6132 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
6136 /*---------------------------------------------------------------------------*\
\r
6138 * Front-end interface functions exported by XBoard.
\r
6139 * Functions appear in same order as prototypes in frontend.h.
\r
6141 \*---------------------------------------------------------------------------*/
\r
6145 static UINT prevChecked = 0;
\r
6146 static int prevPausing = 0;
\r
6149 if (pausing != prevPausing) {
\r
6150 prevPausing = pausing;
\r
6151 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
6152 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
6153 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
6156 switch (gameMode) {
\r
6157 case BeginningOfGame:
\r
6158 if (appData.icsActive)
\r
6159 nowChecked = IDM_IcsClient;
\r
6160 else if (appData.noChessProgram)
\r
6161 nowChecked = IDM_EditGame;
\r
6163 nowChecked = IDM_MachineBlack;
\r
6165 case MachinePlaysBlack:
\r
6166 nowChecked = IDM_MachineBlack;
\r
6168 case MachinePlaysWhite:
\r
6169 nowChecked = IDM_MachineWhite;
\r
6171 case TwoMachinesPlay:
\r
6172 nowChecked = IDM_TwoMachines;
\r
6175 nowChecked = IDM_AnalysisMode;
\r
6178 nowChecked = IDM_AnalyzeFile;
\r
6181 nowChecked = IDM_EditGame;
\r
6183 case PlayFromGameFile:
\r
6184 nowChecked = IDM_LoadGame;
\r
6186 case EditPosition:
\r
6187 nowChecked = IDM_EditPosition;
\r
6190 nowChecked = IDM_Training;
\r
6192 case IcsPlayingWhite:
\r
6193 case IcsPlayingBlack:
\r
6194 case IcsObserving:
\r
6196 nowChecked = IDM_IcsClient;
\r
6203 if (prevChecked != 0)
\r
6204 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6205 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
6206 if (nowChecked != 0)
\r
6207 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6208 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
6210 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
6211 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
6212 MF_BYCOMMAND|MF_ENABLED);
\r
6214 (void) EnableMenuItem(GetMenu(hwndMain),
\r
6215 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
6218 prevChecked = nowChecked;
\r
6224 HMENU hmenu = GetMenu(hwndMain);
\r
6225 SetMenuEnables(hmenu, icsEnables);
\r
6226 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
6227 MF_BYPOSITION|MF_ENABLED);
\r
6229 if (appData.zippyPlay) {
\r
6230 SetMenuEnables(hmenu, zippyEnables);
\r
6238 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
6244 HMENU hmenu = GetMenu(hwndMain);
\r
6245 SetMenuEnables(hmenu, ncpEnables);
\r
6246 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
6247 MF_BYPOSITION|MF_GRAYED);
\r
6248 DrawMenuBar(hwndMain);
\r
6254 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
6258 SetTrainingModeOn()
\r
6261 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
6262 for (i = 0; i < N_BUTTONS; i++) {
\r
6263 if (buttonDesc[i].hwnd != NULL)
\r
6264 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
6269 VOID SetTrainingModeOff()
\r
6272 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
6273 for (i = 0; i < N_BUTTONS; i++) {
\r
6274 if (buttonDesc[i].hwnd != NULL)
\r
6275 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
6281 SetUserThinkingEnables()
\r
6283 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
6287 SetMachineThinkingEnables()
\r
6289 HMENU hMenu = GetMenu(hwndMain);
\r
6290 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
6292 SetMenuEnables(hMenu, machineThinkingEnables);
\r
6294 if (gameMode == MachinePlaysBlack) {
\r
6295 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
6296 } else if (gameMode == MachinePlaysWhite) {
\r
6297 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
6298 } else if (gameMode == TwoMachinesPlay) {
\r
6299 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
6305 DisplayTitle(char *str)
\r
6307 char title[MSG_SIZ], *host;
\r
6308 if (str[0] != NULLCHAR) {
\r
6309 strcpy(title, str);
\r
6310 } else if (appData.icsActive) {
\r
6311 if (appData.icsCommPort[0] != NULLCHAR)
\r
6314 host = appData.icsHost;
\r
6315 sprintf(title, "%s: %s", szTitle, host);
\r
6316 } else if (appData.noChessProgram) {
\r
6317 strcpy(title, szTitle);
\r
6319 strcpy(title, szTitle);
\r
6320 strcat(title, ": ");
\r
6321 strcat(title, first.tidy);
\r
6323 SetWindowText(hwndMain, title);
\r
6328 DisplayMessage(char *str1, char *str2)
\r
6332 int remain = MESSAGE_TEXT_MAX - 1;
\r
6335 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
6336 messageText[0] = NULLCHAR;
\r
6338 len = strlen(str1);
\r
6339 if (len > remain) len = remain;
\r
6340 strncpy(messageText, str1, len);
\r
6341 messageText[len] = NULLCHAR;
\r
6344 if (*str2 && remain >= 2) {
\r
6346 strcat(messageText, " ");
\r
6349 len = strlen(str2);
\r
6350 if (len > remain) len = remain;
\r
6351 strncat(messageText, str2, len);
\r
6353 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
6355 if (IsIconic(hwndMain)) return;
\r
6356 hdc = GetDC(hwndMain);
\r
6357 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
6358 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
6359 &messageRect, messageText, strlen(messageText), NULL);
\r
6360 (void) SelectObject(hdc, oldFont);
\r
6361 (void) ReleaseDC(hwndMain, hdc);
\r
6365 DisplayError(char *str, int error)
\r
6367 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
6373 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
6374 NULL, error, LANG_NEUTRAL,
\r
6375 (LPSTR) buf2, MSG_SIZ, NULL);
\r
6377 sprintf(buf, "%s:\n%s", str, buf2);
\r
6379 ErrorMap *em = errmap;
\r
6380 while (em->err != 0 && em->err != error) em++;
\r
6381 if (em->err != 0) {
\r
6382 sprintf(buf, "%s:\n%s", str, em->msg);
\r
6384 sprintf(buf, "%s:\nError code %d", str, error);
\r
6389 ErrorPopUp("Error", buf);
\r
6394 DisplayMoveError(char *str)
\r
6396 fromX = fromY = -1;
\r
6397 ClearHighlights();
\r
6398 DrawPosition(FALSE, NULL);
\r
6399 if (appData.popupMoveErrors) {
\r
6400 ErrorPopUp("Error", str);
\r
6402 DisplayMessage(str, "");
\r
6403 moveErrorMessageUp = TRUE;
\r
6408 DisplayFatalError(char *str, int error, int exitStatus)
\r
6410 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
6412 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
6415 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
6416 NULL, error, LANG_NEUTRAL,
\r
6417 (LPSTR) buf2, MSG_SIZ, NULL);
\r
6419 sprintf(buf, "%s:\n%s", str, buf2);
\r
6421 ErrorMap *em = errmap;
\r
6422 while (em->err != 0 && em->err != error) em++;
\r
6423 if (em->err != 0) {
\r
6424 sprintf(buf, "%s:\n%s", str, em->msg);
\r
6426 sprintf(buf, "%s:\nError code %d", str, error);
\r
6431 if (appData.debugMode) {
\r
6432 fprintf(debugFP, "%s: %s\n", label, str);
\r
6434 if (appData.popupExitMessage) {
\r
6435 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
6436 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
6438 ExitEvent(exitStatus);
\r
6443 DisplayInformation(char *str)
\r
6445 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
6450 DisplayNote(char *str)
\r
6452 ErrorPopUp("Note", str);
\r
6457 char *title, *question, *replyPrefix;
\r
6462 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6464 static QuestionParams *qp;
\r
6465 char reply[MSG_SIZ];
\r
6468 switch (message) {
\r
6469 case WM_INITDIALOG:
\r
6470 qp = (QuestionParams *) lParam;
\r
6471 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
6472 SetWindowText(hDlg, qp->title);
\r
6473 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
6474 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
6478 switch (LOWORD(wParam)) {
\r
6480 strcpy(reply, qp->replyPrefix);
\r
6481 if (*reply) strcat(reply, " ");
\r
6482 len = strlen(reply);
\r
6483 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
6484 strcat(reply, "\n");
\r
6485 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
6486 EndDialog(hDlg, TRUE);
\r
6487 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
6490 EndDialog(hDlg, FALSE);
\r
6501 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
6503 QuestionParams qp;
\r
6507 qp.question = question;
\r
6508 qp.replyPrefix = replyPrefix;
\r
6510 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
6511 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
6512 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
6513 FreeProcInstance(lpProc);
\r
6518 DisplayIcsInteractionTitle(char *str)
\r
6520 char consoleTitle[MSG_SIZ];
\r
6522 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
6523 SetWindowText(hwndConsole, consoleTitle);
\r
6527 DrawPosition(int fullRedraw, Board board)
\r
6529 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
6536 fromX = fromY = -1;
\r
6537 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
6538 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
6539 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
6540 dragInfo.lastpos = dragInfo.pos;
\r
6541 dragInfo.start.x = dragInfo.start.y = -1;
\r
6542 dragInfo.from = dragInfo.start;
\r
6544 DrawPosition(TRUE, NULL);
\r
6550 CommentPopUp(char *title, char *str)
\r
6552 HWND hwnd = GetActiveWindow();
\r
6553 EitherCommentPopUp(0, title, str, FALSE);
\r
6554 SetActiveWindow(hwnd);
\r
6558 CommentPopDown(void)
\r
6560 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
6561 if (commentDialog) {
\r
6562 ShowWindow(commentDialog, SW_HIDE);
\r
6564 commentDialogUp = FALSE;
\r
6568 EditCommentPopUp(int index, char *title, char *str)
\r
6570 EitherCommentPopUp(index, title, str, TRUE);
\r
6577 MyPlaySound(&sounds[(int)SoundMove]);
\r
6580 VOID PlayIcsWinSound()
\r
6582 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
6585 VOID PlayIcsLossSound()
\r
6587 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
6590 VOID PlayIcsDrawSound()
\r
6592 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
6595 VOID PlayIcsUnfinishedSound()
\r
6597 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
6603 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
6611 consoleEcho = TRUE;
\r
6612 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6613 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
6614 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6623 consoleEcho = FALSE;
\r
6624 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6625 /* This works OK: set text and background both to the same color */
\r
6627 cf.crTextColor = COLOR_ECHOOFF;
\r
6628 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6629 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
6632 /* No Raw()...? */
\r
6634 void Colorize(ColorClass cc, int continuation)
\r
6636 currentColorClass = cc;
\r
6637 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6638 consoleCF.crTextColor = textAttribs[cc].color;
\r
6639 consoleCF.dwEffects = textAttribs[cc].effects;
\r
6640 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
6646 static char buf[MSG_SIZ];
\r
6647 DWORD bufsiz = MSG_SIZ;
\r
6649 if (!GetUserName(buf, &bufsiz)) {
\r
6650 /*DisplayError("Error getting user name", GetLastError());*/
\r
6651 strcpy(buf, "User");
\r
6659 static char buf[MSG_SIZ];
\r
6660 DWORD bufsiz = MSG_SIZ;
\r
6662 if (!GetComputerName(buf, &bufsiz)) {
\r
6663 /*DisplayError("Error getting host name", GetLastError());*/
\r
6664 strcpy(buf, "Unknown");
\r
6671 ClockTimerRunning()
\r
6673 return clockTimerEvent != 0;
\r
6679 if (clockTimerEvent == 0) return FALSE;
\r
6680 KillTimer(hwndMain, clockTimerEvent);
\r
6681 clockTimerEvent = 0;
\r
6686 StartClockTimer(long millisec)
\r
6688 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
6689 (UINT) millisec, NULL);
\r
6693 DisplayWhiteClock(long timeRemaining, int highlight)
\r
6696 hdc = GetDC(hwndMain);
\r
6697 if (!IsIconic(hwndMain)) {
\r
6698 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");
\r
6700 if (highlight && iconCurrent == iconBlack) {
\r
6701 iconCurrent = iconWhite;
\r
6702 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6703 if (IsIconic(hwndMain)) {
\r
6704 DrawIcon(hdc, 2, 2, iconCurrent);
\r
6707 (void) ReleaseDC(hwndMain, hdc);
\r
6709 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6713 DisplayBlackClock(long timeRemaining, int highlight)
\r
6716 hdc = GetDC(hwndMain);
\r
6717 if (!IsIconic(hwndMain)) {
\r
6718 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");
\r
6720 if (highlight && iconCurrent == iconWhite) {
\r
6721 iconCurrent = iconBlack;
\r
6722 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6723 if (IsIconic(hwndMain)) {
\r
6724 DrawIcon(hdc, 2, 2, iconCurrent);
\r
6727 (void) ReleaseDC(hwndMain, hdc);
\r
6729 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6734 LoadGameTimerRunning()
\r
6736 return loadGameTimerEvent != 0;
\r
6740 StopLoadGameTimer()
\r
6742 if (loadGameTimerEvent == 0) return FALSE;
\r
6743 KillTimer(hwndMain, loadGameTimerEvent);
\r
6744 loadGameTimerEvent = 0;
\r
6749 StartLoadGameTimer(long millisec)
\r
6751 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
6752 (UINT) millisec, NULL);
\r
6760 char fileTitle[MSG_SIZ];
\r
6762 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
6763 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
6764 appData.oldSaveStyle ? "gam" : "pgn",
\r
6766 "Save Game to File", NULL, fileTitle, NULL);
\r
6768 SaveGame(f, 0, "");
\r
6775 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
6777 if (delayedTimerEvent != 0) {
\r
6778 if (appData.debugMode) {
\r
6779 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
6781 KillTimer(hwndMain, delayedTimerEvent);
\r
6782 delayedTimerEvent = 0;
\r
6783 delayedTimerCallback();
\r
6785 delayedTimerCallback = cb;
\r
6786 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
6787 (UINT) millisec, NULL);
\r
6790 DelayedEventCallback
\r
6793 if (delayedTimerEvent) {
\r
6794 return delayedTimerCallback;
\r
6801 CancelDelayedEvent()
\r
6803 if (delayedTimerEvent) {
\r
6804 KillTimer(hwndMain, delayedTimerEvent);
\r
6805 delayedTimerEvent = 0;
\r
6809 /* Start a child process running the given program.
\r
6810 The process's standard output can be read from "from", and its
\r
6811 standard input can be written to "to".
\r
6812 Exit with fatal error if anything goes wrong.
\r
6813 Returns an opaque pointer that can be used to destroy the process
\r
6817 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
6819 #define BUFSIZE 4096
\r
6821 HANDLE hChildStdinRd, hChildStdinWr,
\r
6822 hChildStdoutRd, hChildStdoutWr;
\r
6823 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
6824 SECURITY_ATTRIBUTES saAttr;
\r
6826 PROCESS_INFORMATION piProcInfo;
\r
6827 STARTUPINFO siStartInfo;
\r
6829 char buf[MSG_SIZ];
\r
6832 if (appData.debugMode) {
\r
6833 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
6838 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
6839 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
6840 saAttr.bInheritHandle = TRUE;
\r
6841 saAttr.lpSecurityDescriptor = NULL;
\r
6844 * The steps for redirecting child's STDOUT:
\r
6845 * 1. Create anonymous pipe to be STDOUT for child.
\r
6846 * 2. Create a noninheritable duplicate of read handle,
\r
6847 * and close the inheritable read handle.
\r
6850 /* Create a pipe for the child's STDOUT. */
\r
6851 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
6852 return GetLastError();
\r
6855 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
6856 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
6857 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
6858 FALSE, /* not inherited */
\r
6859 DUPLICATE_SAME_ACCESS);
\r
6861 return GetLastError();
\r
6863 CloseHandle(hChildStdoutRd);
\r
6866 * The steps for redirecting child's STDIN:
\r
6867 * 1. Create anonymous pipe to be STDIN for child.
\r
6868 * 2. Create a noninheritable duplicate of write handle,
\r
6869 * and close the inheritable write handle.
\r
6872 /* Create a pipe for the child's STDIN. */
\r
6873 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
6874 return GetLastError();
\r
6877 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
6878 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
6879 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
6880 FALSE, /* not inherited */
\r
6881 DUPLICATE_SAME_ACCESS);
\r
6883 return GetLastError();
\r
6885 CloseHandle(hChildStdinWr);
\r
6887 /* Arrange to (1) look in dir for the child .exe file, and
\r
6888 * (2) have dir be the child's working directory. Interpret
\r
6889 * dir relative to the directory WinBoard loaded from. */
\r
6890 GetCurrentDirectory(MSG_SIZ, buf);
\r
6891 SetCurrentDirectory(installDir);
\r
6892 SetCurrentDirectory(dir);
\r
6894 /* Now create the child process. */
\r
6896 siStartInfo.cb = sizeof(STARTUPINFO);
\r
6897 siStartInfo.lpReserved = NULL;
\r
6898 siStartInfo.lpDesktop = NULL;
\r
6899 siStartInfo.lpTitle = NULL;
\r
6900 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
6901 siStartInfo.cbReserved2 = 0;
\r
6902 siStartInfo.lpReserved2 = NULL;
\r
6903 siStartInfo.hStdInput = hChildStdinRd;
\r
6904 siStartInfo.hStdOutput = hChildStdoutWr;
\r
6905 siStartInfo.hStdError = hChildStdoutWr;
\r
6907 fSuccess = CreateProcess(NULL,
\r
6908 cmdLine, /* command line */
\r
6909 NULL, /* process security attributes */
\r
6910 NULL, /* primary thread security attrs */
\r
6911 TRUE, /* handles are inherited */
\r
6912 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
6913 NULL, /* use parent's environment */
\r
6915 &siStartInfo, /* STARTUPINFO pointer */
\r
6916 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
6918 err = GetLastError();
\r
6919 SetCurrentDirectory(buf); /* return to prev directory */
\r
6924 /* Close the handles we don't need in the parent */
\r
6925 CloseHandle(piProcInfo.hThread);
\r
6926 CloseHandle(hChildStdinRd);
\r
6927 CloseHandle(hChildStdoutWr);
\r
6929 /* Prepare return value */
\r
6930 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
6931 cp->kind = CPReal;
\r
6932 cp->hProcess = piProcInfo.hProcess;
\r
6933 cp->pid = piProcInfo.dwProcessId;
\r
6934 cp->hFrom = hChildStdoutRdDup;
\r
6935 cp->hTo = hChildStdinWrDup;
\r
6937 *pr = (void *) cp;
\r
6939 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
6940 2000 where engines sometimes don't see the initial command(s)
\r
6941 from WinBoard and hang. I don't understand how that can happen,
\r
6942 but the Sleep is harmless, so I've put it in. Others have also
\r
6943 reported what may be the same problem, so hopefully this will fix
\r
6944 it for them too. */
\r
6952 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
6956 cp = (ChildProc *) pr;
\r
6957 if (cp == NULL) return;
\r
6959 switch (cp->kind) {
\r
6961 /* TerminateProcess is considered harmful, so... */
\r
6962 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
6963 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
6964 /* The following doesn't work because the chess program
\r
6965 doesn't "have the same console" as WinBoard. Maybe
\r
6966 we could arrange for this even though neither WinBoard
\r
6967 nor the chess program uses a console for stdio? */
\r
6968 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
6969 CloseHandle(cp->hProcess);
\r
6973 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
6977 closesocket(cp->sock);
\r
6982 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
6983 closesocket(cp->sock);
\r
6984 closesocket(cp->sock2);
\r
6992 InterruptChildProcess(ProcRef pr)
\r
6996 cp = (ChildProc *) pr;
\r
6997 if (cp == NULL) return;
\r
6998 switch (cp->kind) {
\r
7000 /* The following doesn't work because the chess program
\r
7001 doesn't "have the same console" as WinBoard. Maybe
\r
7002 we could arrange for this even though neither WinBoard
\r
7003 nor the chess program uses a console for stdio */
\r
7004 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
7009 /* Can't interrupt */
\r
7013 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
7020 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
7022 char cmdLine[MSG_SIZ];
\r
7024 if (port[0] == NULLCHAR) {
\r
7025 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
7027 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
7029 return StartChildProcess(cmdLine, "", pr);
\r
7033 /* Code to open TCP sockets */
\r
7036 OpenTCP(char *host, char *port, ProcRef *pr)
\r
7041 struct sockaddr_in sa, mysa;
\r
7042 struct hostent FAR *hp;
\r
7043 unsigned short uport;
\r
7044 WORD wVersionRequested;
\r
7047 /* Initialize socket DLL */
\r
7048 wVersionRequested = MAKEWORD(1, 1);
\r
7049 err = WSAStartup(wVersionRequested, &wsaData);
\r
7050 if (err != 0) return err;
\r
7053 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7054 err = WSAGetLastError();
\r
7059 /* Bind local address using (mostly) don't-care values.
\r
7061 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7062 mysa.sin_family = AF_INET;
\r
7063 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7064 uport = (unsigned short) 0;
\r
7065 mysa.sin_port = htons(uport);
\r
7066 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7067 == SOCKET_ERROR) {
\r
7068 err = WSAGetLastError();
\r
7073 /* Resolve remote host name */
\r
7074 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7075 if (!(hp = gethostbyname(host))) {
\r
7076 unsigned int b0, b1, b2, b3;
\r
7078 err = WSAGetLastError();
\r
7080 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7081 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7082 hp->h_addrtype = AF_INET;
\r
7084 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7085 hp->h_addr_list[0] = (char *) malloc(4);
\r
7086 hp->h_addr_list[0][0] = (char) b0;
\r
7087 hp->h_addr_list[0][1] = (char) b1;
\r
7088 hp->h_addr_list[0][2] = (char) b2;
\r
7089 hp->h_addr_list[0][3] = (char) b3;
\r
7095 sa.sin_family = hp->h_addrtype;
\r
7096 uport = (unsigned short) atoi(port);
\r
7097 sa.sin_port = htons(uport);
\r
7098 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7100 /* Make connection */
\r
7101 if (connect(s, (struct sockaddr *) &sa,
\r
7102 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7103 err = WSAGetLastError();
\r
7108 /* Prepare return value */
\r
7109 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7110 cp->kind = CPSock;
\r
7112 *pr = (ProcRef *) cp;
\r
7118 OpenCommPort(char *name, ProcRef *pr)
\r
7123 char fullname[MSG_SIZ];
\r
7125 if (*name != '\\')
\r
7126 sprintf(fullname, "\\\\.\\%s", name);
\r
7128 strcpy(fullname, name);
\r
7130 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
7131 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
7132 if (h == (HANDLE) -1) {
\r
7133 return GetLastError();
\r
7137 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
7139 /* Accumulate characters until a 100ms pause, then parse */
\r
7140 ct.ReadIntervalTimeout = 100;
\r
7141 ct.ReadTotalTimeoutMultiplier = 0;
\r
7142 ct.ReadTotalTimeoutConstant = 0;
\r
7143 ct.WriteTotalTimeoutMultiplier = 0;
\r
7144 ct.WriteTotalTimeoutConstant = 0;
\r
7145 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
7147 /* Prepare return value */
\r
7148 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7149 cp->kind = CPComm;
\r
7152 *pr = (ProcRef *) cp;
\r
7158 OpenLoopback(ProcRef *pr)
\r
7160 DisplayFatalError("Not implemented", 0, 1);
\r
7166 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
7171 struct sockaddr_in sa, mysa;
\r
7172 struct hostent FAR *hp;
\r
7173 unsigned short uport;
\r
7174 WORD wVersionRequested;
\r
7177 char stderrPortStr[MSG_SIZ];
\r
7179 /* Initialize socket DLL */
\r
7180 wVersionRequested = MAKEWORD(1, 1);
\r
7181 err = WSAStartup(wVersionRequested, &wsaData);
\r
7182 if (err != 0) return err;
\r
7184 /* Resolve remote host name */
\r
7185 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7186 if (!(hp = gethostbyname(host))) {
\r
7187 unsigned int b0, b1, b2, b3;
\r
7189 err = WSAGetLastError();
\r
7191 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7192 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7193 hp->h_addrtype = AF_INET;
\r
7195 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7196 hp->h_addr_list[0] = (char *) malloc(4);
\r
7197 hp->h_addr_list[0][0] = (char) b0;
\r
7198 hp->h_addr_list[0][1] = (char) b1;
\r
7199 hp->h_addr_list[0][2] = (char) b2;
\r
7200 hp->h_addr_list[0][3] = (char) b3;
\r
7206 sa.sin_family = hp->h_addrtype;
\r
7207 uport = (unsigned short) 514;
\r
7208 sa.sin_port = htons(uport);
\r
7209 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7211 /* Bind local socket to unused "privileged" port address
\r
7213 s = INVALID_SOCKET;
\r
7214 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7215 mysa.sin_family = AF_INET;
\r
7216 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7217 for (fromPort = 1023;; fromPort--) {
\r
7218 if (fromPort < 0) {
\r
7220 return WSAEADDRINUSE;
\r
7222 if (s == INVALID_SOCKET) {
\r
7223 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7224 err = WSAGetLastError();
\r
7229 uport = (unsigned short) fromPort;
\r
7230 mysa.sin_port = htons(uport);
\r
7231 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7232 == SOCKET_ERROR) {
\r
7233 err = WSAGetLastError();
\r
7234 if (err == WSAEADDRINUSE) continue;
\r
7238 if (connect(s, (struct sockaddr *) &sa,
\r
7239 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7240 err = WSAGetLastError();
\r
7241 if (err == WSAEADDRINUSE) {
\r
7252 /* Bind stderr local socket to unused "privileged" port address
\r
7254 s2 = INVALID_SOCKET;
\r
7255 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7256 mysa.sin_family = AF_INET;
\r
7257 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7258 for (fromPort = 1023;; fromPort--) {
\r
7259 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
7260 if (fromPort < 0) {
\r
7261 (void) closesocket(s);
\r
7263 return WSAEADDRINUSE;
\r
7265 if (s2 == INVALID_SOCKET) {
\r
7266 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7267 err = WSAGetLastError();
\r
7273 uport = (unsigned short) fromPort;
\r
7274 mysa.sin_port = htons(uport);
\r
7275 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7276 == SOCKET_ERROR) {
\r
7277 err = WSAGetLastError();
\r
7278 if (err == WSAEADDRINUSE) continue;
\r
7279 (void) closesocket(s);
\r
7283 if (listen(s2, 1) == SOCKET_ERROR) {
\r
7284 err = WSAGetLastError();
\r
7285 if (err == WSAEADDRINUSE) {
\r
7287 s2 = INVALID_SOCKET;
\r
7290 (void) closesocket(s);
\r
7291 (void) closesocket(s2);
\r
7297 prevStderrPort = fromPort; // remember port used
\r
7298 sprintf(stderrPortStr, "%d", fromPort);
\r
7300 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
7301 err = WSAGetLastError();
\r
7302 (void) closesocket(s);
\r
7303 (void) closesocket(s2);
\r
7308 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
7309 err = WSAGetLastError();
\r
7310 (void) closesocket(s);
\r
7311 (void) closesocket(s2);
\r
7315 if (*user == NULLCHAR) user = UserName();
\r
7316 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
7317 err = WSAGetLastError();
\r
7318 (void) closesocket(s);
\r
7319 (void) closesocket(s2);
\r
7323 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
7324 err = WSAGetLastError();
\r
7325 (void) closesocket(s);
\r
7326 (void) closesocket(s2);
\r
7331 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
7332 err = WSAGetLastError();
\r
7333 (void) closesocket(s);
\r
7334 (void) closesocket(s2);
\r
7338 (void) closesocket(s2); /* Stop listening */
\r
7340 /* Prepare return value */
\r
7341 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7342 cp->kind = CPRcmd;
\r
7345 *pr = (ProcRef *) cp;
\r
7352 AddInputSource(ProcRef pr, int lineByLine,
\r
7353 InputCallback func, VOIDSTAR closure)
\r
7355 InputSource *is, *is2;
\r
7356 ChildProc *cp = (ChildProc *) pr;
\r
7358 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
7359 is->lineByLine = lineByLine;
\r
7361 is->closure = closure;
\r
7362 is->second = NULL;
\r
7363 is->next = is->buf;
\r
7364 if (pr == NoProc) {
\r
7365 is->kind = CPReal;
\r
7366 consoleInputSource = is;
\r
7368 is->kind = cp->kind;
\r
7369 switch (cp->kind) {
\r
7371 is->hFile = cp->hFrom;
\r
7372 cp->hFrom = NULL; /* now owned by InputThread */
\r
7374 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
7375 (LPVOID) is, 0, &is->id);
\r
7379 is->hFile = cp->hFrom;
\r
7380 cp->hFrom = NULL; /* now owned by InputThread */
\r
7382 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
7383 (LPVOID) is, 0, &is->id);
\r
7387 is->sock = cp->sock;
\r
7389 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7390 (LPVOID) is, 0, &is->id);
\r
7394 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
7396 is->sock = cp->sock;
\r
7398 is2->sock = cp->sock2;
\r
7399 is2->second = is2;
\r
7401 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7402 (LPVOID) is, 0, &is->id);
\r
7404 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7405 (LPVOID) is2, 0, &is2->id);
\r
7409 return (InputSourceRef) is;
\r
7413 RemoveInputSource(InputSourceRef isr)
\r
7417 is = (InputSource *) isr;
\r
7418 is->hThread = NULL; /* tell thread to stop */
\r
7419 CloseHandle(is->hThread);
\r
7420 if (is->second != NULL) {
\r
7421 is->second->hThread = NULL;
\r
7422 CloseHandle(is->second->hThread);
\r
7428 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
7431 int outCount = SOCKET_ERROR;
\r
7432 ChildProc *cp = (ChildProc *) pr;
\r
7433 static OVERLAPPED ovl;
\r
7435 if (pr == NoProc) {
\r
7436 ConsoleOutput(message, count, FALSE);
\r
7440 if (ovl.hEvent == NULL) {
\r
7441 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7443 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7445 switch (cp->kind) {
\r
7448 outCount = send(cp->sock, message, count, 0);
\r
7449 if (outCount == SOCKET_ERROR) {
\r
7450 *outError = WSAGetLastError();
\r
7452 *outError = NO_ERROR;
\r
7457 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
7458 &dOutCount, NULL)) {
\r
7459 *outError = NO_ERROR;
\r
7460 outCount = (int) dOutCount;
\r
7462 *outError = GetLastError();
\r
7467 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
7468 &dOutCount, &ovl);
\r
7469 if (*outError == NO_ERROR) {
\r
7470 outCount = (int) dOutCount;
\r
7478 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
7481 /* Ignore delay, not implemented for WinBoard */
\r
7482 return OutputToProcess(pr, message, count, outError);
\r
7487 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
7488 char *buf, int count, int error)
\r
7490 DisplayFatalError("Not implemented", 0, 1);
\r
7493 /* see wgamelist.c for Game List functions */
\r
7494 /* see wedittags.c for Edit Tags functions */
\r
7501 char buf[MSG_SIZ];
\r
7504 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
7505 f = fopen(buf, "r");
\r
7507 ProcessICSInitScript(f);
\r
7515 StartAnalysisClock()
\r
7517 if (analysisTimerEvent) return;
\r
7518 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
7519 (UINT) 2000, NULL);
\r
7523 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7525 static HANDLE hwndText;
\r
7527 static int sizeX, sizeY;
\r
7528 int newSizeX, newSizeY, flags;
\r
7531 switch (message) {
\r
7532 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7533 /* Initialize the dialog items */
\r
7534 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
7535 SetWindowText(hDlg, analysisTitle);
\r
7536 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
7537 /* Size and position the dialog */
\r
7538 if (!analysisDialog) {
\r
7539 analysisDialog = hDlg;
\r
7540 flags = SWP_NOZORDER;
\r
7541 GetClientRect(hDlg, &rect);
\r
7542 sizeX = rect.right;
\r
7543 sizeY = rect.bottom;
\r
7544 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
7545 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
7546 WINDOWPLACEMENT wp;
\r
7547 EnsureOnScreen(&analysisX, &analysisY);
\r
7548 wp.length = sizeof(WINDOWPLACEMENT);
\r
7550 wp.showCmd = SW_SHOW;
\r
7551 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7552 wp.rcNormalPosition.left = analysisX;
\r
7553 wp.rcNormalPosition.right = analysisX + analysisW;
\r
7554 wp.rcNormalPosition.top = analysisY;
\r
7555 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
7556 SetWindowPlacement(hDlg, &wp);
\r
7558 GetClientRect(hDlg, &rect);
\r
7559 newSizeX = rect.right;
\r
7560 newSizeY = rect.bottom;
\r
7561 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7562 newSizeX, newSizeY);
\r
7569 case WM_COMMAND: /* message: received a command */
\r
7570 switch (LOWORD(wParam)) {
\r
7580 newSizeX = LOWORD(lParam);
\r
7581 newSizeY = HIWORD(lParam);
\r
7582 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7587 case WM_GETMINMAXINFO:
\r
7588 /* Prevent resizing window too small */
\r
7589 mmi = (MINMAXINFO *) lParam;
\r
7590 mmi->ptMinTrackSize.x = 100;
\r
7591 mmi->ptMinTrackSize.y = 100;
\r
7598 AnalysisPopUp(char* title, char* str)
\r
7603 if (str == NULL) str = "";
\r
7604 p = (char *) malloc(2 * strlen(str) + 2);
\r
7607 if (*str == '\n') *q++ = '\r';
\r
7611 if (analysisText != NULL) free(analysisText);
\r
7614 if (analysisDialog) {
\r
7615 SetWindowText(analysisDialog, title);
\r
7616 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
7617 ShowWindow(analysisDialog, SW_SHOW);
\r
7619 analysisTitle = title;
\r
7620 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
7621 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
7622 hwndMain, (DLGPROC)lpProc);
\r
7623 FreeProcInstance(lpProc);
\r
7625 analysisDialogUp = TRUE;
\r
7631 if (analysisDialog) {
\r
7632 ShowWindow(analysisDialog, SW_HIDE);
\r
7634 analysisDialogUp = FALSE;
\r
7639 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
7641 highlightInfo.sq[0].x = fromX;
\r
7642 highlightInfo.sq[0].y = fromY;
\r
7643 highlightInfo.sq[1].x = toX;
\r
7644 highlightInfo.sq[1].y = toY;
\r
7650 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
7651 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
7655 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
7657 premoveHighlightInfo.sq[0].x = fromX;
\r
7658 premoveHighlightInfo.sq[0].y = fromY;
\r
7659 premoveHighlightInfo.sq[1].x = toX;
\r
7660 premoveHighlightInfo.sq[1].y = toY;
\r
7664 ClearPremoveHighlights()
\r
7666 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
7667 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
7671 ShutDownFrontEnd()
\r
7673 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
7674 DeleteClipboardTempFiles();
\r
7680 if (IsIconic(hwndMain))
\r
7681 ShowWindow(hwndMain, SW_RESTORE);
\r
7683 SetActiveWindow(hwndMain);
\r
7687 * Prototypes for animation support routines
\r
7689 static void ScreenSquare(int column, int row, POINT * pt);
\r
7690 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
7691 POINT frames[], int * nFrames);
\r
7697 AnimateMove(board, fromX, fromY, toX, toY)
\r
7704 ChessSquare piece;
\r
7705 POINT start, finish, mid;
\r
7706 POINT frames[kFactor * 2 + 1];
\r
7709 if (!appData.animate) return;
\r
7710 if (doingSizing) return;
\r
7711 if (fromY < 0 || fromX < 0) return;
\r
7712 piece = board[fromY][fromX];
\r
7713 if (piece >= EmptySquare) return;
\r
7715 ScreenSquare(fromX, fromY, &start);
\r
7716 ScreenSquare(toX, toY, &finish);
\r
7718 /* All pieces except knights move in straight line */
\r
7719 if (piece != WhiteKnight && piece != BlackKnight) {
\r
7720 mid.x = start.x + (finish.x - start.x) / 2;
\r
7721 mid.y = start.y + (finish.y - start.y) / 2;
\r
7723 /* Knight: make diagonal movement then straight */
\r
7724 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
7725 mid.x = start.x + (finish.x - start.x) / 2;
\r
7729 mid.y = start.y + (finish.y - start.y) / 2;
\r
7733 /* Don't use as many frames for very short moves */
\r
7734 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
7735 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
7737 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
7739 animInfo.from.x = fromX;
\r
7740 animInfo.from.y = fromY;
\r
7741 animInfo.to.x = toX;
\r
7742 animInfo.to.y = toY;
\r
7743 animInfo.lastpos = start;
\r
7744 animInfo.piece = piece;
\r
7745 for (n = 0; n < nFrames; n++) {
\r
7746 animInfo.pos = frames[n];
\r
7747 DrawPosition(FALSE, NULL);
\r
7748 animInfo.lastpos = animInfo.pos;
\r
7749 Sleep(appData.animSpeed);
\r
7751 animInfo.pos = finish;
\r
7752 DrawPosition(FALSE, NULL);
\r
7753 animInfo.piece = EmptySquare;
\r
7756 /* Convert board position to corner of screen rect and color */
\r
7759 ScreenSquare(column, row, pt)
\r
7760 int column; int row; POINT * pt;
\r
7763 pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
7764 pt->y = lineGap + row * (squareSize + lineGap);
\r
7766 pt->x = lineGap + column * (squareSize + lineGap);
\r
7767 pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
7771 /* Generate a series of frame coords from start->mid->finish.
\r
7772 The movement rate doubles until the half way point is
\r
7773 reached, then halves back down to the final destination,
\r
7774 which gives a nice slow in/out effect. The algorithmn
\r
7775 may seem to generate too many intermediates for short
\r
7776 moves, but remember that the purpose is to attract the
\r
7777 viewers attention to the piece about to be moved and
\r
7778 then to where it ends up. Too few frames would be less
\r
7782 Tween(start, mid, finish, factor, frames, nFrames)
\r
7783 POINT * start; POINT * mid;
\r
7784 POINT * finish; int factor;
\r
7785 POINT frames[]; int * nFrames;
\r
7787 int n, fraction = 1, count = 0;
\r
7789 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
7790 for (n = 0; n < factor; n++)
\r
7792 for (n = 0; n < factor; n++) {
\r
7793 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
7794 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
7796 fraction = fraction / 2;
\r
7800 frames[count] = *mid;
\r
7803 /* Slow out, stepping 1/2, then 1/4, ... */
\r
7805 for (n = 0; n < factor; n++) {
\r
7806 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
7807 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
7809 fraction = fraction * 2;
\r
7815 HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current)
\r
7817 /* Currently not implemented in WinBoard */
\r