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
3112 case WM_MBUTTONDOWN:
\r
3113 case WM_RBUTTONDOWN:
\r
3116 fromX = fromY = -1;
\r
3117 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
3118 dragInfo.start.x = dragInfo.start.y = -1;
\r
3119 dragInfo.from = dragInfo.start;
\r
3120 dragInfo.lastpos = dragInfo.pos;
\r
3121 if (appData.highlightDragging) {
\r
3122 ClearHighlights();
\r
3124 DrawPosition(TRUE, NULL);
\r
3126 switch (gameMode) {
\r
3127 case EditPosition:
\r
3128 case IcsExamining:
\r
3129 if (x < 0 || y < 0) break;
\r
3132 if (message == WM_MBUTTONDOWN) {
\r
3133 buttonCount = 3; /* even if system didn't think so */
\r
3134 if (wParam & MK_SHIFT)
\r
3135 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3137 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3138 } else { /* message == WM_RBUTTONDOWN */
\r
3140 if (buttonCount == 3) {
\r
3141 if (wParam & MK_SHIFT)
\r
3142 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3144 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3146 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3149 /* Just have one menu, on the right button. Windows users don't
\r
3150 think to try the middle one, and sometimes other software steals
\r
3151 it, or it doesn't really exist. */
\r
3152 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3156 case IcsPlayingWhite:
\r
3157 case IcsPlayingBlack:
\r
3159 case MachinePlaysWhite:
\r
3160 case MachinePlaysBlack:
\r
3161 if (appData.testLegality &&
\r
3162 gameInfo.variant != VariantBughouse &&
\r
3163 gameInfo.variant != VariantCrazyhouse) break;
\r
3164 if (x < 0 || y < 0) break;
\r
3167 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
3168 SetupDropMenu(hmenu);
\r
3169 MenuPopup(hwnd, pt, hmenu, -1);
\r
3180 /* Preprocess messages for buttons in main window */
\r
3182 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3184 int id = GetWindowLong(hwnd, GWL_ID);
\r
3187 for (i=0; i<N_BUTTONS; i++) {
\r
3188 if (buttonDesc[i].id == id) break;
\r
3190 if (i == N_BUTTONS) return 0;
\r
3191 switch (message) {
\r
3196 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
3197 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
3204 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
3207 if (appData.icsActive) {
\r
3208 if (GetKeyState(VK_SHIFT) < 0) {
\r
3210 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3211 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3215 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3216 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3223 if (appData.icsActive) {
\r
3224 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3225 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3227 SendMessage(h, WM_CHAR, wParam, lParam);
\r
3229 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
3230 PopUpMoveDialog((char)wParam);
\r
3236 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
3239 /* Process messages for Promotion dialog box */
\r
3241 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
3245 switch (message) {
\r
3246 case WM_INITDIALOG: /* message: initialize dialog box */
\r
3247 /* Center the dialog over the application window */
\r
3248 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
3249 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
3250 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
3251 gameInfo.variant == VariantGiveaway) ?
\r
3252 SW_SHOW : SW_HIDE);
\r
3255 case WM_COMMAND: /* message: received a command */
\r
3256 switch (LOWORD(wParam)) {
\r
3258 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3259 ClearHighlights();
\r
3260 DrawPosition(FALSE, NULL);
\r
3280 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3281 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
3282 if (!appData.highlightLastMove) {
\r
3283 ClearHighlights();
\r
3284 DrawPosition(FALSE, NULL);
\r
3291 /* Pop up promotion dialog */
\r
3293 PromotionPopup(HWND hwnd)
\r
3297 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
3298 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
3299 hwnd, (DLGPROC)lpProc);
\r
3300 FreeProcInstance(lpProc);
\r
3303 /* Toggle ShowThinking */
\r
3305 ToggleShowThinking()
\r
3307 ShowThinkingEvent(!appData.showThinking);
\r
3311 LoadGameDialog(HWND hwnd, char* title)
\r
3315 char fileTitle[MSG_SIZ];
\r
3316 f = OpenFileDialog(hwnd, FALSE, "",
\r
3317 appData.oldSaveStyle ? "gam" : "pgn",
\r
3319 title, &number, fileTitle, NULL);
\r
3321 cmailMsgLoaded = FALSE;
\r
3322 if (number == 0) {
\r
3323 int error = GameListBuild(f);
\r
3325 DisplayError("Cannot build game list", error);
\r
3326 } else if (!ListEmpty(&gameList) &&
\r
3327 ((ListGame *) gameList.tailPred)->number > 1) {
\r
3328 GameListPopUp(f, fileTitle);
\r
3331 GameListDestroy();
\r
3334 LoadGame(f, number, fileTitle, FALSE);
\r
3339 ChangedConsoleFont()
\r
3342 CHARRANGE tmpsel, sel;
\r
3343 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
3344 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3345 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3348 cfmt.cbSize = sizeof(CHARFORMAT);
\r
3349 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
3350 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
3351 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
3352 * size. This was undocumented in the version of MSVC++ that I had
\r
3353 * when I wrote the code, but is apparently documented now.
\r
3355 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
3356 cfmt.bCharSet = f->lf.lfCharSet;
\r
3357 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
3358 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
3359 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
3360 /* Why are the following seemingly needed too? */
\r
3361 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
3362 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
3363 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
3365 tmpsel.cpMax = -1; /*999999?*/
\r
3366 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
3367 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
3368 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
3369 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
3371 paraf.cbSize = sizeof(paraf);
\r
3372 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
3373 paraf.dxStartIndent = 0;
\r
3374 paraf.dxOffset = WRAP_INDENT;
\r
3375 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
3376 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
3379 /*---------------------------------------------------------------------------*\
\r
3381 * Window Proc for main window
\r
3383 \*---------------------------------------------------------------------------*/
\r
3385 /* Process messages for main window, etc. */
\r
3387 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3390 int wmId, wmEvent;
\r
3394 char fileTitle[MSG_SIZ];
\r
3396 switch (message) {
\r
3398 case WM_PAINT: /* message: repaint portion of window */
\r
3402 case WM_ERASEBKGND:
\r
3403 if (IsIconic(hwnd)) {
\r
3404 /* Cheat; change the message */
\r
3405 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
3407 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
3411 case WM_LBUTTONDOWN:
\r
3412 case WM_MBUTTONDOWN:
\r
3413 case WM_RBUTTONDOWN:
\r
3414 case WM_LBUTTONUP:
\r
3415 case WM_MBUTTONUP:
\r
3416 case WM_RBUTTONUP:
\r
3417 case WM_MOUSEMOVE:
\r
3418 MouseEvent(hwnd, message, wParam, lParam);
\r
3423 if (appData.icsActive) {
\r
3424 if (wParam == '\t') {
\r
3425 if (GetKeyState(VK_SHIFT) < 0) {
\r
3427 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3428 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3432 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3433 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3437 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3438 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3440 SendMessage(h, message, wParam, lParam);
\r
3442 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
3443 PopUpMoveDialog((char)wParam);
\r
3447 case WM_PALETTECHANGED:
\r
3448 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
3450 HDC hdc = GetDC(hwndMain);
\r
3451 SelectPalette(hdc, hPal, TRUE);
\r
3452 nnew = RealizePalette(hdc);
\r
3454 paletteChanged = TRUE;
\r
3456 UpdateColors(hdc);
\r
3458 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
3461 ReleaseDC(hwnd, hdc);
\r
3465 case WM_QUERYNEWPALETTE:
\r
3466 if (!appData.monoMode /*&& paletteChanged*/) {
\r
3468 HDC hdc = GetDC(hwndMain);
\r
3469 paletteChanged = FALSE;
\r
3470 SelectPalette(hdc, hPal, FALSE);
\r
3471 nnew = RealizePalette(hdc);
\r
3473 InvalidateRect(hwnd, &boardRect, FALSE);
\r
3475 ReleaseDC(hwnd, hdc);
\r
3480 case WM_COMMAND: /* message: command from application menu */
\r
3481 wmId = LOWORD(wParam);
\r
3482 wmEvent = HIWORD(wParam);
\r
3487 AnalysisPopDown();
\r
3490 case IDM_LoadGame:
\r
3491 LoadGameDialog(hwnd, "Load Game from File");
\r
3494 case IDM_LoadNextGame:
\r
3498 case IDM_LoadPrevGame:
\r
3502 case IDM_ReloadGame:
\r
3506 case IDM_LoadPosition:
\r
3507 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
3508 Reset(FALSE, TRUE);
\r
3511 f = OpenFileDialog(hwnd, FALSE, "",
\r
3512 appData.oldSaveStyle ? "pos" : "fen",
\r
3514 "Load Position from File", &number, fileTitle, NULL);
\r
3516 LoadPosition(f, number, fileTitle);
\r
3520 case IDM_LoadNextPosition:
\r
3521 ReloadPosition(1);
\r
3524 case IDM_LoadPrevPosition:
\r
3525 ReloadPosition(-1);
\r
3528 case IDM_ReloadPosition:
\r
3529 ReloadPosition(0);
\r
3532 case IDM_SaveGame:
\r
3533 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
3534 f = OpenFileDialog(hwnd, TRUE, defName,
\r
3535 appData.oldSaveStyle ? "gam" : "pgn",
\r
3537 "Save Game to File", NULL, fileTitle, NULL);
\r
3539 SaveGame(f, 0, "");
\r
3543 case IDM_SavePosition:
\r
3544 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
3545 f = OpenFileDialog(hwnd, TRUE, defName,
\r
3546 appData.oldSaveStyle ? "pos" : "fen",
\r
3548 "Save Position to File", NULL, fileTitle, NULL);
\r
3550 SavePosition(f, 0, "");
\r
3554 case IDM_CopyGame:
\r
3555 CopyGameToClipboard();
\r
3558 case IDM_PasteGame:
\r
3559 PasteGameFromClipboard();
\r
3562 case IDM_CopyPosition:
\r
3563 CopyFENToClipboard();
\r
3566 case IDM_PastePosition:
\r
3567 PasteFENFromClipboard();
\r
3570 case IDM_MailMove:
\r
3574 case IDM_ReloadCMailMsg:
\r
3575 Reset(TRUE, TRUE);
\r
3576 ReloadCmailMsgEvent(FALSE);
\r
3579 case IDM_Minimize:
\r
3580 ShowWindow(hwnd, SW_MINIMIZE);
\r
3587 case IDM_MachineWhite:
\r
3588 MachineWhiteEvent();
\r
3590 * refresh the tags dialog only if it's visible
\r
3592 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
3594 tags = PGNTags(&gameInfo);
\r
3595 TagsPopUp(tags, CmailMsg());
\r
3600 case IDM_MachineBlack:
\r
3601 MachineBlackEvent();
\r
3603 * refresh the tags dialog only if it's visible
\r
3605 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
3607 tags = PGNTags(&gameInfo);
\r
3608 TagsPopUp(tags, CmailMsg());
\r
3613 case IDM_TwoMachines:
\r
3614 TwoMachinesEvent();
\r
3616 * refresh the tags dialog only if it's visible
\r
3618 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
3620 tags = PGNTags(&gameInfo);
\r
3621 TagsPopUp(tags, CmailMsg());
\r
3626 case IDM_AnalysisMode:
\r
3627 if (!first.analysisSupport) {
\r
3628 char buf[MSG_SIZ];
\r
3629 sprintf(buf, "%s does not support analysis", first.tidy);
\r
3630 DisplayError(buf, 0);
\r
3632 if (!appData.showThinking) ToggleShowThinking();
\r
3633 AnalyzeModeEvent();
\r
3637 case IDM_AnalyzeFile:
\r
3638 if (!first.analysisSupport) {
\r
3639 char buf[MSG_SIZ];
\r
3640 sprintf(buf, "%s does not support analysis", first.tidy);
\r
3641 DisplayError(buf, 0);
\r
3643 if (!appData.showThinking) ToggleShowThinking();
\r
3644 AnalyzeFileEvent();
\r
3645 LoadGameDialog(hwnd, "Analyze Game from File");
\r
3646 AnalysisPeriodicEvent(1);
\r
3650 case IDM_IcsClient:
\r
3654 case IDM_EditGame:
\r
3658 case IDM_EditPosition:
\r
3659 EditPositionEvent();
\r
3662 case IDM_Training:
\r
3666 case IDM_ShowGameList:
\r
3667 ShowGameListProc();
\r
3670 case IDM_EditTags:
\r
3674 case IDM_EditComment:
\r
3675 if (commentDialogUp && editComment) {
\r
3678 EditCommentEvent();
\r
3698 case IDM_CallFlag:
\r
3718 case IDM_StopObserving:
\r
3719 StopObservingEvent();
\r
3722 case IDM_StopExamining:
\r
3723 StopExaminingEvent();
\r
3726 case IDM_TypeInMove:
\r
3727 PopUpMoveDialog('\000');
\r
3730 case IDM_Backward:
\r
3732 SetFocus(hwndMain);
\r
3737 SetFocus(hwndMain);
\r
3742 SetFocus(hwndMain);
\r
3747 SetFocus(hwndMain);
\r
3754 case IDM_TruncateGame:
\r
3755 TruncateGameEvent();
\r
3762 case IDM_RetractMove:
\r
3763 RetractMoveEvent();
\r
3766 case IDM_FlipView:
\r
3767 flipView = !flipView;
\r
3768 DrawPosition(FALSE, NULL);
\r
3771 case IDM_GeneralOptions:
\r
3772 GeneralOptionsPopup(hwnd);
\r
3775 case IDM_BoardOptions:
\r
3776 BoardOptionsPopup(hwnd);
\r
3779 case IDM_IcsOptions:
\r
3780 IcsOptionsPopup(hwnd);
\r
3784 FontsOptionsPopup(hwnd);
\r
3788 SoundOptionsPopup(hwnd);
\r
3791 case IDM_CommPort:
\r
3792 CommPortOptionsPopup(hwnd);
\r
3795 case IDM_LoadOptions:
\r
3796 LoadOptionsPopup(hwnd);
\r
3799 case IDM_SaveOptions:
\r
3800 SaveOptionsPopup(hwnd);
\r
3803 case IDM_TimeControl:
\r
3804 TimeControlOptionsPopup(hwnd);
\r
3807 case IDM_SaveSettings:
\r
3808 SaveSettings(settingsFileName);
\r
3811 case IDM_SaveSettingsOnExit:
\r
3812 saveSettingsOnExit = !saveSettingsOnExit;
\r
3813 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
3814 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
3815 MF_CHECKED : MF_UNCHECKED));
\r
3826 case IDM_AboutGame:
\r
3831 appData.debugMode = !appData.debugMode;
\r
3832 if (appData.debugMode) {
\r
3833 char dir[MSG_SIZ];
\r
3834 GetCurrentDirectory(MSG_SIZ, dir);
\r
3835 SetCurrentDirectory(installDir);
\r
3836 debugFP = fopen("WinBoard.debug", "w");
\r
3837 SetCurrentDirectory(dir);
\r
3838 setbuf(debugFP, NULL);
\r
3845 case IDM_HELPCONTENTS:
\r
3846 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
3847 MessageBox (GetFocus(),
\r
3848 "Unable to activate help",
\r
3849 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3853 case IDM_HELPSEARCH:
\r
3854 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
3855 MessageBox (GetFocus(),
\r
3856 "Unable to activate help",
\r
3857 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3861 case IDM_HELPHELP:
\r
3862 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
3863 MessageBox (GetFocus(),
\r
3864 "Unable to activate help",
\r
3865 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
3870 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
3872 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
3873 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
3874 FreeProcInstance(lpProc);
\r
3877 case IDM_DirectCommand1:
\r
3878 AskQuestionEvent("Direct Command",
\r
3879 "Send to chess program:", "", "1");
\r
3881 case IDM_DirectCommand2:
\r
3882 AskQuestionEvent("Direct Command",
\r
3883 "Send to second chess program:", "", "2");
\r
3886 case EP_WhitePawn:
\r
3887 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
3888 fromX = fromY = -1;
\r
3891 case EP_WhiteKnight:
\r
3892 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
3893 fromX = fromY = -1;
\r
3896 case EP_WhiteBishop:
\r
3897 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
3898 fromX = fromY = -1;
\r
3901 case EP_WhiteRook:
\r
3902 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
3903 fromX = fromY = -1;
\r
3906 case EP_WhiteQueen:
\r
3907 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
3908 fromX = fromY = -1;
\r
3911 case EP_WhiteKing:
\r
3912 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
3913 fromX = fromY = -1;
\r
3916 case EP_BlackPawn:
\r
3917 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
3918 fromX = fromY = -1;
\r
3921 case EP_BlackKnight:
\r
3922 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
3923 fromX = fromY = -1;
\r
3926 case EP_BlackBishop:
\r
3927 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
3928 fromX = fromY = -1;
\r
3931 case EP_BlackRook:
\r
3932 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
3933 fromX = fromY = -1;
\r
3936 case EP_BlackQueen:
\r
3937 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
3938 fromX = fromY = -1;
\r
3941 case EP_BlackKing:
\r
3942 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
3943 fromX = fromY = -1;
\r
3946 case EP_EmptySquare:
\r
3947 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
3948 fromX = fromY = -1;
\r
3951 case EP_ClearBoard:
\r
3952 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
3953 fromX = fromY = -1;
\r
3957 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
3958 fromX = fromY = -1;
\r
3962 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
3963 fromX = fromY = -1;
\r
3967 DropMenuEvent(WhitePawn, fromX, fromY);
\r
3968 fromX = fromY = -1;
\r
3972 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
3973 fromX = fromY = -1;
\r
3977 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
3978 fromX = fromY = -1;
\r
3982 DropMenuEvent(WhiteRook, fromX, fromY);
\r
3983 fromX = fromY = -1;
\r
3987 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
3988 fromX = fromY = -1;
\r
3992 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
3998 case CLOCK_TIMER_ID:
\r
3999 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
4000 clockTimerEvent = 0;
\r
4001 DecrementClocks(); /* call into back end */
\r
4003 case LOAD_GAME_TIMER_ID:
\r
4004 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
4005 loadGameTimerEvent = 0;
\r
4006 AutoPlayGameLoop(); /* call into back end */
\r
4008 case ANALYSIS_TIMER_ID:
\r
4009 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
4010 appData.periodicUpdates) {
\r
4011 AnalysisPeriodicEvent(0);
\r
4013 KillTimer(hwnd, analysisTimerEvent);
\r
4014 analysisTimerEvent = 0;
\r
4017 case DELAYED_TIMER_ID:
\r
4018 KillTimer(hwnd, delayedTimerEvent);
\r
4019 delayedTimerEvent = 0;
\r
4020 delayedTimerCallback();
\r
4025 case WM_USER_Input:
\r
4026 InputEvent(hwnd, message, wParam, lParam);
\r
4029 case WM_ENTERSIZEMOVE:
\r
4030 if (hwnd == hwndMain) {
\r
4031 doingSizing = TRUE;
\r
4037 if (hwnd == hwndMain) {
\r
4038 lastSizing = wParam;
\r
4042 case WM_EXITSIZEMOVE:
\r
4043 if (hwnd == hwndMain) {
\r
4045 doingSizing = FALSE;
\r
4046 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4047 GetClientRect(hwnd, &client);
\r
4048 ResizeBoard(client.right, client.bottom, lastSizing);
\r
4053 case WM_DESTROY: /* message: window being destroyed */
\r
4054 PostQuitMessage(0);
\r
4058 if (hwnd == hwndMain) {
\r
4063 default: /* Passes it on if unprocessed */
\r
4064 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4069 /*---------------------------------------------------------------------------*\
\r
4071 * Misc utility routines
\r
4073 \*---------------------------------------------------------------------------*/
\r
4076 * Decent random number generator, at least not as bad as Windows
\r
4077 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
4079 unsigned int randstate;
\r
4084 randstate = randstate * 1664525 + 1013904223;
\r
4085 return (int) randstate & 0x7fffffff;
\r
4089 mysrandom(unsigned int seed)
\r
4096 * returns TRUE if user selects a different color, FALSE otherwise
\r
4100 ChangeColor(HWND hwnd, COLORREF *which)
\r
4102 static BOOL firstTime = TRUE;
\r
4103 static DWORD customColors[16];
\r
4105 COLORREF newcolor;
\r
4110 /* Make initial colors in use available as custom colors */
\r
4111 /* Should we put the compiled-in defaults here instead? */
\r
4113 customColors[i++] = lightSquareColor & 0xffffff;
\r
4114 customColors[i++] = darkSquareColor & 0xffffff;
\r
4115 customColors[i++] = whitePieceColor & 0xffffff;
\r
4116 customColors[i++] = blackPieceColor & 0xffffff;
\r
4117 customColors[i++] = highlightSquareColor & 0xffffff;
\r
4118 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
4120 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
4121 customColors[i++] = textAttribs[ccl].color;
\r
4123 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
4124 firstTime = FALSE;
\r
4127 cc.lStructSize = sizeof(cc);
\r
4128 cc.hwndOwner = hwnd;
\r
4129 cc.hInstance = NULL;
\r
4130 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
4131 cc.lpCustColors = (LPDWORD) customColors;
\r
4132 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
4134 if (!ChooseColor(&cc)) return FALSE;
\r
4136 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
4137 if (newcolor == *which) return FALSE;
\r
4138 *which = newcolor;
\r
4142 InitDrawingColors();
\r
4143 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4148 MyLoadSound(MySound *ms)
\r
4154 if (ms->data) free(ms->data);
\r
4157 switch (ms->name[0]) {
\r
4163 /* System sound from Control Panel. Don't preload here. */
\r
4167 if (ms->name[1] == NULLCHAR) {
\r
4168 /* "!" alone = silence */
\r
4171 /* Builtin wave resource. Error if not found. */
\r
4172 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
4173 if (h == NULL) break;
\r
4174 ms->data = (void *)LoadResource(hInst, h);
\r
4175 if (h == NULL) break;
\r
4180 /* .wav file. Error if not found. */
\r
4181 f = fopen(ms->name, "rb");
\r
4182 if (f == NULL) break;
\r
4183 if (fstat(fileno(f), &st) < 0) break;
\r
4184 ms->data = malloc(st.st_size);
\r
4185 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
4191 char buf[MSG_SIZ];
\r
4192 sprintf(buf, "Error loading sound %s", ms->name);
\r
4193 DisplayError(buf, GetLastError());
\r
4199 MyPlaySound(MySound *ms)
\r
4201 BOOLEAN ok = FALSE;
\r
4202 switch (ms->name[0]) {
\r
4208 /* System sound from Control Panel (deprecated feature).
\r
4209 "$" alone or an unset sound name gets default beep (still in use). */
\r
4210 if (ms->name[1]) {
\r
4211 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
4213 if (!ok) ok = MessageBeep(MB_OK);
\r
4216 /* Builtin wave resource, or "!" alone for silence */
\r
4217 if (ms->name[1]) {
\r
4218 if (ms->data == NULL) return FALSE;
\r
4219 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4225 /* .wav file. Error if not found. */
\r
4226 if (ms->data == NULL) return FALSE;
\r
4227 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4230 /* Don't print an error: this can happen innocently if the sound driver
\r
4231 is busy; for instance, if another instance of WinBoard is playing
\r
4232 a sound at about the same time. */
\r
4235 char buf[MSG_SIZ];
\r
4236 sprintf(buf, "Error playing sound %s", ms->name);
\r
4237 DisplayError(buf, GetLastError());
\r
4245 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4248 OPENFILENAME *ofn;
\r
4249 static UINT *number; /* gross that this is static */
\r
4251 switch (message) {
\r
4252 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4253 /* Center the dialog over the application window */
\r
4254 ofn = (OPENFILENAME *) lParam;
\r
4255 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
4256 number = (UINT *) ofn->lCustData;
\r
4257 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
4261 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4262 return FALSE; /* Allow for further processing */
\r
4265 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
4266 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
4268 return FALSE; /* Allow for further processing */
\r
4274 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
4276 static UINT *number;
\r
4277 OPENFILENAME *ofname;
\r
4280 case WM_INITDIALOG:
\r
4281 ofname = (OPENFILENAME *)lParam;
\r
4282 number = (UINT *)(ofname->lCustData);
\r
4285 ofnot = (OFNOTIFY *)lParam;
\r
4286 if (ofnot->hdr.code == CDN_FILEOK) {
\r
4287 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
4296 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
4297 char *nameFilt, char *dlgTitle, UINT *number,
\r
4298 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
4300 OPENFILENAME openFileName;
\r
4301 char buf1[MSG_SIZ];
\r
4304 if (fileName == NULL) fileName = buf1;
\r
4305 if (defName == NULL) {
\r
4306 strcpy(fileName, "*.");
\r
4307 strcat(fileName, defExt);
\r
4309 strcpy(fileName, defName);
\r
4311 if (fileTitle) strcpy(fileTitle, "");
\r
4312 if (number) *number = 0;
\r
4314 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
4315 openFileName.hwndOwner = hwnd;
\r
4316 openFileName.hInstance = (HANDLE) hInst;
\r
4317 openFileName.lpstrFilter = nameFilt;
\r
4318 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
4319 openFileName.nMaxCustFilter = 0L;
\r
4320 openFileName.nFilterIndex = 1L;
\r
4321 openFileName.lpstrFile = fileName;
\r
4322 openFileName.nMaxFile = MSG_SIZ;
\r
4323 openFileName.lpstrFileTitle = fileTitle;
\r
4324 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
4325 openFileName.lpstrInitialDir = NULL;
\r
4326 openFileName.lpstrTitle = dlgTitle;
\r
4327 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
4328 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
4329 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
4330 | (oldDialog ? 0 : OFN_EXPLORER);
\r
4331 openFileName.nFileOffset = 0;
\r
4332 openFileName.nFileExtension = 0;
\r
4333 openFileName.lpstrDefExt = defExt;
\r
4334 openFileName.lCustData = (LONG) number;
\r
4335 openFileName.lpfnHook = oldDialog ?
\r
4336 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
4337 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
4339 if (write ? GetSaveFileName(&openFileName) :
\r
4340 GetOpenFileName(&openFileName)) {
\r
4341 /* open the file */
\r
4342 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
4344 MessageBox(hwnd, "File open failed", NULL,
\r
4345 MB_OK|MB_ICONEXCLAMATION);
\r
4349 int err = CommDlgExtendedError();
\r
4350 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
4359 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
4361 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
4364 * Get the first pop-up menu in the menu template. This is the
\r
4365 * menu that TrackPopupMenu displays.
\r
4367 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
4369 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
4372 * TrackPopup uses screen coordinates, so convert the
\r
4373 * coordinates of the mouse click to screen coordinates.
\r
4375 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
4377 /* Draw and track the floating pop-up menu. */
\r
4378 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
4379 pt.x, pt.y, 0, hwnd, NULL);
\r
4381 /* Destroy the menu.*/
\r
4382 DestroyMenu(hmenu);
\r
4387 int sizeX, sizeY, newSizeX, newSizeY;
\r
4389 } ResizeEditPlusButtonsClosure;
\r
4392 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
4394 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
4398 if (hChild == cl->hText) return TRUE;
\r
4399 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
4400 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
4401 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
4402 ScreenToClient(cl->hDlg, &pt);
\r
4403 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
4404 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
4408 /* Resize a dialog that has a (rich) edit field filling most of
\r
4409 the top, with a row of buttons below */
\r
4411 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
4414 int newTextHeight, newTextWidth;
\r
4415 ResizeEditPlusButtonsClosure cl;
\r
4417 /*if (IsIconic(hDlg)) return;*/
\r
4418 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
4420 cl.hdwp = BeginDeferWindowPos(8);
\r
4422 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
4423 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
4424 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
4425 if (newTextHeight < 0) {
\r
4426 newSizeY += -newTextHeight;
\r
4427 newTextHeight = 0;
\r
4429 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
4430 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
4436 cl.newSizeX = newSizeX;
\r
4437 cl.newSizeY = newSizeY;
\r
4438 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
4440 EndDeferWindowPos(cl.hdwp);
\r
4443 /* Center one window over another */
\r
4444 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
4446 RECT rChild, rParent;
\r
4447 int wChild, hChild, wParent, hParent;
\r
4448 int wScreen, hScreen, xNew, yNew;
\r
4451 /* Get the Height and Width of the child window */
\r
4452 GetWindowRect (hwndChild, &rChild);
\r
4453 wChild = rChild.right - rChild.left;
\r
4454 hChild = rChild.bottom - rChild.top;
\r
4456 /* Get the Height and Width of the parent window */
\r
4457 GetWindowRect (hwndParent, &rParent);
\r
4458 wParent = rParent.right - rParent.left;
\r
4459 hParent = rParent.bottom - rParent.top;
\r
4461 /* Get the display limits */
\r
4462 hdc = GetDC (hwndChild);
\r
4463 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
4464 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
4465 ReleaseDC(hwndChild, hdc);
\r
4467 /* Calculate new X position, then adjust for screen */
\r
4468 xNew = rParent.left + ((wParent - wChild) /2);
\r
4471 } else if ((xNew+wChild) > wScreen) {
\r
4472 xNew = wScreen - wChild;
\r
4475 /* Calculate new Y position, then adjust for screen */
\r
4476 yNew = rParent.top + ((hParent - hChild) /2);
\r
4479 } else if ((yNew+hChild) > hScreen) {
\r
4480 yNew = hScreen - hChild;
\r
4483 /* Set it, and return */
\r
4484 return SetWindowPos (hwndChild, NULL,
\r
4485 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
4488 /*---------------------------------------------------------------------------*\
\r
4490 * Startup Dialog functions
\r
4492 \*---------------------------------------------------------------------------*/
\r
4494 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
4496 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
4498 while (*cd != NULL) {
\r
4499 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
4505 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
4507 char buf1[ARG_MAX];
\r
4510 if (str[0] == '@') {
\r
4511 FILE* f = fopen(str + 1, "r");
\r
4513 DisplayFatalError(str + 1, errno, 2);
\r
4516 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
4518 buf1[len] = NULLCHAR;
\r
4522 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
4525 char buf[MSG_SIZ];
\r
4526 char *end = strchr(str, '\n');
\r
4527 if (end == NULL) return;
\r
4528 memcpy(buf, str, end - str);
\r
4529 buf[end - str] = NULLCHAR;
\r
4530 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
4536 SetStartupDialogEnables(HWND hDlg)
\r
4538 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
4539 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
4540 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
4541 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
4542 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
4543 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
4544 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
4545 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
4546 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
4547 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
4548 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
4549 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
4550 IsDlgButtonChecked(hDlg, OPT_View));
\r
4554 QuoteForFilename(char *filename)
\r
4556 int dquote, space;
\r
4557 dquote = strchr(filename, '"') != NULL;
\r
4558 space = strchr(filename, ' ') != NULL;
\r
4559 if (dquote || space) {
\r
4571 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
4573 char buf[MSG_SIZ];
\r
4576 InitComboStringsFromOption(hwndCombo, nthnames);
\r
4577 q = QuoteForFilename(nthcp);
\r
4578 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
4579 if (*nthdir != NULLCHAR) {
\r
4580 q = QuoteForFilename(nthdir);
\r
4581 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
4583 if (*nthcp == NULLCHAR) {
\r
4584 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
4585 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
4586 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
4587 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
4592 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4594 char buf[MSG_SIZ];
\r
4598 switch (message) {
\r
4599 case WM_INITDIALOG:
\r
4600 /* Center the dialog */
\r
4601 CenterWindow (hDlg, GetDesktopWindow());
\r
4602 /* Initialize the dialog items */
\r
4603 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
4604 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
4605 firstChessProgramNames);
\r
4606 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
4607 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
4608 secondChessProgramNames);
\r
4609 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
4610 InitComboStringsFromOption(hwndCombo, icsNames);
\r
4611 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
4612 if (*appData.icsHelper != NULLCHAR) {
\r
4613 char *q = QuoteForFilename(appData.icsHelper);
\r
4614 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
4616 if (*appData.icsHost == NULLCHAR) {
\r
4617 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
4618 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
4619 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
4620 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
4621 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
4623 if (chessProgram) {
\r
4624 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
4625 } else if (appData.icsActive) {
\r
4626 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
4627 } else if (appData.noChessProgram) {
\r
4628 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
4630 SetStartupDialogEnables(hDlg);
\r
4634 switch (LOWORD(wParam)) {
\r
4636 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
4637 strcpy(buf, "/fcp=");
\r
4638 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4640 ParseArgs(StringGet, &p);
\r
4641 strcpy(buf, "/scp=");
\r
4642 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4644 ParseArgs(StringGet, &p);
\r
4645 appData.noChessProgram = FALSE;
\r
4646 appData.icsActive = FALSE;
\r
4647 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
4648 strcpy(buf, "/ics /icshost=");
\r
4649 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4651 ParseArgs(StringGet, &p);
\r
4652 if (appData.zippyPlay) {
\r
4653 strcpy(buf, "/fcp=");
\r
4654 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
4656 ParseArgs(StringGet, &p);
\r
4658 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
4659 appData.noChessProgram = TRUE;
\r
4660 appData.icsActive = FALSE;
\r
4662 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
4663 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
4666 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
4667 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
4669 ParseArgs(StringGet, &p);
\r
4671 EndDialog(hDlg, TRUE);
\r
4678 case IDM_HELPCONTENTS:
\r
4679 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
4680 MessageBox (GetFocus(),
\r
4681 "Unable to activate help",
\r
4682 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4687 SetStartupDialogEnables(hDlg);
\r
4695 /*---------------------------------------------------------------------------*\
\r
4697 * About box dialog functions
\r
4699 \*---------------------------------------------------------------------------*/
\r
4701 /* Process messages for "About" dialog box */
\r
4703 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4705 switch (message) {
\r
4706 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4707 /* Center the dialog over the application window */
\r
4708 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4709 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
4712 case WM_COMMAND: /* message: received a command */
\r
4713 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
4714 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
4715 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4723 /*---------------------------------------------------------------------------*\
\r
4725 * Comment Dialog functions
\r
4727 \*---------------------------------------------------------------------------*/
\r
4730 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4732 static HANDLE hwndText = NULL;
\r
4733 int len, newSizeX, newSizeY, flags;
\r
4734 static int sizeX, sizeY;
\r
4739 switch (message) {
\r
4740 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4741 /* Initialize the dialog items */
\r
4742 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
4743 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
4744 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
4745 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
4746 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
4747 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
4748 SetWindowText(hDlg, commentTitle);
\r
4749 if (editComment) {
\r
4750 SetFocus(hwndText);
\r
4752 SetFocus(GetDlgItem(hDlg, IDOK));
\r
4754 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
4755 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
4756 MAKELPARAM(FALSE, 0));
\r
4757 /* Size and position the dialog */
\r
4758 if (!commentDialog) {
\r
4759 commentDialog = hDlg;
\r
4760 flags = SWP_NOZORDER;
\r
4761 GetClientRect(hDlg, &rect);
\r
4762 sizeX = rect.right;
\r
4763 sizeY = rect.bottom;
\r
4764 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
4765 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
4766 WINDOWPLACEMENT wp;
\r
4767 EnsureOnScreen(&commentX, &commentY);
\r
4768 wp.length = sizeof(WINDOWPLACEMENT);
\r
4770 wp.showCmd = SW_SHOW;
\r
4771 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
4772 wp.rcNormalPosition.left = commentX;
\r
4773 wp.rcNormalPosition.right = commentX + commentW;
\r
4774 wp.rcNormalPosition.top = commentY;
\r
4775 wp.rcNormalPosition.bottom = commentY + commentH;
\r
4776 SetWindowPlacement(hDlg, &wp);
\r
4778 GetClientRect(hDlg, &rect);
\r
4779 newSizeX = rect.right;
\r
4780 newSizeY = rect.bottom;
\r
4781 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
4782 newSizeX, newSizeY);
\r
4789 case WM_COMMAND: /* message: received a command */
\r
4790 switch (LOWORD(wParam)) {
\r
4792 if (editComment) {
\r
4794 /* Read changed options from the dialog box */
\r
4795 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
4796 len = GetWindowTextLength(hwndText);
\r
4797 str = (char *) malloc(len + 1);
\r
4798 GetWindowText(hwndText, str, len + 1);
\r
4807 ReplaceComment(commentIndex, str);
\r
4814 case OPT_CancelComment:
\r
4818 case OPT_ClearComment:
\r
4819 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
4822 case OPT_EditComment:
\r
4823 EditCommentEvent();
\r
4832 newSizeX = LOWORD(lParam);
\r
4833 newSizeY = HIWORD(lParam);
\r
4834 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
4839 case WM_GETMINMAXINFO:
\r
4840 /* Prevent resizing window too small */
\r
4841 mmi = (MINMAXINFO *) lParam;
\r
4842 mmi->ptMinTrackSize.x = 100;
\r
4843 mmi->ptMinTrackSize.y = 100;
\r
4850 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
4855 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
4857 if (str == NULL) str = "";
\r
4858 p = (char *) malloc(2 * strlen(str) + 2);
\r
4861 if (*str == '\n') *q++ = '\r';
\r
4865 if (commentText != NULL) free(commentText);
\r
4867 commentIndex = index;
\r
4868 commentTitle = title;
\r
4870 editComment = edit;
\r
4872 if (commentDialog) {
\r
4873 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
4874 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
4876 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
4877 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
4878 hwndMain, (DLGPROC)lpProc);
\r
4879 FreeProcInstance(lpProc);
\r
4881 commentDialogUp = TRUE;
\r
4885 /*---------------------------------------------------------------------------*\
\r
4887 * Type-in move dialog functions
\r
4889 \*---------------------------------------------------------------------------*/
\r
4892 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4894 char move[MSG_SIZ];
\r
4896 ChessMove moveType;
\r
4897 int fromX, fromY, toX, toY;
\r
4900 switch (message) {
\r
4901 case WM_INITDIALOG:
\r
4902 move[0] = (char) lParam;
\r
4903 move[1] = NULLCHAR;
\r
4904 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4905 hInput = GetDlgItem(hDlg, OPT_Move);
\r
4906 SetWindowText(hInput, move);
\r
4908 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
4912 switch (LOWORD(wParam)) {
\r
4914 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
4915 gameMode != Training) {
\r
4916 DisplayMoveError("Displayed move is not current");
\r
4918 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
4919 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
4920 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
4921 if (gameMode != Training)
\r
4922 forwardMostMove = currentMove;
\r
4923 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4925 DisplayMoveError("Could not parse move");
\r
4928 EndDialog(hDlg, TRUE);
\r
4931 EndDialog(hDlg, FALSE);
\r
4942 PopUpMoveDialog(char firstchar)
\r
4946 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
4947 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
4948 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
4949 gameMode == EditPosition || gameMode == IcsExamining ||
\r
4950 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
4951 gameMode == Training) {
\r
4952 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
4953 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
4954 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
4955 FreeProcInstance(lpProc);
\r
4959 /*---------------------------------------------------------------------------*\
\r
4963 \*---------------------------------------------------------------------------*/
\r
4965 /* Nonmodal error box */
\r
4966 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
4967 WPARAM wParam, LPARAM lParam);
\r
4970 ErrorPopUp(char *title, char *content)
\r
4974 BOOLEAN modal = hwndMain == NULL;
\r
4992 strncpy(errorTitle, title, sizeof(errorTitle));
\r
4993 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
4996 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
4998 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
4999 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
5000 hwndMain, (DLGPROC)lpProc);
\r
5001 FreeProcInstance(lpProc);
\r
5008 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
5009 if (errorDialog == NULL) return;
\r
5010 DestroyWindow(errorDialog);
\r
5011 errorDialog = NULL;
\r
5015 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5020 switch (message) {
\r
5021 case WM_INITDIALOG:
\r
5022 GetWindowRect(hDlg, &rChild);
\r
5023 SetWindowPos(hDlg, NULL, rChild.left,
\r
5024 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
5025 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
5026 errorDialog = hDlg;
\r
5027 SetWindowText(hDlg, errorTitle);
\r
5028 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
5029 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
5033 switch (LOWORD(wParam)) {
\r
5036 if (errorDialog == hDlg) errorDialog = NULL;
\r
5037 DestroyWindow(hDlg);
\r
5048 /*---------------------------------------------------------------------------*\
\r
5050 * Ics Interaction console functions
\r
5052 \*---------------------------------------------------------------------------*/
\r
5054 #define HISTORY_SIZE 64
\r
5055 static char *history[HISTORY_SIZE];
\r
5056 int histIn = 0, histP = 0;
\r
5059 SaveInHistory(char *cmd)
\r
5061 if (history[histIn] != NULL) {
\r
5062 free(history[histIn]);
\r
5063 history[histIn] = NULL;
\r
5065 if (*cmd == NULLCHAR) return;
\r
5066 history[histIn] = StrSave(cmd);
\r
5067 histIn = (histIn + 1) % HISTORY_SIZE;
\r
5068 if (history[histIn] != NULL) {
\r
5069 free(history[histIn]);
\r
5070 history[histIn] = NULL;
\r
5076 PrevInHistory(char *cmd)
\r
5079 if (histP == histIn) {
\r
5080 if (history[histIn] != NULL) free(history[histIn]);
\r
5081 history[histIn] = StrSave(cmd);
\r
5083 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
5084 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
5086 return history[histP];
\r
5092 if (histP == histIn) return NULL;
\r
5093 histP = (histP + 1) % HISTORY_SIZE;
\r
5094 return history[histP];
\r
5101 BOOLEAN immediate;
\r
5102 } IcsTextMenuEntry;
\r
5103 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
5104 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
5107 ParseIcsTextMenu(char *icsTextMenuString)
\r
5110 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
5111 char *p = icsTextMenuString;
\r
5112 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5115 if (e->command != NULL) {
\r
5117 e->command = NULL;
\r
5121 e = icsTextMenuEntry;
\r
5122 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5123 if (*p == ';' || *p == '\n') {
\r
5124 e->item = strdup("-");
\r
5125 e->command = NULL;
\r
5127 } else if (*p == '-') {
\r
5128 e->item = strdup("-");
\r
5129 e->command = NULL;
\r
5133 char *q, *r, *s, *t;
\r
5135 q = strchr(p, ',');
\r
5136 if (q == NULL) break;
\r
5138 r = strchr(q + 1, ',');
\r
5139 if (r == NULL) break;
\r
5141 s = strchr(r + 1, ',');
\r
5142 if (s == NULL) break;
\r
5145 t = strchr(s + 1, c);
\r
5148 t = strchr(s + 1, c);
\r
5150 if (t != NULL) *t = NULLCHAR;
\r
5151 e->item = strdup(p);
\r
5152 e->command = strdup(q + 1);
\r
5153 e->getname = *(r + 1) != '0';
\r
5154 e->immediate = *(s + 1) != '0';
\r
5158 if (t == NULL) break;
\r
5167 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
5171 hmenu = LoadMenu(hInst, "TextMenu");
\r
5172 h = GetSubMenu(hmenu, 0);
\r
5174 if (strcmp(e->item, "-") == 0) {
\r
5175 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
5177 if (e->item[0] == '|') {
\r
5178 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
5179 IDM_CommandX + i, &e->item[1]);
\r
5181 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
5190 WNDPROC consoleTextWindowProc;
\r
5193 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
5195 char buf[MSG_SIZ], name[MSG_SIZ];
\r
5196 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5200 SetWindowText(hInput, command);
\r
5202 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5204 sel.cpMin = 999999;
\r
5205 sel.cpMax = 999999;
\r
5206 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5211 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5212 if (sel.cpMin == sel.cpMax) {
\r
5213 /* Expand to surrounding word */
\r
5216 tr.chrg.cpMax = sel.cpMin;
\r
5217 tr.chrg.cpMin = --sel.cpMin;
\r
5218 if (sel.cpMin < 0) break;
\r
5219 tr.lpstrText = name;
\r
5220 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5221 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5225 tr.chrg.cpMin = sel.cpMax;
\r
5226 tr.chrg.cpMax = ++sel.cpMax;
\r
5227 tr.lpstrText = name;
\r
5228 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
5229 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5232 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5233 MessageBeep(MB_ICONEXCLAMATION);
\r
5237 tr.lpstrText = name;
\r
5238 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5240 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5241 MessageBeep(MB_ICONEXCLAMATION);
\r
5244 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
5247 sprintf(buf, "%s %s", command, name);
\r
5248 SetWindowText(hInput, buf);
\r
5249 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5251 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
5252 SetWindowText(hInput, buf);
\r
5253 sel.cpMin = 999999;
\r
5254 sel.cpMax = 999999;
\r
5255 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5261 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5266 switch (message) {
\r
5268 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5271 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
5274 sel.cpMin = 999999;
\r
5275 sel.cpMax = 999999;
\r
5276 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5277 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
5282 if (wParam == '\t') {
\r
5283 if (GetKeyState(VK_SHIFT) < 0) {
\r
5285 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5286 if (buttonDesc[0].hwnd) {
\r
5287 SetFocus(buttonDesc[0].hwnd);
\r
5289 SetFocus(hwndMain);
\r
5293 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
5296 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5298 SendMessage(hInput, message, wParam, lParam);
\r
5302 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5304 return SendMessage(hInput, message, wParam, lParam);
\r
5305 case WM_MBUTTONDOWN:
\r
5306 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5307 case WM_RBUTTONDOWN:
\r
5308 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
5309 /* Move selection here if it was empty */
\r
5311 pt.x = LOWORD(lParam);
\r
5312 pt.y = HIWORD(lParam);
\r
5313 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5314 if (sel.cpMin == sel.cpMax) {
\r
5315 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
5316 sel.cpMax = sel.cpMin;
\r
5317 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5319 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
5322 case WM_RBUTTONUP:
\r
5323 if (GetKeyState(VK_SHIFT) & ~1) {
\r
5324 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5325 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5328 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
5329 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5330 if (sel.cpMin == sel.cpMax) {
\r
5331 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
5332 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
5334 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
5335 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
5337 pt.x = LOWORD(lParam);
\r
5338 pt.y = HIWORD(lParam);
\r
5339 MenuPopup(hwnd, pt, hmenu, -1);
\r
5343 switch (LOWORD(wParam)) {
\r
5344 case IDM_QuickPaste:
\r
5346 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5347 if (sel.cpMin == sel.cpMax) {
\r
5348 MessageBeep(MB_ICONEXCLAMATION);
\r
5351 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5352 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5353 SendMessage(hInput, WM_PASTE, 0, 0);
\r
5358 SendMessage(hwnd, WM_CUT, 0, 0);
\r
5361 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
5364 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5368 int i = LOWORD(wParam) - IDM_CommandX;
\r
5369 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
5370 icsTextMenuEntry[i].command != NULL) {
\r
5371 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
5372 icsTextMenuEntry[i].getname,
\r
5373 icsTextMenuEntry[i].immediate);
\r
5381 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
5384 WNDPROC consoleInputWindowProc;
\r
5387 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5389 char buf[MSG_SIZ];
\r
5391 static BOOL sendNextChar = FALSE;
\r
5392 static BOOL quoteNextChar = FALSE;
\r
5393 InputSource *is = consoleInputSource;
\r
5397 switch (message) {
\r
5399 if (!appData.localLineEditing || sendNextChar) {
\r
5400 is->buf[0] = (CHAR) wParam;
\r
5402 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5403 sendNextChar = FALSE;
\r
5406 if (quoteNextChar) {
\r
5407 buf[0] = (char) wParam;
\r
5408 buf[1] = NULLCHAR;
\r
5409 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
5410 quoteNextChar = FALSE;
\r
5414 case '\r': /* Enter key */
\r
5415 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
5416 if (consoleEcho) SaveInHistory(is->buf);
\r
5417 is->buf[is->count++] = '\n';
\r
5418 is->buf[is->count] = NULLCHAR;
\r
5419 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5420 if (consoleEcho) {
\r
5421 ConsoleOutput(is->buf, is->count, TRUE);
\r
5422 } else if (appData.localLineEditing) {
\r
5423 ConsoleOutput("\n", 1, TRUE);
\r
5426 case '\033': /* Escape key */
\r
5427 SetWindowText(hwnd, "");
\r
5428 cf.cbSize = sizeof(CHARFORMAT);
\r
5429 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
5430 if (consoleEcho) {
\r
5431 cf.crTextColor = textAttribs[ColorNormal].color;
\r
5433 cf.crTextColor = COLOR_ECHOOFF;
\r
5435 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
5436 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
5438 case '\t': /* Tab key */
\r
5439 if (GetKeyState(VK_SHIFT) < 0) {
\r
5441 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
5444 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5445 if (buttonDesc[0].hwnd) {
\r
5446 SetFocus(buttonDesc[0].hwnd);
\r
5448 SetFocus(hwndMain);
\r
5452 case '\023': /* Ctrl+S */
\r
5453 sendNextChar = TRUE;
\r
5455 case '\021': /* Ctrl+Q */
\r
5456 quoteNextChar = TRUE;
\r
5465 GetWindowText(hwnd, buf, MSG_SIZ);
\r
5466 p = PrevInHistory(buf);
\r
5468 SetWindowText(hwnd, p);
\r
5469 sel.cpMin = 999999;
\r
5470 sel.cpMax = 999999;
\r
5471 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5476 p = NextInHistory();
\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
5487 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5491 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
5495 case WM_MBUTTONDOWN:
\r
5496 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5497 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5499 case WM_RBUTTONUP:
\r
5500 if (GetKeyState(VK_SHIFT) & ~1) {
\r
5501 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
5502 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5506 hmenu = LoadMenu(hInst, "InputMenu");
\r
5507 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5508 if (sel.cpMin == sel.cpMax) {
\r
5509 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
5510 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
5512 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
5513 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
5515 pt.x = LOWORD(lParam);
\r
5516 pt.y = HIWORD(lParam);
\r
5517 MenuPopup(hwnd, pt, hmenu, -1);
\r
5521 switch (LOWORD(wParam)) {
\r
5523 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
5525 case IDM_SelectAll:
\r
5527 sel.cpMax = -1; /*999999?*/
\r
5528 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5531 SendMessage(hwnd, WM_CUT, 0, 0);
\r
5534 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
5537 SendMessage(hwnd, WM_COPY, 0, 0);
\r
5542 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
5545 #define CO_MAX 100000
\r
5546 #define CO_TRIM 1000
\r
5549 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5551 static HWND hText, hInput, hFocus;
\r
5552 InputSource *is = consoleInputSource;
\r
5554 static int sizeX, sizeY;
\r
5555 int newSizeX, newSizeY;
\r
5558 switch (message) {
\r
5559 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5560 hwndConsole = hDlg;
\r
5561 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
5562 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
5564 consoleTextWindowProc = (WNDPROC)
\r
5565 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
5566 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
5567 consoleInputWindowProc = (WNDPROC)
\r
5568 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
5569 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
5570 Colorize(ColorNormal, TRUE);
\r
5571 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
5572 ChangedConsoleFont();
\r
5573 GetClientRect(hDlg, &rect);
\r
5574 sizeX = rect.right;
\r
5575 sizeY = rect.bottom;
\r
5576 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
5577 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
5578 WINDOWPLACEMENT wp;
\r
5579 EnsureOnScreen(&consoleX, &consoleY);
\r
5580 wp.length = sizeof(WINDOWPLACEMENT);
\r
5582 wp.showCmd = SW_SHOW;
\r
5583 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
5584 wp.rcNormalPosition.left = consoleX;
\r
5585 wp.rcNormalPosition.right = consoleX + consoleW;
\r
5586 wp.rcNormalPosition.top = consoleY;
\r
5587 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
5588 SetWindowPlacement(hDlg, &wp);
\r
5602 if (IsIconic(hDlg)) break;
\r
5603 newSizeX = LOWORD(lParam);
\r
5604 newSizeY = HIWORD(lParam);
\r
5605 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
5606 RECT rectText, rectInput;
\r
5608 int newTextHeight, newTextWidth;
\r
5609 GetWindowRect(hText, &rectText);
\r
5610 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5611 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5612 if (newTextHeight < 0) {
\r
5613 newSizeY += -newTextHeight;
\r
5614 newTextHeight = 0;
\r
5616 SetWindowPos(hText, NULL, 0, 0,
\r
5617 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5618 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
5619 pt.x = rectInput.left;
\r
5620 pt.y = rectInput.top + newSizeY - sizeY;
\r
5621 ScreenToClient(hDlg, &pt);
\r
5622 SetWindowPos(hInput, NULL,
\r
5623 pt.x, pt.y, /* needs client coords */
\r
5624 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
5625 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
5631 case WM_GETMINMAXINFO:
\r
5632 /* Prevent resizing window too small */
\r
5633 mmi = (MINMAXINFO *) lParam;
\r
5634 mmi->ptMinTrackSize.x = 100;
\r
5635 mmi->ptMinTrackSize.y = 100;
\r
5638 return DefWindowProc(hDlg, message, wParam, lParam);
\r
5646 if (hwndConsole) return;
\r
5647 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
5648 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
5653 ConsoleOutput(char* data, int length, int forceVisible)
\r
5658 char buf[CO_MAX+1];
\r
5661 static int delayLF = 0;
\r
5662 CHARRANGE savesel, sel;
\r
5664 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
5672 while (length--) {
\r
5680 } else if (*p == '\007') {
\r
5681 MyPlaySound(&sounds[(int)SoundBell]);
\r
5688 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5689 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
5690 /* Save current selection */
\r
5691 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
5692 exlen = GetWindowTextLength(hText);
\r
5693 /* Find out whether current end of text is visible */
\r
5694 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
5695 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
5696 /* Trim existing text if it's too long */
\r
5697 if (exlen + (q - buf) > CO_MAX) {
\r
5698 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
5701 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5702 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
5704 savesel.cpMin -= trim;
\r
5705 savesel.cpMax -= trim;
\r
5706 if (exlen < 0) exlen = 0;
\r
5707 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
5708 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
5710 /* Append the new text */
\r
5711 sel.cpMin = exlen;
\r
5712 sel.cpMax = exlen;
\r
5713 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5714 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
5715 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
5716 if (forceVisible || exlen == 0 ||
\r
5717 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
5718 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
5719 /* Scroll to make new end of text visible if old end of text
\r
5720 was visible or new text is an echo of user typein */
\r
5721 sel.cpMin = 9999999;
\r
5722 sel.cpMax = 9999999;
\r
5723 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5724 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
5725 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
5726 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
5728 if (savesel.cpMax == exlen || forceVisible) {
\r
5729 /* Move insert point to new end of text if it was at the old
\r
5730 end of text or if the 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
5735 /* Restore previous selection */
\r
5736 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
5738 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
5745 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
5746 RECT *rect, char *color)
\r
5750 COLORREF oldFg, oldBg;
\r
5753 if (appData.clockMode) {
\r
5755 sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));
\r
5757 sprintf(buf, "%s: %s", color, TimeString(timeRemaining));
\r
5764 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
5765 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
5767 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
5768 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
5770 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
5772 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
5773 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
5774 rect, str, strlen(str), NULL);
\r
5776 (void) SetTextColor(hdc, oldFg);
\r
5777 (void) SetBkColor(hdc, oldBg);
\r
5778 (void) SelectObject(hdc, oldFont);
\r
5783 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
5788 ResetEvent(ovl->hEvent);
\r
5789 ovl->Offset = ovl->OffsetHigh = 0;
\r
5790 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
5794 err = GetLastError();
\r
5795 if (err == ERROR_IO_PENDING) {
\r
5796 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
5800 err = GetLastError();
\r
5807 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
5812 ResetEvent(ovl->hEvent);
\r
5813 ovl->Offset = ovl->OffsetHigh = 0;
\r
5814 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
5818 err = GetLastError();
\r
5819 if (err == ERROR_IO_PENDING) {
\r
5820 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
5824 err = GetLastError();
\r
5832 InputThread(LPVOID arg)
\r
5837 is = (InputSource *) arg;
\r
5838 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
5839 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
5840 while (is->hThread != NULL) {
\r
5841 is->error = DoReadFile(is->hFile, is->next,
\r
5842 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
5843 &is->count, &ovl);
\r
5844 if (is->error == NO_ERROR) {
\r
5845 is->next += is->count;
\r
5847 if (is->error == ERROR_BROKEN_PIPE) {
\r
5848 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
5851 is->count = (DWORD) -1;
\r
5854 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5855 if (is->count <= 0) break; /* Quit on EOF or error */
\r
5857 CloseHandle(ovl.hEvent);
\r
5858 CloseHandle(is->hFile);
\r
5863 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
5865 NonOvlInputThread(LPVOID arg)
\r
5872 is = (InputSource *) arg;
\r
5873 while (is->hThread != NULL) {
\r
5874 is->error = ReadFile(is->hFile, is->next,
\r
5875 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
5876 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
5877 if (is->error == NO_ERROR) {
\r
5878 /* Change CRLF to LF */
\r
5879 if (is->next > is->buf) {
\r
5881 i = is->count + 1;
\r
5889 if (prev == '\r' && *p == '\n') {
\r
5901 if (is->error == ERROR_BROKEN_PIPE) {
\r
5902 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
5905 is->count = (DWORD) -1;
\r
5908 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5909 if (is->count < 0) break; /* Quit on error */
\r
5911 CloseHandle(is->hFile);
\r
5916 SocketInputThread(LPVOID arg)
\r
5920 is = (InputSource *) arg;
\r
5921 while (is->hThread != NULL) {
\r
5922 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
5923 if ((int)is->count == SOCKET_ERROR) {
\r
5924 is->count = (DWORD) -1;
\r
5925 is->error = WSAGetLastError();
\r
5927 is->error = NO_ERROR;
\r
5928 is->next += is->count;
\r
5929 if (is->count == 0 && is->second == is) {
\r
5930 /* End of file on stderr; quit with no message */
\r
5934 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
5935 if (is->count <= 0) break; /* Quit on EOF or error */
\r
5941 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5945 is = (InputSource *) lParam;
\r
5946 if (is->lineByLine) {
\r
5947 /* Feed in lines one by one */
\r
5948 char *p = is->buf;
\r
5950 while (q < is->next) {
\r
5951 if (*q++ == '\n') {
\r
5952 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
5956 /* Move any partial line to the start of the buffer */
\r
5958 while (p < is->next) {
\r
5962 if (is->error != NO_ERROR || is->count == 0) {
\r
5963 /* Notify backend of the error. Note: If there was a partial
\r
5964 line at the end, it is not flushed through. */
\r
5965 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
5968 /* Feed in the whole chunk of input at once */
\r
5969 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
5970 is->next = is->buf;
\r
5974 /*---------------------------------------------------------------------------*\
\r
5976 * Menu enables. Used when setting various modes.
\r
5978 \*---------------------------------------------------------------------------*/
\r
5986 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
5988 while (enab->item > 0) {
\r
5989 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
5994 Enables gnuEnables[] = {
\r
5995 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
5996 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
5997 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
5998 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
5999 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
6000 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
6001 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6002 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
6003 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
6004 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
6008 Enables icsEnables[] = {
\r
6009 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6010 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6011 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6012 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6013 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6014 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
6015 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
6016 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
6017 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6018 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
6019 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
6020 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
6025 Enables zippyEnables[] = {
\r
6026 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6027 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
6028 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
6033 Enables ncpEnables[] = {
\r
6034 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6035 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6036 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6037 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6038 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6039 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
6040 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
6041 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
6042 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
6043 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
6044 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6045 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6046 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
6047 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
6048 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
6052 Enables trainingOnEnables[] = {
\r
6053 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
6054 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
6055 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
6056 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
6057 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
6058 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
6059 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6060 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
6064 Enables trainingOffEnables[] = {
\r
6065 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
6066 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
6067 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
6068 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
6069 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
6070 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
6071 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6072 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
6076 /* These modify either ncpEnables or gnuEnables */
\r
6077 Enables cmailEnables[] = {
\r
6078 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
6079 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
6080 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
6081 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
6082 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
6083 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6084 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
6088 Enables machineThinkingEnables[] = {
\r
6089 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6090 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
6091 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
6092 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6093 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
6094 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6095 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6096 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6097 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6098 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
6099 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6100 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6101 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6102 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
6103 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6107 Enables userThinkingEnables[] = {
\r
6108 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6109 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
6110 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
6111 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6112 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
6113 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6114 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6115 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6116 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6117 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
6118 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
6119 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
6120 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
6121 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
6122 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
6126 /*---------------------------------------------------------------------------*\
\r
6128 * Front-end interface functions exported by XBoard.
\r
6129 * Functions appear in same order as prototypes in frontend.h.
\r
6131 \*---------------------------------------------------------------------------*/
\r
6135 static UINT prevChecked = 0;
\r
6136 static int prevPausing = 0;
\r
6139 if (pausing != prevPausing) {
\r
6140 prevPausing = pausing;
\r
6141 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
6142 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
6143 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
6146 switch (gameMode) {
\r
6147 case BeginningOfGame:
\r
6148 if (appData.icsActive)
\r
6149 nowChecked = IDM_IcsClient;
\r
6150 else if (appData.noChessProgram)
\r
6151 nowChecked = IDM_EditGame;
\r
6153 nowChecked = IDM_MachineBlack;
\r
6155 case MachinePlaysBlack:
\r
6156 nowChecked = IDM_MachineBlack;
\r
6158 case MachinePlaysWhite:
\r
6159 nowChecked = IDM_MachineWhite;
\r
6161 case TwoMachinesPlay:
\r
6162 nowChecked = IDM_TwoMachines;
\r
6165 nowChecked = IDM_AnalysisMode;
\r
6168 nowChecked = IDM_AnalyzeFile;
\r
6171 nowChecked = IDM_EditGame;
\r
6173 case PlayFromGameFile:
\r
6174 nowChecked = IDM_LoadGame;
\r
6176 case EditPosition:
\r
6177 nowChecked = IDM_EditPosition;
\r
6180 nowChecked = IDM_Training;
\r
6182 case IcsPlayingWhite:
\r
6183 case IcsPlayingBlack:
\r
6184 case IcsObserving:
\r
6186 nowChecked = IDM_IcsClient;
\r
6193 if (prevChecked != 0)
\r
6194 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6195 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
6196 if (nowChecked != 0)
\r
6197 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6198 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
6200 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
6201 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
6202 MF_BYCOMMAND|MF_ENABLED);
\r
6204 (void) EnableMenuItem(GetMenu(hwndMain),
\r
6205 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
6208 prevChecked = nowChecked;
\r
6214 HMENU hmenu = GetMenu(hwndMain);
\r
6215 SetMenuEnables(hmenu, icsEnables);
\r
6216 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
6217 MF_BYPOSITION|MF_ENABLED);
\r
6219 if (appData.zippyPlay) {
\r
6220 SetMenuEnables(hmenu, zippyEnables);
\r
6228 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
6234 HMENU hmenu = GetMenu(hwndMain);
\r
6235 SetMenuEnables(hmenu, ncpEnables);
\r
6236 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
6237 MF_BYPOSITION|MF_GRAYED);
\r
6238 DrawMenuBar(hwndMain);
\r
6244 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
6248 SetTrainingModeOn()
\r
6251 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
6252 for (i = 0; i < N_BUTTONS; i++) {
\r
6253 if (buttonDesc[i].hwnd != NULL)
\r
6254 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
6259 VOID SetTrainingModeOff()
\r
6262 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
6263 for (i = 0; i < N_BUTTONS; i++) {
\r
6264 if (buttonDesc[i].hwnd != NULL)
\r
6265 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
6271 SetUserThinkingEnables()
\r
6273 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
6277 SetMachineThinkingEnables()
\r
6279 HMENU hMenu = GetMenu(hwndMain);
\r
6280 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
6282 SetMenuEnables(hMenu, machineThinkingEnables);
\r
6284 if (gameMode == MachinePlaysBlack) {
\r
6285 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
6286 } else if (gameMode == MachinePlaysWhite) {
\r
6287 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
6288 } else if (gameMode == TwoMachinesPlay) {
\r
6289 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
6295 DisplayTitle(char *str)
\r
6297 char title[MSG_SIZ], *host;
\r
6298 if (str[0] != NULLCHAR) {
\r
6299 strcpy(title, str);
\r
6300 } else if (appData.icsActive) {
\r
6301 if (appData.icsCommPort[0] != NULLCHAR)
\r
6304 host = appData.icsHost;
\r
6305 sprintf(title, "%s: %s", szTitle, host);
\r
6306 } else if (appData.noChessProgram) {
\r
6307 strcpy(title, szTitle);
\r
6309 strcpy(title, szTitle);
\r
6310 strcat(title, ": ");
\r
6311 strcat(title, first.tidy);
\r
6313 SetWindowText(hwndMain, title);
\r
6318 DisplayMessage(char *str1, char *str2)
\r
6322 int remain = MESSAGE_TEXT_MAX - 1;
\r
6325 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
6326 messageText[0] = NULLCHAR;
\r
6328 len = strlen(str1);
\r
6329 if (len > remain) len = remain;
\r
6330 strncpy(messageText, str1, len);
\r
6331 messageText[len] = NULLCHAR;
\r
6334 if (*str2 && remain >= 2) {
\r
6336 strcat(messageText, " ");
\r
6339 len = strlen(str2);
\r
6340 if (len > remain) len = remain;
\r
6341 strncat(messageText, str2, len);
\r
6343 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
6345 if (IsIconic(hwndMain)) return;
\r
6346 hdc = GetDC(hwndMain);
\r
6347 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
6348 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
6349 &messageRect, messageText, strlen(messageText), NULL);
\r
6350 (void) SelectObject(hdc, oldFont);
\r
6351 (void) ReleaseDC(hwndMain, hdc);
\r
6355 DisplayError(char *str, int error)
\r
6358 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
6365 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
6366 NULL, error, LANG_NEUTRAL,
\r
6367 (LPSTR) buf2, MSG_SIZ, NULL);
\r
6369 sprintf(buf, "%s:\n%s", str, buf2);
\r
6371 ErrorMap *em = errmap;
\r
6372 while (em->err != 0 && em->err != error) em++;
\r
6373 if (em->err != 0) {
\r
6374 sprintf(buf, "%s:\n%s", str, em->msg);
\r
6376 sprintf(buf, "%s:\nError code %d", str, error);
\r
6381 ErrorPopUp("Error", buf);
\r
6386 DisplayMoveError(char *str)
\r
6388 fromX = fromY = -1;
\r
6389 ClearHighlights();
\r
6390 DrawPosition(FALSE, NULL);
\r
6391 if (appData.popupMoveErrors) {
\r
6392 ErrorPopUp("Error", str);
\r
6394 DisplayMessage(str, "");
\r
6395 moveErrorMessageUp = TRUE;
\r
6400 DisplayFatalError(char *str, int error, int exitStatus)
\r
6402 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
6404 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
6407 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
6408 NULL, error, LANG_NEUTRAL,
\r
6409 (LPSTR) buf2, MSG_SIZ, NULL);
\r
6411 sprintf(buf, "%s:\n%s", str, buf2);
\r
6413 ErrorMap *em = errmap;
\r
6414 while (em->err != 0 && em->err != error) em++;
\r
6415 if (em->err != 0) {
\r
6416 sprintf(buf, "%s:\n%s", str, em->msg);
\r
6418 sprintf(buf, "%s:\nError code %d", str, error);
\r
6423 if (appData.debugMode) {
\r
6424 fprintf(debugFP, "%s: %s\n", label, str);
\r
6426 if (appData.popupExitMessage) {
\r
6427 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
6428 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
6430 ExitEvent(exitStatus);
\r
6435 DisplayInformation(char *str)
\r
6437 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
6442 DisplayNote(char *str)
\r
6444 ErrorPopUp("Note", str);
\r
6449 char *title, *question, *replyPrefix;
\r
6454 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6456 static QuestionParams *qp;
\r
6457 char reply[MSG_SIZ];
\r
6460 switch (message) {
\r
6461 case WM_INITDIALOG:
\r
6462 qp = (QuestionParams *) lParam;
\r
6463 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
6464 SetWindowText(hDlg, qp->title);
\r
6465 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
6466 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
6470 switch (LOWORD(wParam)) {
\r
6472 strcpy(reply, qp->replyPrefix);
\r
6473 if (*reply) strcat(reply, " ");
\r
6474 len = strlen(reply);
\r
6475 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
6476 strcat(reply, "\n");
\r
6477 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
6478 EndDialog(hDlg, TRUE);
\r
6479 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
6482 EndDialog(hDlg, FALSE);
\r
6493 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
6495 QuestionParams qp;
\r
6499 qp.question = question;
\r
6500 qp.replyPrefix = replyPrefix;
\r
6502 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
6503 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
6504 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
6505 FreeProcInstance(lpProc);
\r
6510 DisplayIcsInteractionTitle(char *str)
\r
6512 char consoleTitle[MSG_SIZ];
\r
6514 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
6515 SetWindowText(hwndConsole, consoleTitle);
\r
6519 DrawPosition(int fullRedraw, Board board)
\r
6521 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
6528 fromX = fromY = -1;
\r
6529 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
6530 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
6531 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
6532 dragInfo.lastpos = dragInfo.pos;
\r
6533 dragInfo.start.x = dragInfo.start.y = -1;
\r
6534 dragInfo.from = dragInfo.start;
\r
6536 DrawPosition(TRUE, NULL);
\r
6542 CommentPopUp(char *title, char *str)
\r
6544 HWND hwnd = GetActiveWindow();
\r
6545 EitherCommentPopUp(0, title, str, FALSE);
\r
6546 SetActiveWindow(hwnd);
\r
6550 CommentPopDown(void)
\r
6552 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
6553 if (commentDialog) {
\r
6554 ShowWindow(commentDialog, SW_HIDE);
\r
6556 commentDialogUp = FALSE;
\r
6560 EditCommentPopUp(int index, char *title, char *str)
\r
6562 EitherCommentPopUp(index, title, str, TRUE);
\r
6569 MyPlaySound(&sounds[(int)SoundMove]);
\r
6572 VOID PlayIcsWinSound()
\r
6574 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
6577 VOID PlayIcsLossSound()
\r
6579 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
6582 VOID PlayIcsDrawSound()
\r
6584 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
6587 VOID PlayIcsUnfinishedSound()
\r
6589 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
6595 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
6603 consoleEcho = TRUE;
\r
6604 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6605 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
6606 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6615 consoleEcho = FALSE;
\r
6616 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6617 /* This works OK: set text and background both to the same color */
\r
6619 cf.crTextColor = COLOR_ECHOOFF;
\r
6620 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6621 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
6624 /* No Raw()...? */
\r
6626 void Colorize(ColorClass cc, int continuation)
\r
6628 currentColorClass = cc;
\r
6629 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6630 consoleCF.crTextColor = textAttribs[cc].color;
\r
6631 consoleCF.dwEffects = textAttribs[cc].effects;
\r
6632 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
6638 static char buf[MSG_SIZ];
\r
6639 DWORD bufsiz = MSG_SIZ;
\r
6641 if (!GetUserName(buf, &bufsiz)) {
\r
6642 /*DisplayError("Error getting user name", GetLastError());*/
\r
6643 strcpy(buf, "User");
\r
6651 static char buf[MSG_SIZ];
\r
6652 DWORD bufsiz = MSG_SIZ;
\r
6654 if (!GetComputerName(buf, &bufsiz)) {
\r
6655 /*DisplayError("Error getting host name", GetLastError());*/
\r
6656 strcpy(buf, "Unknown");
\r
6663 ClockTimerRunning()
\r
6665 return clockTimerEvent != 0;
\r
6671 if (clockTimerEvent == 0) return FALSE;
\r
6672 KillTimer(hwndMain, clockTimerEvent);
\r
6673 clockTimerEvent = 0;
\r
6678 StartClockTimer(long millisec)
\r
6680 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
6681 (UINT) millisec, NULL);
\r
6685 DisplayWhiteClock(long timeRemaining, int highlight)
\r
6688 hdc = GetDC(hwndMain);
\r
6689 if (!IsIconic(hwndMain)) {
\r
6690 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");
\r
6692 if (highlight && iconCurrent == iconBlack) {
\r
6693 iconCurrent = iconWhite;
\r
6694 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6695 if (IsIconic(hwndMain)) {
\r
6696 DrawIcon(hdc, 2, 2, iconCurrent);
\r
6699 (void) ReleaseDC(hwndMain, hdc);
\r
6701 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6705 DisplayBlackClock(long timeRemaining, int highlight)
\r
6708 hdc = GetDC(hwndMain);
\r
6709 if (!IsIconic(hwndMain)) {
\r
6710 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");
\r
6712 if (highlight && iconCurrent == iconWhite) {
\r
6713 iconCurrent = iconBlack;
\r
6714 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6715 if (IsIconic(hwndMain)) {
\r
6716 DrawIcon(hdc, 2, 2, iconCurrent);
\r
6719 (void) ReleaseDC(hwndMain, hdc);
\r
6721 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
6726 LoadGameTimerRunning()
\r
6728 return loadGameTimerEvent != 0;
\r
6732 StopLoadGameTimer()
\r
6734 if (loadGameTimerEvent == 0) return FALSE;
\r
6735 KillTimer(hwndMain, loadGameTimerEvent);
\r
6736 loadGameTimerEvent = 0;
\r
6741 StartLoadGameTimer(long millisec)
\r
6743 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
6744 (UINT) millisec, NULL);
\r
6752 char fileTitle[MSG_SIZ];
\r
6754 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
6755 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
6756 appData.oldSaveStyle ? "gam" : "pgn",
\r
6758 "Save Game to File", NULL, fileTitle, NULL);
\r
6760 SaveGame(f, 0, "");
\r
6767 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
6769 if (delayedTimerEvent != 0) {
\r
6770 if (appData.debugMode) {
\r
6771 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
6773 KillTimer(hwndMain, delayedTimerEvent);
\r
6774 delayedTimerEvent = 0;
\r
6775 delayedTimerCallback();
\r
6777 delayedTimerCallback = cb;
\r
6778 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
6779 (UINT) millisec, NULL);
\r
6782 DelayedEventCallback
\r
6785 if (delayedTimerEvent) {
\r
6786 return delayedTimerCallback;
\r
6793 CancelDelayedEvent()
\r
6795 if (delayedTimerEvent) {
\r
6796 KillTimer(hwndMain, delayedTimerEvent);
\r
6797 delayedTimerEvent = 0;
\r
6801 /* Start a child process running the given program.
\r
6802 The process's standard output can be read from "from", and its
\r
6803 standard input can be written to "to".
\r
6804 Exit with fatal error if anything goes wrong.
\r
6805 Returns an opaque pointer that can be used to destroy the process
\r
6809 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
6811 #define BUFSIZE 4096
\r
6813 HANDLE hChildStdinRd, hChildStdinWr,
\r
6814 hChildStdoutRd, hChildStdoutWr;
\r
6815 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
6816 SECURITY_ATTRIBUTES saAttr;
\r
6818 PROCESS_INFORMATION piProcInfo;
\r
6819 STARTUPINFO siStartInfo;
\r
6821 char buf[MSG_SIZ];
\r
6824 if (appData.debugMode) {
\r
6825 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
6830 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
6831 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
6832 saAttr.bInheritHandle = TRUE;
\r
6833 saAttr.lpSecurityDescriptor = NULL;
\r
6836 * The steps for redirecting child's STDOUT:
\r
6837 * 1. Create anonymous pipe to be STDOUT for child.
\r
6838 * 2. Create a noninheritable duplicate of read handle,
\r
6839 * and close the inheritable read handle.
\r
6842 /* Create a pipe for the child's STDOUT. */
\r
6843 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
6844 return GetLastError();
\r
6847 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
6848 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
6849 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
6850 FALSE, /* not inherited */
\r
6851 DUPLICATE_SAME_ACCESS);
\r
6853 return GetLastError();
\r
6855 CloseHandle(hChildStdoutRd);
\r
6858 * The steps for redirecting child's STDIN:
\r
6859 * 1. Create anonymous pipe to be STDIN for child.
\r
6860 * 2. Create a noninheritable duplicate of write handle,
\r
6861 * and close the inheritable write handle.
\r
6864 /* Create a pipe for the child's STDIN. */
\r
6865 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
6866 return GetLastError();
\r
6869 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
6870 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
6871 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
6872 FALSE, /* not inherited */
\r
6873 DUPLICATE_SAME_ACCESS);
\r
6875 return GetLastError();
\r
6877 CloseHandle(hChildStdinWr);
\r
6879 /* Arrange to (1) look in dir for the child .exe file, and
\r
6880 * (2) have dir be the child's working directory. Interpret
\r
6881 * dir relative to the directory WinBoard loaded from. */
\r
6882 GetCurrentDirectory(MSG_SIZ, buf);
\r
6883 SetCurrentDirectory(installDir);
\r
6884 SetCurrentDirectory(dir);
\r
6886 /* Now create the child process. */
\r
6888 siStartInfo.cb = sizeof(STARTUPINFO);
\r
6889 siStartInfo.lpReserved = NULL;
\r
6890 siStartInfo.lpDesktop = NULL;
\r
6891 siStartInfo.lpTitle = NULL;
\r
6892 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
6893 siStartInfo.cbReserved2 = 0;
\r
6894 siStartInfo.lpReserved2 = NULL;
\r
6895 siStartInfo.hStdInput = hChildStdinRd;
\r
6896 siStartInfo.hStdOutput = hChildStdoutWr;
\r
6897 siStartInfo.hStdError = hChildStdoutWr;
\r
6899 fSuccess = CreateProcess(NULL,
\r
6900 cmdLine, /* command line */
\r
6901 NULL, /* process security attributes */
\r
6902 NULL, /* primary thread security attrs */
\r
6903 TRUE, /* handles are inherited */
\r
6904 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
6905 NULL, /* use parent's environment */
\r
6907 &siStartInfo, /* STARTUPINFO pointer */
\r
6908 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
6910 err = GetLastError();
\r
6911 SetCurrentDirectory(buf); /* return to prev directory */
\r
6916 /* Close the handles we don't need in the parent */
\r
6917 CloseHandle(piProcInfo.hThread);
\r
6918 CloseHandle(hChildStdinRd);
\r
6919 CloseHandle(hChildStdoutWr);
\r
6921 /* Prepare return value */
\r
6922 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
6923 cp->kind = CPReal;
\r
6924 cp->hProcess = piProcInfo.hProcess;
\r
6925 cp->pid = piProcInfo.dwProcessId;
\r
6926 cp->hFrom = hChildStdoutRdDup;
\r
6927 cp->hTo = hChildStdinWrDup;
\r
6929 *pr = (void *) cp;
\r
6931 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
6932 2000 where engines sometimes don't see the initial command(s)
\r
6933 from WinBoard and hang. I don't understand how that can happen,
\r
6934 but the Sleep is harmless, so I've put it in. Others have also
\r
6935 reported what may be the same problem, so hopefully this will fix
\r
6936 it for them too. */
\r
6944 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
6948 cp = (ChildProc *) pr;
\r
6949 if (cp == NULL) return;
\r
6951 switch (cp->kind) {
\r
6953 /* TerminateProcess is considered harmful, so... */
\r
6954 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
6955 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
6956 /* The following doesn't work because the chess program
\r
6957 doesn't "have the same console" as WinBoard. Maybe
\r
6958 we could arrange for this even though neither WinBoard
\r
6959 nor the chess program uses a console for stdio? */
\r
6960 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
6961 CloseHandle(cp->hProcess);
\r
6965 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
6969 closesocket(cp->sock);
\r
6974 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
6975 closesocket(cp->sock);
\r
6976 closesocket(cp->sock2);
\r
6984 InterruptChildProcess(ProcRef pr)
\r
6988 cp = (ChildProc *) pr;
\r
6989 if (cp == NULL) return;
\r
6990 switch (cp->kind) {
\r
6992 /* The following doesn't work because the chess program
\r
6993 doesn't "have the same console" as WinBoard. Maybe
\r
6994 we could arrange for this even though neither WinBoard
\r
6995 nor the chess program uses a console for stdio */
\r
6996 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
7001 /* Can't interrupt */
\r
7005 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
7012 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
7014 char cmdLine[MSG_SIZ];
\r
7016 if (port[0] == NULLCHAR) {
\r
7017 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
7019 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
7021 return StartChildProcess(cmdLine, "", pr);
\r
7025 /* Code to open TCP sockets */
\r
7028 OpenTCP(char *host, char *port, ProcRef *pr)
\r
7033 struct sockaddr_in sa, mysa;
\r
7034 struct hostent FAR *hp;
\r
7035 unsigned short uport;
\r
7036 WORD wVersionRequested;
\r
7039 /* Initialize socket DLL */
\r
7040 wVersionRequested = MAKEWORD(1, 1);
\r
7041 err = WSAStartup(wVersionRequested, &wsaData);
\r
7042 if (err != 0) return err;
\r
7045 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7046 err = WSAGetLastError();
\r
7051 /* Bind local address using (mostly) don't-care values.
\r
7053 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7054 mysa.sin_family = AF_INET;
\r
7055 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7056 uport = (unsigned short) 0;
\r
7057 mysa.sin_port = htons(uport);
\r
7058 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7059 == SOCKET_ERROR) {
\r
7060 err = WSAGetLastError();
\r
7065 /* Resolve remote host name */
\r
7066 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7067 if (!(hp = gethostbyname(host))) {
\r
7068 unsigned int b0, b1, b2, b3;
\r
7070 err = WSAGetLastError();
\r
7072 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7073 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7074 hp->h_addrtype = AF_INET;
\r
7076 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7077 hp->h_addr_list[0] = (char *) malloc(4);
\r
7078 hp->h_addr_list[0][0] = (char) b0;
\r
7079 hp->h_addr_list[0][1] = (char) b1;
\r
7080 hp->h_addr_list[0][2] = (char) b2;
\r
7081 hp->h_addr_list[0][3] = (char) b3;
\r
7087 sa.sin_family = hp->h_addrtype;
\r
7088 uport = (unsigned short) atoi(port);
\r
7089 sa.sin_port = htons(uport);
\r
7090 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7092 /* Make connection */
\r
7093 if (connect(s, (struct sockaddr *) &sa,
\r
7094 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7095 err = WSAGetLastError();
\r
7100 /* Prepare return value */
\r
7101 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7102 cp->kind = CPSock;
\r
7104 *pr = (ProcRef *) cp;
\r
7110 OpenCommPort(char *name, ProcRef *pr)
\r
7115 char fullname[MSG_SIZ];
\r
7117 if (*name != '\\')
\r
7118 sprintf(fullname, "\\\\.\\%s", name);
\r
7120 strcpy(fullname, name);
\r
7122 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
7123 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
7124 if (h == (HANDLE) -1) {
\r
7125 return GetLastError();
\r
7129 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
7131 /* Accumulate characters until a 100ms pause, then parse */
\r
7132 ct.ReadIntervalTimeout = 100;
\r
7133 ct.ReadTotalTimeoutMultiplier = 0;
\r
7134 ct.ReadTotalTimeoutConstant = 0;
\r
7135 ct.WriteTotalTimeoutMultiplier = 0;
\r
7136 ct.WriteTotalTimeoutConstant = 0;
\r
7137 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
7139 /* Prepare return value */
\r
7140 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7141 cp->kind = CPComm;
\r
7144 *pr = (ProcRef *) cp;
\r
7150 OpenLoopback(ProcRef *pr)
\r
7152 DisplayFatalError("Not implemented", 0, 1);
\r
7158 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
7163 struct sockaddr_in sa, mysa;
\r
7164 struct hostent FAR *hp;
\r
7165 unsigned short uport;
\r
7166 WORD wVersionRequested;
\r
7169 char stderrPortStr[MSG_SIZ];
\r
7171 /* Initialize socket DLL */
\r
7172 wVersionRequested = MAKEWORD(1, 1);
\r
7173 err = WSAStartup(wVersionRequested, &wsaData);
\r
7174 if (err != 0) return err;
\r
7176 /* Resolve remote host name */
\r
7177 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7178 if (!(hp = gethostbyname(host))) {
\r
7179 unsigned int b0, b1, b2, b3;
\r
7181 err = WSAGetLastError();
\r
7183 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7184 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7185 hp->h_addrtype = AF_INET;
\r
7187 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7188 hp->h_addr_list[0] = (char *) malloc(4);
\r
7189 hp->h_addr_list[0][0] = (char) b0;
\r
7190 hp->h_addr_list[0][1] = (char) b1;
\r
7191 hp->h_addr_list[0][2] = (char) b2;
\r
7192 hp->h_addr_list[0][3] = (char) b3;
\r
7198 sa.sin_family = hp->h_addrtype;
\r
7199 uport = (unsigned short) 514;
\r
7200 sa.sin_port = htons(uport);
\r
7201 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7203 /* Bind local socket to unused "privileged" port address
\r
7205 s = INVALID_SOCKET;
\r
7206 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7207 mysa.sin_family = AF_INET;
\r
7208 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7209 for (fromPort = 1023;; fromPort--) {
\r
7210 if (fromPort < 0) {
\r
7212 return WSAEADDRINUSE;
\r
7214 if (s == INVALID_SOCKET) {
\r
7215 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7216 err = WSAGetLastError();
\r
7221 uport = (unsigned short) fromPort;
\r
7222 mysa.sin_port = htons(uport);
\r
7223 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7224 == SOCKET_ERROR) {
\r
7225 err = WSAGetLastError();
\r
7226 if (err == WSAEADDRINUSE) continue;
\r
7230 if (connect(s, (struct sockaddr *) &sa,
\r
7231 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7232 err = WSAGetLastError();
\r
7233 if (err == WSAEADDRINUSE) {
\r
7244 /* Bind stderr local socket to unused "privileged" port address
\r
7246 s2 = INVALID_SOCKET;
\r
7247 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7248 mysa.sin_family = AF_INET;
\r
7249 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7250 for (fromPort = 1023;; fromPort--) {
\r
7251 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
7252 if (fromPort < 0) {
\r
7253 (void) closesocket(s);
\r
7255 return WSAEADDRINUSE;
\r
7257 if (s2 == INVALID_SOCKET) {
\r
7258 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7259 err = WSAGetLastError();
\r
7265 uport = (unsigned short) fromPort;
\r
7266 mysa.sin_port = htons(uport);
\r
7267 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7268 == SOCKET_ERROR) {
\r
7269 err = WSAGetLastError();
\r
7270 if (err == WSAEADDRINUSE) continue;
\r
7271 (void) closesocket(s);
\r
7275 if (listen(s2, 1) == SOCKET_ERROR) {
\r
7276 err = WSAGetLastError();
\r
7277 if (err == WSAEADDRINUSE) {
\r
7279 s2 = INVALID_SOCKET;
\r
7282 (void) closesocket(s);
\r
7283 (void) closesocket(s2);
\r
7289 prevStderrPort = fromPort; // remember port used
\r
7290 sprintf(stderrPortStr, "%d", fromPort);
\r
7292 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
7293 err = WSAGetLastError();
\r
7294 (void) closesocket(s);
\r
7295 (void) closesocket(s2);
\r
7300 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
7301 err = WSAGetLastError();
\r
7302 (void) closesocket(s);
\r
7303 (void) closesocket(s2);
\r
7307 if (*user == NULLCHAR) user = UserName();
\r
7308 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
7309 err = WSAGetLastError();
\r
7310 (void) closesocket(s);
\r
7311 (void) closesocket(s2);
\r
7315 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
7316 err = WSAGetLastError();
\r
7317 (void) closesocket(s);
\r
7318 (void) closesocket(s2);
\r
7323 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
7324 err = WSAGetLastError();
\r
7325 (void) closesocket(s);
\r
7326 (void) closesocket(s2);
\r
7330 (void) closesocket(s2); /* Stop listening */
\r
7332 /* Prepare return value */
\r
7333 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7334 cp->kind = CPRcmd;
\r
7337 *pr = (ProcRef *) cp;
\r
7344 AddInputSource(ProcRef pr, int lineByLine,
\r
7345 InputCallback func, VOIDSTAR closure)
\r
7347 InputSource *is, *is2;
\r
7348 ChildProc *cp = (ChildProc *) pr;
\r
7350 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
7351 is->lineByLine = lineByLine;
\r
7353 is->closure = closure;
\r
7354 is->second = NULL;
\r
7355 is->next = is->buf;
\r
7356 if (pr == NoProc) {
\r
7357 is->kind = CPReal;
\r
7358 consoleInputSource = is;
\r
7360 is->kind = cp->kind;
\r
7361 switch (cp->kind) {
\r
7363 is->hFile = cp->hFrom;
\r
7364 cp->hFrom = NULL; /* now owned by InputThread */
\r
7366 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
7367 (LPVOID) is, 0, &is->id);
\r
7371 is->hFile = cp->hFrom;
\r
7372 cp->hFrom = NULL; /* now owned by InputThread */
\r
7374 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
7375 (LPVOID) is, 0, &is->id);
\r
7379 is->sock = cp->sock;
\r
7381 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7382 (LPVOID) is, 0, &is->id);
\r
7386 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
7388 is->sock = cp->sock;
\r
7390 is2->sock = cp->sock2;
\r
7391 is2->second = is2;
\r
7393 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7394 (LPVOID) is, 0, &is->id);
\r
7396 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
7397 (LPVOID) is2, 0, &is2->id);
\r
7401 return (InputSourceRef) is;
\r
7405 RemoveInputSource(InputSourceRef isr)
\r
7409 is = (InputSource *) isr;
\r
7410 is->hThread = NULL; /* tell thread to stop */
\r
7411 CloseHandle(is->hThread);
\r
7412 if (is->second != NULL) {
\r
7413 is->second->hThread = NULL;
\r
7414 CloseHandle(is->second->hThread);
\r
7420 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
7423 int outCount = SOCKET_ERROR;
\r
7424 ChildProc *cp = (ChildProc *) pr;
\r
7425 static OVERLAPPED ovl;
\r
7427 if (pr == NoProc) {
\r
7428 ConsoleOutput(message, count, FALSE);
\r
7432 if (ovl.hEvent == NULL) {
\r
7433 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7435 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7437 switch (cp->kind) {
\r
7440 outCount = send(cp->sock, message, count, 0);
\r
7441 if (outCount == SOCKET_ERROR) {
\r
7442 *outError = WSAGetLastError();
\r
7444 *outError = NO_ERROR;
\r
7449 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
7450 &dOutCount, NULL)) {
\r
7451 *outError = NO_ERROR;
\r
7452 outCount = (int) dOutCount;
\r
7454 *outError = GetLastError();
\r
7459 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
7460 &dOutCount, &ovl);
\r
7461 if (*outError == NO_ERROR) {
\r
7462 outCount = (int) dOutCount;
\r
7470 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
7473 /* Ignore delay, not implemented for WinBoard */
\r
7474 return OutputToProcess(pr, message, count, outError);
\r
7479 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
7480 char *buf, int count, int error)
\r
7482 DisplayFatalError("Not implemented", 0, 1);
\r
7485 /* see wgamelist.c for Game List functions */
\r
7486 /* see wedittags.c for Edit Tags functions */
\r
7493 char buf[MSG_SIZ];
\r
7496 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
7497 f = fopen(buf, "r");
\r
7499 ProcessICSInitScript(f);
\r
7507 StartAnalysisClock()
\r
7509 if (analysisTimerEvent) return;
\r
7510 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
7511 (UINT) 2000, NULL);
\r
7515 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7517 static HANDLE hwndText;
\r
7519 static int sizeX, sizeY;
\r
7520 int newSizeX, newSizeY, flags;
\r
7523 switch (message) {
\r
7524 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7525 /* Initialize the dialog items */
\r
7526 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
7527 SetWindowText(hDlg, analysisTitle);
\r
7528 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
7529 /* Size and position the dialog */
\r
7530 if (!analysisDialog) {
\r
7531 analysisDialog = hDlg;
\r
7532 flags = SWP_NOZORDER;
\r
7533 GetClientRect(hDlg, &rect);
\r
7534 sizeX = rect.right;
\r
7535 sizeY = rect.bottom;
\r
7536 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
7537 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
7538 WINDOWPLACEMENT wp;
\r
7539 EnsureOnScreen(&analysisX, &analysisY);
\r
7540 wp.length = sizeof(WINDOWPLACEMENT);
\r
7542 wp.showCmd = SW_SHOW;
\r
7543 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7544 wp.rcNormalPosition.left = analysisX;
\r
7545 wp.rcNormalPosition.right = analysisX + analysisW;
\r
7546 wp.rcNormalPosition.top = analysisY;
\r
7547 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
7548 SetWindowPlacement(hDlg, &wp);
\r
7550 GetClientRect(hDlg, &rect);
\r
7551 newSizeX = rect.right;
\r
7552 newSizeY = rect.bottom;
\r
7553 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7554 newSizeX, newSizeY);
\r
7561 case WM_COMMAND: /* message: received a command */
\r
7562 switch (LOWORD(wParam)) {
\r
7572 newSizeX = LOWORD(lParam);
\r
7573 newSizeY = HIWORD(lParam);
\r
7574 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7579 case WM_GETMINMAXINFO:
\r
7580 /* Prevent resizing window too small */
\r
7581 mmi = (MINMAXINFO *) lParam;
\r
7582 mmi->ptMinTrackSize.x = 100;
\r
7583 mmi->ptMinTrackSize.y = 100;
\r
7590 AnalysisPopUp(char* title, char* str)
\r
7595 if (str == NULL) str = "";
\r
7596 p = (char *) malloc(2 * strlen(str) + 2);
\r
7599 if (*str == '\n') *q++ = '\r';
\r
7603 if (analysisText != NULL) free(analysisText);
\r
7606 if (analysisDialog) {
\r
7607 SetWindowText(analysisDialog, title);
\r
7608 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
7609 ShowWindow(analysisDialog, SW_SHOW);
\r
7611 analysisTitle = title;
\r
7612 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
7613 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
7614 hwndMain, (DLGPROC)lpProc);
\r
7615 FreeProcInstance(lpProc);
\r
7617 analysisDialogUp = TRUE;
\r
7623 if (analysisDialog) {
\r
7624 ShowWindow(analysisDialog, SW_HIDE);
\r
7626 analysisDialogUp = FALSE;
\r
7631 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
7633 highlightInfo.sq[0].x = fromX;
\r
7634 highlightInfo.sq[0].y = fromY;
\r
7635 highlightInfo.sq[1].x = toX;
\r
7636 highlightInfo.sq[1].y = toY;
\r
7642 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
7643 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
7647 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
7649 premoveHighlightInfo.sq[0].x = fromX;
\r
7650 premoveHighlightInfo.sq[0].y = fromY;
\r
7651 premoveHighlightInfo.sq[1].x = toX;
\r
7652 premoveHighlightInfo.sq[1].y = toY;
\r
7656 ClearPremoveHighlights()
\r
7658 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
7659 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
7663 ShutDownFrontEnd()
\r
7665 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
7666 DeleteClipboardTempFiles();
\r
7672 if (IsIconic(hwndMain))
\r
7673 ShowWindow(hwndMain, SW_RESTORE);
\r
7675 SetActiveWindow(hwndMain);
\r
7679 * Prototypes for animation support routines
\r
7681 static void ScreenSquare(int column, int row, POINT * pt);
\r
7682 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
7683 POINT frames[], int * nFrames);
\r
7689 AnimateMove(board, fromX, fromY, toX, toY)
\r
7696 ChessSquare piece;
\r
7697 POINT start, finish, mid;
\r
7698 POINT frames[kFactor * 2 + 1];
\r
7701 if (!appData.animate) return;
\r
7702 if (doingSizing) return;
\r
7703 if (fromY < 0 || fromX < 0) return;
\r
7704 piece = board[fromY][fromX];
\r
7705 if (piece >= EmptySquare) return;
\r
7707 ScreenSquare(fromX, fromY, &start);
\r
7708 ScreenSquare(toX, toY, &finish);
\r
7710 /* All pieces except knights move in straight line */
\r
7711 if (piece != WhiteKnight && piece != BlackKnight) {
\r
7712 mid.x = start.x + (finish.x - start.x) / 2;
\r
7713 mid.y = start.y + (finish.y - start.y) / 2;
\r
7715 /* Knight: make diagonal movement then straight */
\r
7716 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
7717 mid.x = start.x + (finish.x - start.x) / 2;
\r
7721 mid.y = start.y + (finish.y - start.y) / 2;
\r
7725 /* Don't use as many frames for very short moves */
\r
7726 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
7727 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
7729 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
7731 animInfo.from.x = fromX;
\r
7732 animInfo.from.y = fromY;
\r
7733 animInfo.to.x = toX;
\r
7734 animInfo.to.y = toY;
\r
7735 animInfo.lastpos = start;
\r
7736 animInfo.piece = piece;
\r
7737 for (n = 0; n < nFrames; n++) {
\r
7738 animInfo.pos = frames[n];
\r
7739 DrawPosition(FALSE, NULL);
\r
7740 animInfo.lastpos = animInfo.pos;
\r
7741 Sleep(appData.animSpeed);
\r
7743 animInfo.pos = finish;
\r
7744 DrawPosition(FALSE, NULL);
\r
7745 animInfo.piece = EmptySquare;
\r
7748 /* Convert board position to corner of screen rect and color */
\r
7751 ScreenSquare(column, row, pt)
\r
7752 int column; int row; POINT * pt;
\r
7755 pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
7756 pt->y = lineGap + row * (squareSize + lineGap);
\r
7758 pt->x = lineGap + column * (squareSize + lineGap);
\r
7759 pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
7763 /* Generate a series of frame coords from start->mid->finish.
\r
7764 The movement rate doubles until the half way point is
\r
7765 reached, then halves back down to the final destination,
\r
7766 which gives a nice slow in/out effect. The algorithmn
\r
7767 may seem to generate too many intermediates for short
\r
7768 moves, but remember that the purpose is to attract the
\r
7769 viewers attention to the piece about to be moved and
\r
7770 then to where it ends up. Too few frames would be less
\r
7774 Tween(start, mid, finish, factor, frames, nFrames)
\r
7775 POINT * start; POINT * mid;
\r
7776 POINT * finish; int factor;
\r
7777 POINT frames[]; int * nFrames;
\r
7779 int n, fraction = 1, count = 0;
\r
7781 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
7782 for (n = 0; n < factor; n++)
\r
7784 for (n = 0; n < factor; n++) {
\r
7785 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
7786 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
7788 fraction = fraction / 2;
\r
7792 frames[count] = *mid;
\r
7795 /* Slow out, stepping 1/2, then 1/4, ... */
\r
7797 for (n = 0; n < factor; n++) {
\r
7798 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
7799 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
7801 fraction = fraction * 2;
\r
7807 HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current)
\r
7809 /* Currently not implemented in WinBoard */
\r