2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
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
62 #include <sys/stat.h>
\r
65 #include <commdlg.h>
\r
67 #include <richedit.h>
\r
68 #include <mmsystem.h>
\r
76 #include "winboard.h"
\r
77 #include "frontend.h"
\r
78 #include "backend.h"
\r
80 #include "wclipbrd.h"
\r
81 #include "wgamelist.h"
\r
82 #include "wedittags.h"
\r
83 #include "woptions.h"
\r
84 #include "wsockerr.h"
\r
85 #include "defaults.h"
\r
88 void mysrandom(unsigned int seed);
92 POINT pos; /* window coordinates of current pos */
\r
93 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
94 POINT from; /* board coordinates of the piece's orig pos */
\r
95 POINT to; /* board coordinates of the piece's new pos */
\r
98 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
101 POINT start; /* window coordinates of start pos */
\r
102 POINT pos; /* window coordinates of current pos */
\r
103 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
104 POINT from; /* board coordinates of the piece's orig pos */
\r
107 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
110 POINT sq[2]; /* board coordinates of from, to squares */
\r
113 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
114 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
116 /* Window class names */
\r
117 char szAppName[] = "WinBoard";
\r
118 char szConsoleName[] = "WBConsole";
\r
120 /* Title bar text */
\r
121 char szTitle[] = "WinBoard";
\r
122 char szConsoleTitle[] = "ICS Interaction";
\r
125 char *settingsFileName;
\r
126 BOOLEAN saveSettingsOnExit;
\r
127 char installDir[MSG_SIZ];
\r
129 BoardSize boardSize;
\r
130 BOOLEAN chessProgram;
\r
131 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
132 static int squareSize, lineGap;
\r
133 static int winWidth, winHeight;
\r
134 static RECT messageRect, whiteRect, blackRect;
\r
135 static char messageText[MESSAGE_TEXT_MAX];
\r
136 static int clockTimerEvent = 0;
\r
137 static int loadGameTimerEvent = 0;
\r
138 static int analysisTimerEvent = 0;
\r
139 static DelayedEventCallback delayedTimerCallback;
\r
140 static int delayedTimerEvent = 0;
\r
141 static int buttonCount = 2;
\r
142 char *icsTextMenuString;
\r
144 char *firstChessProgramNames;
\r
145 char *secondChessProgramNames;
\r
147 #define ARG_MAX 64*1024 /* [AS] For Roger Brown's very long list! */
149 #define PALETTESIZE 256
\r
151 HINSTANCE hInst; /* current instance */
\r
152 HWND hwndMain = NULL; /* root window*/
\r
153 HWND hwndConsole = NULL;
\r
154 BOOLEAN alwaysOnTop = FALSE;
\r
156 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
157 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
159 ColorClass currentColorClass;
\r
161 HWND hCommPort = NULL; /* currently open comm port */
\r
162 static HWND hwndPause; /* pause button */
\r
163 static HBITMAP pieceBitmap[3][(int) WhiteKing + 1];
\r
164 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
165 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
166 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
167 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
168 static HPEN gridPen = NULL;
\r
169 static HPEN highlightPen = NULL;
\r
170 static HPEN premovePen = NULL;
\r
171 static NPLOGPALETTE pLogPal;
\r
172 static BOOL paletteChanged = FALSE;
\r
173 static HICON iconWhite, iconBlack, iconCurrent;
\r
174 static int doingSizing = FALSE;
\r
175 static int lastSizing = 0;
\r
176 static int prevStderrPort;
\r
178 /* [AS] Support for background textures */
179 #define BACK_TEXTURE_MODE_DISABLED 0
180 #define BACK_TEXTURE_MODE_PLAIN 1
181 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
183 static HBITMAP liteBackTexture = NULL;
184 static HBITMAP darkBackTexture = NULL;
185 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
186 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
187 static int backTextureSquareSize = 0;
188 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
190 #if __GNUC__ && !defined(_winmajor)
\r
191 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
193 #define oldDialog (_winmajor < 4)
\r
196 char *defaultTextAttribs[] =
\r
198 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
199 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
209 int cliWidth, cliHeight;
\r
212 SizeInfo sizeInfo[] =
\r
214 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
215 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
216 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
217 { "petite", 33, 1, 1, 1, 0, 0 },
\r
218 { "slim", 37, 2, 1, 0, 0, 0 },
\r
219 { "small", 40, 2, 1, 0, 0, 0 },
\r
220 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
221 { "middling", 49, 2, 0, 0, 0, 0 },
\r
222 { "average", 54, 2, 0, 0, 0, 0 },
\r
223 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
224 { "medium", 64, 3, 0, 0, 0, 0 },
\r
225 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
226 { "large", 80, 3, 0, 0, 0, 0 },
\r
227 { "big", 87, 3, 0, 0, 0, 0 },
\r
228 { "huge", 95, 3, 0, 0, 0, 0 },
\r
229 { "giant", 108, 3, 0, 0, 0, 0 },
\r
230 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
231 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
232 { NULL, 0, 0, 0, 0, 0, 0 }
\r
235 #define MF(x) {x, {0, }, {0, }, 0}
\r
236 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
238 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY),
\r
239 MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY),
\r
240 MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY) },
\r
241 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY),
\r
242 MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY),
\r
243 MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY) },
\r
244 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY),
\r
245 MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY),
\r
246 MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY) },
\r
247 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE),
\r
248 MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE),
\r
249 MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE) },
\r
250 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM),
\r
251 MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM),
\r
252 MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM) },
\r
253 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL),
\r
254 MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL),
\r
255 MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL) },
\r
256 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE),
\r
257 MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE),
\r
258 MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE) },
\r
259 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING),
\r
260 MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING),
\r
261 MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING) },
\r
262 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE),
\r
263 MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE),
\r
264 MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE) },
\r
265 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE),
\r
266 MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE),
\r
267 MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE) },
\r
268 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM),
\r
269 MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM),
\r
270 MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM) },
\r
271 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY),
\r
272 MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY),
\r
273 MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY) },
\r
274 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE),
\r
275 MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE),
\r
276 MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE) },
\r
277 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG),
\r
278 MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG),
\r
279 MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG) },
\r
280 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE),
\r
281 MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE),
\r
282 MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE) },
\r
283 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT),
\r
284 MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT),
\r
285 MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT) },
\r
286 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL),
\r
287 MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL),
\r
288 MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL) },
\r
289 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC),
\r
290 MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC),
\r
291 MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC) },
\r
294 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
303 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
304 #define N_BUTTONS 5
\r
306 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
308 {"<<", IDM_ToStart, NULL, NULL},
\r
309 {"<", IDM_Backward, NULL, NULL},
\r
310 {"P", IDM_Pause, NULL, NULL},
\r
311 {">", IDM_Forward, NULL, NULL},
\r
312 {">>", IDM_ToEnd, NULL, NULL},
\r
315 int tinyLayout = 0, smallLayout = 0;
\r
316 #define MENU_BAR_ITEMS 6
\r
317 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
318 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
319 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
323 MySound sounds[(int)NSoundClasses];
\r
324 MyTextAttribs textAttribs[(int)NColorClasses];
\r
326 MyColorizeAttribs colorizeAttribs[] = {
\r
327 { (COLORREF)0, 0, "Shout Text" },
\r
328 { (COLORREF)0, 0, "SShout/CShout" },
\r
329 { (COLORREF)0, 0, "Channel 1 Text" },
\r
330 { (COLORREF)0, 0, "Channel Text" },
\r
331 { (COLORREF)0, 0, "Kibitz Text" },
\r
332 { (COLORREF)0, 0, "Tell Text" },
\r
333 { (COLORREF)0, 0, "Challenge Text" },
\r
334 { (COLORREF)0, 0, "Request Text" },
\r
335 { (COLORREF)0, 0, "Seek Text" },
\r
336 { (COLORREF)0, 0, "Normal Text" },
\r
337 { (COLORREF)0, 0, "None" }
\r
342 static char *commentTitle;
\r
343 static char *commentText;
\r
344 static int commentIndex;
\r
345 static Boolean editComment = FALSE;
\r
346 HWND commentDialog = NULL;
\r
347 BOOLEAN commentDialogUp = FALSE;
\r
348 static int commentX, commentY, commentH, commentW;
\r
350 static char *analysisTitle;
\r
351 static char *analysisText;
\r
352 HWND analysisDialog = NULL;
\r
353 BOOLEAN analysisDialogUp = FALSE;
\r
354 static int analysisX, analysisY, analysisH, analysisW;
\r
356 char errorTitle[MSG_SIZ];
\r
357 char errorMessage[2*MSG_SIZ];
\r
358 HWND errorDialog = NULL;
\r
359 BOOLEAN moveErrorMessageUp = FALSE;
\r
360 BOOLEAN consoleEcho = TRUE;
\r
361 CHARFORMAT consoleCF;
\r
362 COLORREF consoleBackgroundColor;
\r
364 char *programVersion;
\r
370 typedef int CPKind;
\r
379 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
382 #define INPUT_SOURCE_BUF_SIZE 4096
\r
384 typedef struct _InputSource {
\r
391 char buf[INPUT_SOURCE_BUF_SIZE];
\r
395 InputCallback func;
\r
396 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
400 InputSource *consoleInputSource;
\r
405 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
406 VOID ConsoleCreate();
\r
408 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
409 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
410 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
411 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
413 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
414 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
415 void ParseIcsTextMenu(char *icsTextMenuString);
\r
416 VOID PopUpMoveDialog(char firstchar);
\r
417 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
421 * Setting "frozen" should disable all user input other than deleting
\r
422 * the window. We do this while engines are initializing themselves.
\r
424 static int frozen = 0;
\r
425 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
431 if (frozen) return;
\r
433 hmenu = GetMenu(hwndMain);
\r
434 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
435 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
437 DrawMenuBar(hwndMain);
\r
440 /* Undo a FreezeUI */
\r
446 if (!frozen) return;
\r
448 hmenu = GetMenu(hwndMain);
\r
449 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
450 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
452 DrawMenuBar(hwndMain);
\r
455 /*---------------------------------------------------------------------------*\
\r
459 \*---------------------------------------------------------------------------*/
\r
462 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
463 LPSTR lpCmdLine, int nCmdShow)
\r
466 HANDLE hAccelMain, hAccelNoAlt;
\r
470 LoadLibrary("RICHED32.DLL");
\r
471 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
473 if (!InitApplication(hInstance)) {
\r
476 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
480 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
481 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
483 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
485 while (GetMessage(&msg, /* message structure */
\r
486 NULL, /* handle of window receiving the message */
\r
487 0, /* lowest message to examine */
\r
488 0)) /* highest message to examine */
\r
490 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
491 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
492 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
493 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
494 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
495 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
496 TranslateMessage(&msg); /* Translates virtual key codes */
\r
497 DispatchMessage(&msg); /* Dispatches message to window */
\r
502 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
505 /*---------------------------------------------------------------------------*\
\r
507 * Initialization functions
\r
509 \*---------------------------------------------------------------------------*/
\r
512 InitApplication(HINSTANCE hInstance)
\r
516 /* Fill in window class structure with parameters that describe the */
\r
519 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
520 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
521 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
522 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
523 wc.hInstance = hInstance; /* Owner of this class */
\r
524 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
525 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
526 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
527 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
528 wc.lpszClassName = szAppName; /* Name to register as */
\r
530 /* Register the window class and return success/failure code. */
\r
531 if (!RegisterClass(&wc)) return FALSE;
\r
533 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
534 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
536 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
537 wc.hInstance = hInstance;
\r
538 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
539 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
540 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
541 wc.lpszMenuName = NULL;
\r
542 wc.lpszClassName = szConsoleName;
\r
544 if (!RegisterClass(&wc)) return FALSE;
\r
549 /* Set by InitInstance, used by EnsureOnScreen */
\r
550 int screenHeight, screenWidth;
\r
553 EnsureOnScreen(int *x, int *y)
\r
555 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
556 if (*x > screenWidth - 32) *x = 0;
\r
557 if (*y > screenHeight - 32) *y = 0;
\r
561 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
563 HWND hwnd; /* Main window handle. */
\r
565 WINDOWPLACEMENT wp;
\r
568 hInst = hInstance; /* Store instance handle in our global variable */
\r
570 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
571 *filepart = NULLCHAR;
\r
573 GetCurrentDirectory(MSG_SIZ, installDir);
\r
575 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
576 if (appData.debugMode) {
\r
577 debugFP = fopen(appData.nameOfDebugFile, "w");
578 setbuf(debugFP, NULL);
\r
583 /* Create a main window for this application instance. */
\r
584 hwnd = CreateWindow(szAppName, szTitle,
\r
585 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
586 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
587 NULL, NULL, hInstance, NULL);
\r
590 /* If window could not be created, return "failure" */
\r
595 iconWhite = LoadIcon(hInstance, "icon_white");
\r
596 iconBlack = LoadIcon(hInstance, "icon_black");
\r
597 iconCurrent = iconWhite;
\r
598 InitDrawingColors();
\r
599 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
600 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
601 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
602 /* Compute window size for each board size, and use the largest
\r
603 size that fits on this screen as the default. */
\r
604 InitDrawingSizes((BoardSize)ibs, 0);
\r
605 if (boardSize == (BoardSize)-1 &&
\r
606 winHeight <= screenHeight && winWidth <= screenWidth) {
\r
607 boardSize = (BoardSize)ibs;
\r
610 InitDrawingSizes(boardSize, 0);
\r
612 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
614 /* [AS] Load textures if specified */
615 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
617 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
618 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
619 liteBackTextureMode = appData.liteBackTextureMode;
621 if (liteBackTexture == NULL && appData.debugMode) {
622 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
626 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
627 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
628 darkBackTextureMode = appData.darkBackTextureMode;
630 if (darkBackTexture == NULL && appData.debugMode) {
631 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
635 mysrandom( (unsigned) time(NULL) );
637 /* Make a console window if needed */
\r
638 if (appData.icsActive) {
\r
644 /* Make the window visible; update its client area; and return "success" */
\r
645 EnsureOnScreen(&boardX, &boardY);
\r
646 wp.length = sizeof(WINDOWPLACEMENT);
\r
648 wp.showCmd = nCmdShow;
\r
649 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
650 wp.rcNormalPosition.left = boardX;
\r
651 wp.rcNormalPosition.right = boardX + winWidth;
\r
652 wp.rcNormalPosition.top = boardY;
\r
653 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
654 SetWindowPlacement(hwndMain, &wp);
\r
656 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
657 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
659 /* [AS] Disable the FRC stuff if not playing the proper variant */
660 if( gameInfo.variant != VariantFischeRandom ) {
661 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
666 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
667 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
669 ShowWindow(hwndConsole, nCmdShow);
\r
671 UpdateWindow(hwnd);
\r
679 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
680 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
681 ArgSettingsFilename
\r
689 String *pString; // ArgString
\r
690 int *pInt; // ArgInt
\r
691 float *pFloat; // ArgFloat
\r
692 Boolean *pBoolean; // ArgBoolean
\r
693 COLORREF *pColor; // ArgColor
\r
694 ColorClass cc; // ArgAttribs
\r
695 String *pFilename; // ArgFilename
\r
696 BoardSize *pBoardSize; // ArgBoardSize
\r
697 int whichFont; // ArgFont
\r
698 DCB *pDCB; // ArgCommSettings
\r
699 String *pFilename; // ArgSettingsFilename
\r
707 ArgDescriptor argDescriptors[] = {
\r
708 /* positional arguments */
\r
709 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
710 { "", ArgNone, NULL },
\r
711 /* keyword arguments */
\r
712 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
713 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
714 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
715 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
716 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
717 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
718 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
719 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
720 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
721 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
722 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
723 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
724 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
725 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
726 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
727 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
728 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
729 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
731 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
733 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
735 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
736 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
738 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
739 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
740 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
741 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
742 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
743 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
744 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
745 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
746 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
747 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
748 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
749 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
750 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
751 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
752 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
753 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
754 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
755 /*!!bitmapDirectory?*/
\r
756 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
757 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
758 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
759 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
760 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
761 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
762 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
763 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
764 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
765 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
766 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
767 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
768 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
769 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
770 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
771 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
772 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
773 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
774 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
775 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
776 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
777 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
778 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
779 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
780 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
781 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
782 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
783 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
784 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
785 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
786 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
787 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
788 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
789 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
790 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
791 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
792 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
793 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
794 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
795 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
796 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
797 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
798 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
799 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
800 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
801 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
802 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
803 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
804 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
805 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
806 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
807 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
808 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
809 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
810 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
811 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
812 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
813 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
814 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
815 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
816 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
817 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
818 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
819 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
820 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
821 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
822 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
823 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
824 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
825 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
826 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
827 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
828 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
829 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
830 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
831 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
832 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
833 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
834 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
835 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
836 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
837 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
838 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
839 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
840 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
841 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
842 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
843 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
844 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
845 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
846 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
847 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
848 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
849 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
850 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
851 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
852 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
853 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
854 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
855 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
856 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
857 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
858 TRUE }, /* must come after all fonts */
\r
859 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
860 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
861 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
862 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
863 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
864 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
865 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
866 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
867 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
868 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
869 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
870 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
871 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
872 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
873 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
874 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
875 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
876 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
877 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
878 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
879 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
880 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
881 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
882 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
883 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
884 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
885 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
886 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
887 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
888 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
889 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
891 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
892 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
894 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
895 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
896 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
897 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
898 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
899 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
900 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
901 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
902 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
903 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
904 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
905 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
906 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
907 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
908 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
909 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
910 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
911 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
912 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
913 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
914 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
915 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
916 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
917 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
918 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
919 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
920 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
921 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
922 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
923 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
924 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
925 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
926 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
927 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
928 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
929 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
930 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
931 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
932 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
933 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
934 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
935 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
936 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
937 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
938 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
939 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
940 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
941 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
942 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
943 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
944 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
945 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
946 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
947 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
948 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
949 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
950 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
951 { "highlightLastMove", ArgBoolean,
\r
952 (LPVOID) &appData.highlightLastMove, TRUE },
\r
953 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
954 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
955 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
956 { "highlightDragging", ArgBoolean,
\r
957 (LPVOID) &appData.highlightDragging, TRUE },
\r
958 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
959 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
960 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
961 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
962 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
963 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
964 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
965 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
966 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
967 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
968 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
969 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
970 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
971 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
972 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
973 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
974 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
975 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
976 { "soundShout", ArgFilename,
\r
977 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
978 { "soundSShout", ArgFilename,
\r
979 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
980 { "soundChannel1", ArgFilename,
\r
981 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
982 { "soundChannel", ArgFilename,
\r
983 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
984 { "soundKibitz", ArgFilename,
\r
985 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
986 { "soundTell", ArgFilename,
\r
987 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
988 { "soundChallenge", ArgFilename,
\r
989 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
990 { "soundRequest", ArgFilename,
\r
991 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
992 { "soundSeek", ArgFilename,
\r
993 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
994 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
995 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
996 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
997 { "soundIcsLoss", ArgFilename,
\r
998 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
999 { "soundIcsDraw", ArgFilename,
\r
1000 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1001 { "soundIcsUnfinished", ArgFilename,
\r
1002 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1003 { "soundIcsAlarm", ArgFilename,
\r
1004 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1005 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1006 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1007 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1008 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1009 { "reuseChessPrograms", ArgBoolean,
\r
1010 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1011 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1012 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1013 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1014 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1015 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1016 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1017 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1018 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1019 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1020 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1021 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1022 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1023 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1024 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1025 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1026 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1027 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1028 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1029 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1030 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1031 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1032 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1033 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1034 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1035 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1036 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1037 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1038 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1039 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1040 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1041 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1042 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1043 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1044 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1045 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1046 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1047 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1049 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1051 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1052 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1053 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1054 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
1055 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
1056 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1057 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1058 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1059 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1060 /* [AS] New features */
1061 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, TRUE },
1062 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, TRUE },
1063 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
1064 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
1065 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
1066 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
1067 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
1068 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
1069 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
1070 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
1071 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
1072 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
1073 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
1074 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
1075 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
1076 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
1077 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
1078 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
1079 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
1080 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
1081 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
1082 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
1083 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
1085 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1086 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1087 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1088 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1089 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1090 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1091 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1092 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1093 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1094 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1095 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1096 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1097 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1099 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1100 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1101 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1102 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1103 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1104 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1105 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1107 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1108 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1109 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1110 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1111 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1112 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1113 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1114 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1115 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1116 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1117 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1118 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1119 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1120 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1121 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1122 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1123 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1124 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1126 { NULL, ArgNone, NULL, FALSE }
\r
1130 /* Kludge for indirection files on command line */
\r
1131 char* lastIndirectionFilename;
\r
1132 ArgDescriptor argDescriptorIndirection =
\r
1133 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1137 ExitArgError(char *msg, char *badArg)
\r
1139 char buf[MSG_SIZ];
\r
1141 sprintf(buf, "%s %s", msg, badArg);
\r
1142 DisplayFatalError(buf, 0, 2);
\r
1146 /* Command line font name parser. NULL name means do nothing.
\r
1147 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1148 For backward compatibility, syntax without the colon is also
\r
1149 accepted, but font names with digits in them won't work in that case.
\r
1152 ParseFontName(char *name, MyFontParams *mfp)
\r
1155 if (name == NULL) return;
\r
1157 q = strchr(p, ':');
\r
1159 if (q - p >= sizeof(mfp->faceName))
\r
1160 ExitArgError("Font name too long:", name);
\r
1161 memcpy(mfp->faceName, p, q - p);
\r
1162 mfp->faceName[q - p] = NULLCHAR;
\r
1165 q = mfp->faceName;
\r
1166 while (*p && !isdigit(*p)) {
\r
1168 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1169 ExitArgError("Font name too long:", name);
\r
1171 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1174 if (!*p) ExitArgError("Font point size missing:", name);
\r
1175 mfp->pointSize = (float) atof(p);
\r
1176 mfp->bold = (strchr(p, 'b') != NULL);
\r
1177 mfp->italic = (strchr(p, 'i') != NULL);
\r
1178 mfp->underline = (strchr(p, 'u') != NULL);
\r
1179 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1182 /* Color name parser.
\r
1183 X version accepts X color names, but this one
\r
1184 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1186 ParseColorName(char *name)
\r
1188 int red, green, blue, count;
\r
1189 char buf[MSG_SIZ];
\r
1191 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1193 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1194 &red, &green, &blue);
\r
1197 sprintf(buf, "Can't parse color name %s", name);
\r
1198 DisplayError(buf, 0);
\r
1199 return RGB(0, 0, 0);
\r
1201 return PALETTERGB(red, green, blue);
\r
1205 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1207 char *e = argValue;
\r
1211 if (*e == 'b') eff |= CFE_BOLD;
\r
1212 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1213 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1214 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1215 else if (*e == '#' || isdigit(*e)) break;
\r
1219 *color = ParseColorName(e);
\r
1224 ParseBoardSize(char *name)
\r
1226 BoardSize bs = SizeTiny;
\r
1227 while (sizeInfo[bs].name != NULL) {
\r
1228 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1231 ExitArgError("Unrecognized board size value", name);
\r
1232 return bs; /* not reached */
\r
1237 StringGet(void *getClosure)
\r
1239 char **p = (char **) getClosure;
\r
1244 FileGet(void *getClosure)
\r
1247 FILE* f = (FILE*) getClosure;
\r
1256 /* Parse settings file named "name". If file found, return the
\r
1257 full name in fullname and return TRUE; else return FALSE */
\r
1259 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1264 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1265 f = fopen(fullname, "r");
\r
1267 ParseArgs(FileGet, f);
\r
1276 ParseArgs(GetFunc get, void *cl)
\r
1278 char argName[ARG_MAX];
\r
1279 char argValue[ARG_MAX];
\r
1280 ArgDescriptor *ad;
\r
1289 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1290 if (ch == NULLCHAR) break;
\r
1292 /* Comment to end of line */
\r
1294 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1296 } else if (ch == '/' || ch == '-') {
\r
1299 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1300 ch != '\n' && ch != '\t') {
\r
1306 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1307 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1309 if (ad->argName == NULL)
\r
1310 ExitArgError("Unrecognized argument", argName);
\r
1312 } else if (ch == '@') {
\r
1313 /* Indirection file */
\r
1314 ad = &argDescriptorIndirection;
\r
1317 /* Positional argument */
\r
1318 ad = &argDescriptors[posarg++];
\r
1319 strcpy(argName, ad->argName);
\r
1322 if (ad->argType == ArgTrue) {
\r
1323 *(Boolean *) ad->argLoc = TRUE;
\r
1326 if (ad->argType == ArgFalse) {
\r
1327 *(Boolean *) ad->argLoc = FALSE;
\r
1331 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1332 if (ch == NULLCHAR || ch == '\n') {
\r
1333 ExitArgError("No value provided for argument", argName);
\r
1337 // Quoting with { }. No characters have to (or can) be escaped.
\r
1338 // Thus the string cannot contain a '}' character.
\r
1358 } else if (ch == '\'' || ch == '"') {
\r
1359 // Quoting with ' ' or " ", with \ as escape character.
\r
1360 // Inconvenient for long strings that may contain Windows filenames.
\r
1377 if (ch == start) {
\r
1386 if (ad->argType == ArgFilename
\r
1387 || ad->argType == ArgSettingsFilename) {
\r
1393 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1417 for (i = 0; i < 3; i++) {
\r
1418 if (ch >= '0' && ch <= '7') {
\r
1419 octval = octval*8 + (ch - '0');
\r
1426 *q++ = (char) octval;
\r
1437 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1444 switch (ad->argType) {
\r
1446 *(int *) ad->argLoc = atoi(argValue);
\r
1450 *(float *) ad->argLoc = (float) atof(argValue);
\r
1455 *(char **) ad->argLoc = strdup(argValue);
\r
1458 case ArgSettingsFilename:
\r
1460 char fullname[MSG_SIZ];
\r
1461 if (ParseSettingsFile(argValue, fullname)) {
\r
1462 if (ad->argLoc != NULL) {
\r
1463 *(char **) ad->argLoc = strdup(fullname);
\r
1466 if (ad->argLoc != NULL) {
\r
1468 ExitArgError("Failed to open indirection file", argValue);
\r
1475 switch (argValue[0]) {
\r
1478 *(Boolean *) ad->argLoc = TRUE;
\r
1482 *(Boolean *) ad->argLoc = FALSE;
\r
1485 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1491 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1494 case ArgAttribs: {
\r
1495 ColorClass cc = (ColorClass)ad->argLoc;
\r
1496 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1500 case ArgBoardSize:
\r
1501 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1505 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1508 case ArgCommSettings:
\r
1509 ParseCommSettings(argValue, &dcb);
\r
1513 ExitArgError("Unrecognized argument", argValue);
\r
1520 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1522 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1523 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1526 lf->lfEscapement = 0;
\r
1527 lf->lfOrientation = 0;
\r
1528 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1529 lf->lfItalic = mfp->italic;
\r
1530 lf->lfUnderline = mfp->underline;
\r
1531 lf->lfStrikeOut = mfp->strikeout;
\r
1532 lf->lfCharSet = DEFAULT_CHARSET;
\r
1533 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1534 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1535 lf->lfQuality = DEFAULT_QUALITY;
\r
1536 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1537 strcpy(lf->lfFaceName, mfp->faceName);
\r
1541 CreateFontInMF(MyFont *mf)
\r
1543 LFfromMFP(&mf->lf, &mf->mfp);
\r
1544 if (mf->hf) DeleteObject(mf->hf);
\r
1545 mf->hf = CreateFontIndirect(&mf->lf);
\r
1549 SetDefaultTextAttribs()
\r
1552 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1553 ParseAttribs(&textAttribs[cc].color,
\r
1554 &textAttribs[cc].effects,
\r
1555 defaultTextAttribs[cc]);
\r
1560 SetDefaultSounds()
\r
1564 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1565 textAttribs[cc].sound.name = strdup("");
\r
1566 textAttribs[cc].sound.data = NULL;
\r
1568 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1569 sounds[sc].name = strdup("");
\r
1570 sounds[sc].data = NULL;
\r
1572 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1580 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1581 MyLoadSound(&textAttribs[cc].sound);
\r
1583 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1584 MyLoadSound(&sounds[sc]);
\r
1589 InitAppData(LPSTR lpCmdLine)
\r
1592 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1595 programName = szAppName;
\r
1597 /* Initialize to defaults */
\r
1598 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1599 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1600 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1601 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1602 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1603 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1604 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1605 SetDefaultTextAttribs();
\r
1606 SetDefaultSounds();
\r
1607 appData.movesPerSession = MOVES_PER_SESSION;
\r
1608 appData.initString = INIT_STRING;
\r
1609 appData.secondInitString = INIT_STRING;
\r
1610 appData.firstComputerString = COMPUTER_STRING;
\r
1611 appData.secondComputerString = COMPUTER_STRING;
\r
1612 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1613 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1614 appData.firstPlaysBlack = FALSE;
\r
1615 appData.noChessProgram = FALSE;
\r
1616 chessProgram = FALSE;
\r
1617 appData.firstHost = FIRST_HOST;
\r
1618 appData.secondHost = SECOND_HOST;
\r
1619 appData.firstDirectory = FIRST_DIRECTORY;
\r
1620 appData.secondDirectory = SECOND_DIRECTORY;
\r
1621 appData.bitmapDirectory = "";
\r
1622 appData.remoteShell = REMOTE_SHELL;
\r
1623 appData.remoteUser = "";
\r
1624 appData.timeDelay = TIME_DELAY;
\r
1625 appData.timeControl = TIME_CONTROL;
\r
1626 appData.timeIncrement = TIME_INCREMENT;
\r
1627 appData.icsActive = FALSE;
\r
1628 appData.icsHost = "";
\r
1629 appData.icsPort = ICS_PORT;
\r
1630 appData.icsCommPort = ICS_COMM_PORT;
\r
1631 appData.icsLogon = ICS_LOGON;
\r
1632 appData.icsHelper = "";
\r
1633 appData.useTelnet = FALSE;
\r
1634 appData.telnetProgram = TELNET_PROGRAM;
\r
1635 appData.gateway = "";
\r
1636 appData.loadGameFile = "";
\r
1637 appData.loadGameIndex = 0;
\r
1638 appData.saveGameFile = "";
\r
1639 appData.autoSaveGames = FALSE;
\r
1640 appData.loadPositionFile = "";
\r
1641 appData.loadPositionIndex = 1;
\r
1642 appData.savePositionFile = "";
\r
1643 appData.matchMode = FALSE;
\r
1644 appData.matchGames = 0;
\r
1645 appData.monoMode = FALSE;
\r
1646 appData.debugMode = FALSE;
\r
1647 appData.clockMode = TRUE;
\r
1648 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1649 appData.Iconic = FALSE; /*unused*/
\r
1650 appData.searchTime = "";
\r
1651 appData.searchDepth = 0;
\r
1652 appData.showCoords = FALSE;
\r
1653 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1654 appData.autoCallFlag = FALSE;
\r
1655 appData.flipView = FALSE;
\r
1656 appData.autoFlipView = TRUE;
\r
1657 appData.cmailGameName = "";
\r
1658 appData.alwaysPromoteToQueen = FALSE;
\r
1659 appData.oldSaveStyle = FALSE;
\r
1660 appData.quietPlay = FALSE;
\r
1661 appData.showThinking = FALSE;
\r
1662 appData.ponderNextMove = TRUE;
\r
1663 appData.periodicUpdates = TRUE;
\r
1664 appData.popupExitMessage = TRUE;
\r
1665 appData.popupMoveErrors = FALSE;
\r
1666 appData.autoObserve = FALSE;
\r
1667 appData.autoComment = FALSE;
\r
1668 appData.animate = TRUE;
\r
1669 appData.animSpeed = 10;
\r
1670 appData.animateDragging = TRUE;
\r
1671 appData.highlightLastMove = TRUE;
\r
1672 appData.getMoveList = TRUE;
\r
1673 appData.testLegality = TRUE;
\r
1674 appData.premove = TRUE;
\r
1675 appData.premoveWhite = FALSE;
\r
1676 appData.premoveWhiteText = "";
\r
1677 appData.premoveBlack = FALSE;
\r
1678 appData.premoveBlackText = "";
\r
1679 appData.icsAlarm = TRUE;
\r
1680 appData.icsAlarmTime = 5000;
\r
1681 appData.autoRaiseBoard = TRUE;
\r
1682 appData.localLineEditing = TRUE;
\r
1683 appData.colorize = TRUE;
\r
1684 appData.reuseFirst = TRUE;
\r
1685 appData.reuseSecond = TRUE;
\r
1686 appData.blindfold = FALSE;
\r
1687 dcb.DCBlength = sizeof(DCB);
\r
1688 dcb.BaudRate = 9600;
\r
1689 dcb.fBinary = TRUE;
\r
1690 dcb.fParity = FALSE;
\r
1691 dcb.fOutxCtsFlow = FALSE;
\r
1692 dcb.fOutxDsrFlow = FALSE;
\r
1693 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1694 dcb.fDsrSensitivity = FALSE;
\r
1695 dcb.fTXContinueOnXoff = TRUE;
\r
1696 dcb.fOutX = FALSE;
\r
1698 dcb.fNull = FALSE;
\r
1699 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1700 dcb.fAbortOnError = FALSE;
\r
1701 dcb.wReserved = 0;
\r
1703 dcb.Parity = SPACEPARITY;
\r
1704 dcb.StopBits = ONESTOPBIT;
\r
1705 settingsFileName = SETTINGS_FILE;
\r
1706 saveSettingsOnExit = TRUE;
\r
1707 boardX = CW_USEDEFAULT;
\r
1708 boardY = CW_USEDEFAULT;
\r
1709 consoleX = CW_USEDEFAULT;
\r
1710 consoleY = CW_USEDEFAULT;
\r
1711 consoleW = CW_USEDEFAULT;
\r
1712 consoleH = CW_USEDEFAULT;
\r
1713 analysisX = CW_USEDEFAULT;
\r
1714 analysisY = CW_USEDEFAULT;
\r
1715 analysisW = CW_USEDEFAULT;
\r
1716 analysisH = CW_USEDEFAULT;
\r
1717 commentX = CW_USEDEFAULT;
\r
1718 commentY = CW_USEDEFAULT;
\r
1719 commentW = CW_USEDEFAULT;
\r
1720 commentH = CW_USEDEFAULT;
\r
1721 editTagsX = CW_USEDEFAULT;
\r
1722 editTagsY = CW_USEDEFAULT;
\r
1723 editTagsW = CW_USEDEFAULT;
\r
1724 editTagsH = CW_USEDEFAULT;
\r
1725 gameListX = CW_USEDEFAULT;
\r
1726 gameListY = CW_USEDEFAULT;
\r
1727 gameListW = CW_USEDEFAULT;
\r
1728 gameListH = CW_USEDEFAULT;
\r
1729 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1730 icsNames = ICS_NAMES;
\r
1731 firstChessProgramNames = FCP_NAMES;
\r
1732 secondChessProgramNames = SCP_NAMES;
\r
1733 appData.initialMode = "";
\r
1734 appData.variant = "normal";
\r
1735 appData.firstProtocolVersion = PROTOVER;
\r
1736 appData.secondProtocolVersion = PROTOVER;
\r
1737 appData.showButtonBar = TRUE;
\r
1739 /* [AS] New properties (see comments in header file) */
1740 appData.firstScoreIsAbsolute = FALSE;
1741 appData.secondScoreIsAbsolute = FALSE;
1742 appData.saveExtendedInfoInPGN = FALSE;
1743 appData.hideThinkingFromHuman = FALSE;
1744 appData.liteBackTextureFile = "";
1745 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
1746 appData.darkBackTextureFile = "";
1747 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
1748 appData.renderPiecesWithFont = "";
1749 appData.fontToPieceTable = "";
1750 appData.fontBackColorWhite = 0;
1751 appData.fontForeColorWhite = 0;
1752 appData.fontBackColorBlack = 0;
1753 appData.fontForeColorBlack = 0;
1754 appData.fontPieceSize = 80;
1755 appData.overrideLineGap = 1;
1756 appData.adjudicateLossThreshold = 0;
1757 appData.delayBeforeQuit = 0;
1758 appData.delayAfterQuit = 0;
1759 appData.nameOfDebugFile = "winboard.debug";
1760 appData.pgnEventHeader = "Computer Chess Game";
1761 appData.defaultFrcPosition = -1;
1764 appData.zippyTalk = ZIPPY_TALK;
\r
1765 appData.zippyPlay = ZIPPY_PLAY;
\r
1766 appData.zippyLines = ZIPPY_LINES;
\r
1767 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1768 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1769 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1770 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1771 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1772 appData.zippyUseI = ZIPPY_USE_I;
\r
1773 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1774 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1775 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1776 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1777 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1778 appData.zippyAbort = ZIPPY_ABORT;
\r
1779 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1780 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1781 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1784 /* Point font array elements to structures and
\r
1785 parse default font names */
\r
1786 for (i=0; i<NUM_FONTS; i++) {
\r
1787 for (j=0; j<NUM_SIZES; j++) {
\r
1788 font[j][i] = &fontRec[j][i];
\r
1789 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1793 /* Parse default settings file if any */
\r
1794 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1795 settingsFileName = strdup(buf);
\r
1798 /* Parse command line */
\r
1799 ParseArgs(StringGet, &lpCmdLine);
\r
1801 /* Propagate options that affect others */
\r
1802 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1803 if (appData.icsActive || appData.noChessProgram) {
\r
1804 chessProgram = FALSE; /* not local chess program mode */
\r
1807 /* Open startup dialog if needed */
\r
1808 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1809 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1810 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1811 *appData.secondChessProgram == NULLCHAR))) {
\r
1814 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1815 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1816 FreeProcInstance(lpProc);
\r
1819 /* Make sure save files land in the right (?) directory */
\r
1820 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1821 appData.saveGameFile = strdup(buf);
\r
1823 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1824 appData.savePositionFile = strdup(buf);
\r
1827 /* Finish initialization for fonts and sounds */
\r
1828 for (i=0; i<NUM_FONTS; i++) {
\r
1829 for (j=0; j<NUM_SIZES; j++) {
\r
1830 CreateFontInMF(font[j][i]);
\r
1833 /* xboard, and older WinBoards, controlled the move sound with the
\r
1834 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1835 always turn the option on (so that the backend will call us),
\r
1836 then let the user turn the sound off by setting it to silence if
\r
1837 desired. To accommodate old winboard.ini files saved by old
\r
1838 versions of WinBoard, we also turn off the sound if the option
\r
1839 was initially set to false. */
\r
1840 if (!appData.ringBellAfterMoves) {
\r
1841 sounds[(int)SoundMove].name = strdup("");
\r
1842 appData.ringBellAfterMoves = TRUE;
\r
1844 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1845 SetCurrentDirectory(installDir);
\r
1847 SetCurrentDirectory(currDir);
\r
1849 p = icsTextMenuString;
\r
1850 if (p[0] == '@') {
\r
1851 FILE* f = fopen(p + 1, "r");
\r
1853 DisplayFatalError(p + 1, errno, 2);
\r
1856 i = fread(buf, 1, sizeof(buf)-1, f);
\r
1858 buf[i] = NULLCHAR;
\r
1861 ParseIcsTextMenu(strdup(p));
\r
1868 HMENU hmenu = GetMenu(hwndMain);
\r
1870 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1871 MF_BYCOMMAND|((appData.icsActive &&
\r
1872 *appData.icsCommPort != NULLCHAR) ?
\r
1873 MF_ENABLED : MF_GRAYED));
\r
1874 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1875 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1876 MF_CHECKED : MF_UNCHECKED));
\r
1881 SaveSettings(char* name)
\r
1884 ArgDescriptor *ad;
\r
1885 WINDOWPLACEMENT wp;
\r
1886 char dir[MSG_SIZ];
\r
1888 if (!hwndMain) return;
\r
1890 GetCurrentDirectory(MSG_SIZ, dir);
\r
1891 SetCurrentDirectory(installDir);
\r
1892 f = fopen(name, "w");
\r
1893 SetCurrentDirectory(dir);
\r
1895 DisplayError(name, errno);
\r
1898 fprintf(f, ";\n");
\r
1899 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
1900 fprintf(f, ";\n");
\r
1901 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
1902 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
1903 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
1904 fprintf(f, ";\n");
\r
1906 wp.length = sizeof(WINDOWPLACEMENT);
\r
1907 GetWindowPlacement(hwndMain, &wp);
\r
1908 boardX = wp.rcNormalPosition.left;
\r
1909 boardY = wp.rcNormalPosition.top;
\r
1911 if (hwndConsole) {
\r
1912 GetWindowPlacement(hwndConsole, &wp);
\r
1913 consoleX = wp.rcNormalPosition.left;
\r
1914 consoleY = wp.rcNormalPosition.top;
\r
1915 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1916 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1919 if (analysisDialog) {
\r
1920 GetWindowPlacement(analysisDialog, &wp);
\r
1921 analysisX = wp.rcNormalPosition.left;
\r
1922 analysisY = wp.rcNormalPosition.top;
\r
1923 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1924 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1927 if (commentDialog) {
\r
1928 GetWindowPlacement(commentDialog, &wp);
\r
1929 commentX = wp.rcNormalPosition.left;
\r
1930 commentY = wp.rcNormalPosition.top;
\r
1931 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1932 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1935 if (editTagsDialog) {
\r
1936 GetWindowPlacement(editTagsDialog, &wp);
\r
1937 editTagsX = wp.rcNormalPosition.left;
\r
1938 editTagsY = wp.rcNormalPosition.top;
\r
1939 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1940 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1943 if (gameListDialog) {
\r
1944 GetWindowPlacement(gameListDialog, &wp);
\r
1945 gameListX = wp.rcNormalPosition.left;
\r
1946 gameListY = wp.rcNormalPosition.top;
\r
1947 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1948 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1951 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
1952 if (!ad->save) continue;
\r
1953 switch (ad->argType) {
\r
1956 char *p = *(char **)ad->argLoc;
\r
1957 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
1958 /* Quote multiline values or \-containing values
\r
1959 with { } if possible */
\r
1960 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
1962 /* Else quote with " " */
\r
1963 fprintf(f, "/%s=\"", ad->argName);
\r
1965 if (*p == '\n') fprintf(f, "\n");
\r
1966 else if (*p == '\r') fprintf(f, "\\r");
\r
1967 else if (*p == '\t') fprintf(f, "\\t");
\r
1968 else if (*p == '\b') fprintf(f, "\\b");
\r
1969 else if (*p == '\f') fprintf(f, "\\f");
\r
1970 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
1971 else if (*p == '\"') fprintf(f, "\\\"");
\r
1972 else if (*p == '\\') fprintf(f, "\\\\");
\r
1976 fprintf(f, "\"\n");
\r
1981 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
1984 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
1987 fprintf(f, "/%s=%s\n", ad->argName,
\r
1988 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
1991 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1994 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1998 COLORREF color = *(COLORREF *)ad->argLoc;
\r
1999 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2000 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2005 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2006 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2007 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2008 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2009 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2010 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2011 (ta->effects) ? " " : "",
\r
2012 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2016 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2017 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2019 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2022 case ArgBoardSize:
\r
2023 fprintf(f, "/%s=%s\n", ad->argName,
\r
2024 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2029 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2030 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2031 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2032 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2033 ad->argName, mfp->faceName, mfp->pointSize,
\r
2034 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2035 mfp->bold ? "b" : "",
\r
2036 mfp->italic ? "i" : "",
\r
2037 mfp->underline ? "u" : "",
\r
2038 mfp->strikeout ? "s" : "");
\r
2042 case ArgCommSettings:
\r
2043 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2051 /*---------------------------------------------------------------------------*\
\r
2053 * GDI board drawing routines
\r
2055 \*---------------------------------------------------------------------------*/
\r
2057 /* [AS] Draw square using background texture */
2058 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
2063 return; /* Should never happen! */
2066 SetGraphicsMode( dst, GM_ADVANCED );
2078 x.eDx = (FLOAT) dw + dx - 1;
2081 SetWorldTransform( dst, &x );
2090 x.eDy = (FLOAT) dh + dy - 1;
2092 SetWorldTransform( dst, &x );
2104 SetWorldTransform( dst, &x );
2108 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
2116 SetWorldTransform( dst, &x );
2118 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
2137 static HFONT hPieceFont = NULL;
2138 static HBITMAP hPieceMask[12];
2139 static HBITMAP hPieceFace[12];
2140 static int fontBitmapSquareSize = 0;
2141 static char pieceToFontChar[12] = { 'p', 'n', 'b', 'r', 'q', 'k', 'o', 'm', 'v', 't', 'w', 'l' };
2143 static BOOL SetPieceToFontCharTable( const char * map )
2145 BOOL result = FALSE;
2147 if( map != NULL && strlen(map) == 12 ) {
2150 for( i=0; i<12; i++ ) {
2151 pieceToFontChar[i] = map[i];
2160 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
2163 BYTE r1 = GetRValue( color );
2164 BYTE g1 = GetGValue( color );
2165 BYTE b1 = GetBValue( color );
2171 /* Create a uniform background first */
2172 hbrush = CreateSolidBrush( color );
2173 SetRect( &rc, 0, 0, squareSize, squareSize );
2174 FillRect( hdc, &rc, hbrush );
2175 DeleteObject( hbrush );
2178 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
2179 int steps = squareSize / 2;
2182 for( i=0; i<steps; i++ ) {
2183 BYTE r = r1 - (r1-r2) * i / steps;
2184 BYTE g = g1 - (g1-g2) * i / steps;
2185 BYTE b = b1 - (b1-b2) * i / steps;
2187 hbrush = CreateSolidBrush( RGB(r,g,b) );
2188 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
2189 FillRect( hdc, &rc, hbrush );
2190 DeleteObject(hbrush);
2193 else if( mode == 2 ) {
2194 /* Diagonal gradient, good more or less for every piece */
2196 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
2198 int steps = squareSize;
2201 triangle[0].x = squareSize - steps;
2202 triangle[0].y = squareSize;
2203 triangle[1].x = squareSize;
2204 triangle[1].y = squareSize;
2205 triangle[2].x = squareSize;
2206 triangle[2].y = squareSize - steps;
2208 for( i=0; i<steps; i++ ) {
2209 BYTE r = r1 - (r1-r2) * i / steps;
2210 BYTE g = g1 - (g1-g2) * i / steps;
2211 BYTE b = b1 - (b1-b2) * i / steps;
2213 hbrush = CreateSolidBrush( RGB(r,g,b) );
2214 hbrush_old = SelectObject( hdc, hbrush );
2215 Polygon( hdc, triangle, 3 );
2216 SelectObject( hdc, hbrush_old );
2217 DeleteObject(hbrush);
2222 SelectObject( hdc, hpen );
2227 [AS] The method I use to create the bitmaps it a bit tricky, but it
2228 seems to work ok. The main problem here is to find the "inside" of a chess
2229 piece: follow the steps as explained below.
2231 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
2235 COLORREF chroma = RGB(0xFF,0x00,0xFF);
2239 int backColor = whitePieceColor;
2240 int foreColor = blackPieceColor;
2241 int shapeIndex = index < 6 ? index+6 : index;
2243 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
2244 backColor = appData.fontBackColorWhite;
2245 foreColor = appData.fontForeColorWhite;
2247 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
2248 backColor = appData.fontBackColorBlack;
2249 foreColor = appData.fontForeColorBlack;
2253 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2255 hbm_old = SelectObject( hdc, hbm );
2259 rc.right = squareSize;
2260 rc.bottom = squareSize;
2262 /* Step 1: background is now black */
2263 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
2265 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
2267 pt.x = (squareSize - sz.cx) / 2;
2268 pt.y = (squareSize - sz.cy) / 2;
2270 SetBkMode( hdc, TRANSPARENT );
2271 SetTextColor( hdc, chroma );
2272 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
2273 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2275 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
2276 /* Step 3: the area outside the piece is filled with white */
2277 FloodFill( hdc, 0, 0, chroma );
2278 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
2280 Step 4: this is the tricky part, the area inside the piece is filled with black,
2281 but if the start point is not inside the piece we're lost!
2282 There should be a better way to do this... if we could create a region or path
2283 from the fill operation we would be fine for example.
2285 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
2287 SetTextColor( hdc, 0 );
2289 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
2290 draw the piece again in black for safety.
2292 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2294 SelectObject( hdc, hbm_old );
2296 if( hPieceMask[index] != NULL ) {
2297 DeleteObject( hPieceMask[index] );
2300 hPieceMask[index] = hbm;
2303 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2305 SelectObject( hdc, hbm );
2308 HDC dc1 = CreateCompatibleDC( hdc_window );
2309 HDC dc2 = CreateCompatibleDC( hdc_window );
2310 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2312 SelectObject( dc1, hPieceMask[index] );
2313 SelectObject( dc2, bm2 );
2314 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
2315 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
2318 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
2319 the piece background and deletes (makes transparent) the rest.
2320 Thanks to that mask, we are free to paint the background with the greates
2321 freedom, as we'll be able to mask off the unwanted parts when finished.
2322 We use this, to make gradients and give the pieces a "roundish" look.
2324 SetPieceBackground( hdc, backColor, 2 );
2325 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
2329 DeleteObject( bm2 );
2332 SetTextColor( hdc, foreColor );
2333 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2335 SelectObject( hdc, hbm_old );
2337 hPieceFace[index] = hbm;
2340 static int TranslatePieceToFontPiece( int piece )
2372 void CreatePiecesFromFont()
2375 HDC hdc_window = NULL;
2381 if( fontBitmapSquareSize < 0 ) {
2382 /* Something went seriously wrong in the past: do not try to recreate fonts! */
2386 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
2387 fontBitmapSquareSize = -1;
2391 if( fontBitmapSquareSize != squareSize ) {
2392 hdc_window = GetDC( hwndMain );
2393 hdc = CreateCompatibleDC( hdc_window );
2395 if( hPieceFont != NULL ) {
2396 DeleteObject( hPieceFont );
2399 for( i=0; i<12; i++ ) {
2400 hPieceMask[i] = NULL;
2406 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
2407 fontHeight = appData.fontPieceSize;
2410 fontHeight = (fontHeight * squareSize) / 100;
2412 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
2414 lf.lfEscapement = 0;
2415 lf.lfOrientation = 0;
2416 lf.lfWeight = FW_NORMAL;
2420 lf.lfCharSet = DEFAULT_CHARSET;
2421 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
2422 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2423 lf.lfQuality = PROOF_QUALITY;
2424 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
2425 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
2426 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
2428 hPieceFont = CreateFontIndirect( &lf );
2430 if( hPieceFont == NULL ) {
2431 fontBitmapSquareSize = -2;
2434 /* Setup font-to-piece character table */
2435 if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) {
2436 /* No (or wrong) global settings, try to detect the font */
2437 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
2439 SetPieceToFontCharTable("phbrqkojntwl");
2441 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
2442 /* DiagramTT* family */
2443 SetPieceToFontCharTable("PNLRQKpnlrqk");
2446 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
2447 SetPieceToFontCharTable("pnbrqkomvtwl");
2451 /* Create bitmaps */
2452 hfont_old = SelectObject( hdc, hPieceFont );
2454 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
2455 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
2456 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
2457 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
2458 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
2459 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
2460 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
2461 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
2462 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
2463 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
2464 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
2465 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
2467 SelectObject( hdc, hfont_old );
2469 fontBitmapSquareSize = squareSize;
2477 if( hdc_window != NULL ) {
2478 ReleaseDC( hwndMain, hdc_window );
2483 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2487 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2488 if (gameInfo.event &&
\r
2489 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2490 strcmp(name, "k80s") == 0) {
\r
2491 strcpy(name, "tim");
\r
2493 return LoadBitmap(hinst, name);
\r
2497 /* Insert a color into the program's logical palette
\r
2498 structure. This code assumes the given color is
\r
2499 the result of the RGB or PALETTERGB macro, and it
\r
2500 knows how those macros work (which is documented).
\r
2503 InsertInPalette(COLORREF color)
\r
2505 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2507 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2508 DisplayFatalError("Too many colors", 0, 1);
\r
2509 pLogPal->palNumEntries--;
\r
2513 pe->peFlags = (char) 0;
\r
2514 pe->peRed = (char) (0xFF & color);
\r
2515 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2516 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2522 InitDrawingColors()
\r
2524 if (pLogPal == NULL) {
\r
2525 /* Allocate enough memory for a logical palette with
\r
2526 * PALETTESIZE entries and set the size and version fields
\r
2527 * of the logical palette structure.
\r
2529 pLogPal = (NPLOGPALETTE)
\r
2530 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2531 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2532 pLogPal->palVersion = 0x300;
\r
2534 pLogPal->palNumEntries = 0;
\r
2536 InsertInPalette(lightSquareColor);
\r
2537 InsertInPalette(darkSquareColor);
\r
2538 InsertInPalette(whitePieceColor);
\r
2539 InsertInPalette(blackPieceColor);
\r
2540 InsertInPalette(highlightSquareColor);
\r
2541 InsertInPalette(premoveHighlightColor);
\r
2543 /* create a logical color palette according the information
\r
2544 * in the LOGPALETTE structure.
\r
2546 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2548 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2549 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2550 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2551 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2552 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2554 /* [AS] Force rendering of the font-based pieces */
2555 if( fontBitmapSquareSize > 0 ) {
2556 fontBitmapSquareSize = 0;
2562 BoardWidth(int boardSize)
\r
2564 int lineGap = sizeInfo[boardSize].lineGap;
2566 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
2567 lineGap = appData.overrideLineGap;
2570 return (BOARD_SIZE + 1) * lineGap +
2571 BOARD_SIZE * sizeInfo[boardSize].squareSize;
\r
2574 /* Respond to board resize by dragging edge */
\r
2576 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2578 BoardSize newSize = NUM_SIZES - 1;
\r
2579 static int recurse = 0;
\r
2580 if (IsIconic(hwndMain)) return;
\r
2581 if (recurse > 0) return;
\r
2583 while (newSize > 0 &&
\r
2584 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2585 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2588 boardSize = newSize;
\r
2589 InitDrawingSizes(boardSize, flags);
\r
2596 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2598 int i, boardWidth;
\r
2599 ChessSquare piece;
\r
2600 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2602 SIZE clockSize, messageSize;
\r
2604 char buf[MSG_SIZ];
\r
2606 HMENU hmenu = GetMenu(hwndMain);
\r
2607 RECT crect, wrect;
\r
2609 LOGBRUSH logbrush;
\r
2611 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2612 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2613 squareSize = sizeInfo[boardSize].squareSize;
\r
2614 lineGap = sizeInfo[boardSize].lineGap;
\r
2616 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
2617 lineGap = appData.overrideLineGap;
2620 if (tinyLayout != oldTinyLayout) {
\r
2621 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2623 style &= ~WS_SYSMENU;
\r
2624 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2625 "&Minimize\tCtrl+F4");
\r
2627 style |= WS_SYSMENU;
\r
2628 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2630 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2632 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2633 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2634 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2636 DrawMenuBar(hwndMain);
\r
2639 boardWidth = BoardWidth(boardSize);
\r
2641 /* Get text area sizes */
\r
2642 hdc = GetDC(hwndMain);
\r
2643 if (appData.clockMode) {
\r
2644 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2646 sprintf(buf, "White");
\r
2648 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2649 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2650 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2651 str = "We only care about the height here";
\r
2652 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2653 SelectObject(hdc, oldFont);
\r
2654 ReleaseDC(hwndMain, hdc);
\r
2656 /* Compute where everything goes */
\r
2657 whiteRect.left = OUTER_MARGIN;
\r
2658 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2659 whiteRect.top = OUTER_MARGIN;
\r
2660 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2662 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2663 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2664 blackRect.top = whiteRect.top;
\r
2665 blackRect.bottom = whiteRect.bottom;
\r
2667 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2668 if (appData.showButtonBar) {
\r
2669 messageRect.right = blackRect.right
\r
2670 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2672 messageRect.right = blackRect.right;
\r
2674 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2675 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2677 boardRect.left = whiteRect.left;
\r
2678 boardRect.right = boardRect.left + boardWidth;
\r
2679 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2680 boardRect.bottom = boardRect.top + boardWidth;
\r
2682 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2683 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2684 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2685 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2686 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2687 GetWindowRect(hwndMain, &wrect);
\r
2688 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2689 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2690 /* compensate if menu bar wrapped */
\r
2691 GetClientRect(hwndMain, &crect);
\r
2692 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2693 winHeight += offby;
\r
2695 case WMSZ_TOPLEFT:
\r
2696 SetWindowPos(hwndMain, NULL,
\r
2697 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2698 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2701 case WMSZ_TOPRIGHT:
\r
2703 SetWindowPos(hwndMain, NULL,
\r
2704 wrect.left, wrect.bottom - winHeight,
\r
2705 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2708 case WMSZ_BOTTOMLEFT:
\r
2710 SetWindowPos(hwndMain, NULL,
\r
2711 wrect.right - winWidth, wrect.top,
\r
2712 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2715 case WMSZ_BOTTOMRIGHT:
\r
2719 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2720 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2725 for (i = 0; i < N_BUTTONS; i++) {
\r
2726 if (buttonDesc[i].hwnd != NULL) {
\r
2727 DestroyWindow(buttonDesc[i].hwnd);
\r
2728 buttonDesc[i].hwnd = NULL;
\r
2730 if (appData.showButtonBar) {
\r
2731 buttonDesc[i].hwnd =
\r
2732 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2733 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2734 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2735 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2736 (HMENU) buttonDesc[i].id,
\r
2737 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2739 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2740 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2741 MAKELPARAM(FALSE, 0));
\r
2743 if (buttonDesc[i].id == IDM_Pause)
\r
2744 hwndPause = buttonDesc[i].hwnd;
\r
2745 buttonDesc[i].wndproc = (WNDPROC)
\r
2746 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2749 if (gridPen != NULL) DeleteObject(gridPen);
\r
2750 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2751 if (premovePen != NULL) DeleteObject(premovePen);
\r
2752 if (lineGap != 0) {
\r
2753 logbrush.lbStyle = BS_SOLID;
\r
2754 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2756 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2757 lineGap, &logbrush, 0, NULL);
\r
2758 logbrush.lbColor = highlightSquareColor;
\r
2760 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2761 lineGap, &logbrush, 0, NULL);
\r
2763 logbrush.lbColor = premoveHighlightColor;
\r
2765 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2766 lineGap, &logbrush, 0, NULL);
\r
2768 for (i = 0; i < BOARD_SIZE + 1; i++) {
\r
2769 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2770 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2;
\r
2771 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2772 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2773 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2774 BOARD_SIZE * (squareSize + lineGap);
\r
2775 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x =
\r
2776 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left +
\r
2777 lineGap / 2 + (i * (squareSize + lineGap));
\r
2778 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y =
\r
2779 boardRect.top + BOARD_SIZE * (squareSize + lineGap);
\r
2780 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2784 if (boardSize == oldBoardSize) return;
\r
2785 oldBoardSize = boardSize;
\r
2786 oldTinyLayout = tinyLayout;
\r
2788 /* Load piece bitmaps for this board size */
\r
2789 for (i=0; i<=2; i++) {
\r
2790 for (piece = WhitePawn;
\r
2791 (int) piece <= (int) WhiteKing;
\r
2792 piece = (ChessSquare) ((int) piece + 1)) {
\r
2793 if (pieceBitmap[i][piece] != NULL)
\r
2794 DeleteObject(pieceBitmap[i][piece]);
\r
2798 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2799 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2800 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2801 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2802 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2803 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2804 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2805 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2806 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2807 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2808 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2809 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2810 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2811 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2812 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2813 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2814 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2815 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2820 PieceBitmap(ChessSquare p, int kind)
\r
2822 if ((int) p >= (int) BlackPawn)
\r
2823 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2825 return pieceBitmap[kind][(int) p];
\r
2828 /***************************************************************/
\r
2830 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2831 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2833 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2834 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2838 SquareToPos(int row, int column, int * x, int * y)
\r
2841 *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
2842 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2844 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2845 *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
2850 DrawCoordsOnDC(HDC hdc)
\r
2852 static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'};
\r
2853 static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'};
\r
2854 char str[2] = { NULLCHAR, NULLCHAR };
\r
2855 int oldMode, oldAlign, x, y, start, i;
\r
2859 if (!appData.showCoords)
\r
2862 start = flipView ? 0 : 8;
\r
2864 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2865 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2866 oldAlign = GetTextAlign(hdc);
\r
2867 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2869 y = boardRect.top + lineGap;
\r
2870 x = boardRect.left + lineGap;
\r
2872 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2873 for (i = 0; i < 8; i++) {
\r
2874 str[0] = files[start + i];
\r
2875 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2876 y += squareSize + lineGap;
\r
2879 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2880 for (i = 0; i < 8; i++) {
\r
2881 str[0] = ranks[start + i];
\r
2882 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2883 x += squareSize + lineGap;
\r
2886 SelectObject(hdc, oldBrush);
\r
2887 SetBkMode(hdc, oldMode);
\r
2888 SetTextAlign(hdc, oldAlign);
\r
2889 SelectObject(hdc, oldFont);
\r
2893 DrawGridOnDC(HDC hdc)
\r
2897 if (lineGap != 0) {
\r
2898 oldPen = SelectObject(hdc, gridPen);
\r
2899 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2);
\r
2900 SelectObject(hdc, oldPen);
\r
2904 #define HIGHLIGHT_PEN 0
\r
2905 #define PREMOVE_PEN 1
\r
2908 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2911 HPEN oldPen, hPen;
\r
2912 if (lineGap == 0) return;
\r
2914 x1 = boardRect.left +
\r
2915 lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap);
\r
2916 y1 = boardRect.top +
\r
2917 lineGap/2 + y * (squareSize + lineGap);
\r
2919 x1 = boardRect.left +
\r
2920 lineGap/2 + x * (squareSize + lineGap);
\r
2921 y1 = boardRect.top +
\r
2922 lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap);
\r
2924 hPen = pen ? premovePen : highlightPen;
\r
2925 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2926 MoveToEx(hdc, x1, y1, NULL);
\r
2927 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2928 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2929 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2930 LineTo(hdc, x1, y1);
\r
2931 SelectObject(hdc, oldPen);
\r
2935 DrawHighlightsOnDC(HDC hdc)
\r
2938 for (i=0; i<2; i++) {
\r
2939 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
2940 DrawHighlightOnDC(hdc, TRUE,
\r
2941 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
2944 for (i=0; i<2; i++) {
\r
2945 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2946 premoveHighlightInfo.sq[i].y >= 0) {
\r
2947 DrawHighlightOnDC(hdc, TRUE,
\r
2948 premoveHighlightInfo.sq[i].x,
\r
2949 premoveHighlightInfo.sq[i].y,
\r
2955 /* Note: sqcolor is used only in monoMode */
\r
2956 /* Note that this code is largely duplicated in woptions.c,
\r
2957 function DrawSampleSquare, so that needs to be updated too */
\r
2959 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2961 HBITMAP oldBitmap;
\r
2964 if (appData.blindfold) return;
\r
2966 /* [AS] Use font-based pieces if needed */
2967 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
2968 /* Create piece bitmaps, or do nothing if piece set is up to data */
2969 CreatePiecesFromFont();
2971 if( fontBitmapSquareSize == squareSize ) {
2972 int index = TranslatePieceToFontPiece( piece );
2974 SelectObject( tmphdc, hPieceMask[ index ] );
2978 squareSize, squareSize,
2983 SelectObject( tmphdc, hPieceFace[ index ] );
2987 squareSize, squareSize,
2996 if (appData.monoMode) {
\r
2997 SelectObject(tmphdc, PieceBitmap(piece,
\r
2998 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2999 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3000 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3003 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3004 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3005 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3007 /* Use black piece color for outline of white pieces */
\r
3008 /* Not sure this looks really good (though xboard does it).
\r
3009 Maybe better to have another selectable color, default black */
\r
3010 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3011 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3012 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3014 /* Use black for outline of white pieces */
\r
3015 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3016 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
3020 /* Use white piece color for details of black pieces */
\r
3021 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3022 WHITE_PIECE ones aren't always the right shape. */
\r
3023 /* Not sure this looks really good (though xboard does it).
\r
3024 Maybe better to have another selectable color, default medium gray? */
\r
3025 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3026 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3027 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3028 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3029 SelectObject(hdc, blackPieceBrush);
\r
3030 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3032 /* Use square color for details of black pieces */
\r
3033 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3034 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3035 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3038 SelectObject(hdc, oldBrush);
\r
3039 SelectObject(tmphdc, oldBitmap);
\r
3043 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
3044 int GetBackTextureMode( int algo )
3046 int result = BACK_TEXTURE_MODE_DISABLED;
3050 case BACK_TEXTURE_MODE_PLAIN:
3051 result = 1; /* Always use identity map */
3053 case BACK_TEXTURE_MODE_FULL_RANDOM:
3054 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
3062 [AS] Compute and save texture drawing info, otherwise we may not be able
3063 to handle redraws cleanly (as random numbers would always be different).
3065 VOID RebuildTextureSquareInfo()
3075 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
3077 if( liteBackTexture != NULL ) {
3078 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
3079 lite_w = bi.bmWidth;
3080 lite_h = bi.bmHeight;
3084 if( darkBackTexture != NULL ) {
3085 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
3086 dark_w = bi.bmWidth;
3087 dark_h = bi.bmHeight;
3091 for( row=0; row<BOARD_SIZE; row++ ) {
3092 for( col=0; col<BOARD_SIZE; col++ ) {
3093 if( (col + row) & 1 ) {
3095 if( lite_w >= squareSize && lite_h >= squareSize ) {
3096 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_SIZE;
3097 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_SIZE;
3098 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
3103 if( dark_w >= squareSize && dark_h >= squareSize ) {
3104 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_SIZE;
3105 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_SIZE;
3106 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
3114 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3116 int row, column, x, y, square_color, piece_color;
\r
3117 ChessSquare piece;
\r
3119 HDC texture_hdc = NULL;
3121 /* [AS] Initialize background textures if needed */
3122 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
3123 if( backTextureSquareSize != squareSize ) {
3124 backTextureSquareSize = squareSize;
3125 RebuildTextureSquareInfo();
3128 texture_hdc = CreateCompatibleDC( hdc );
3131 for (row = 0; row < BOARD_SIZE; row++) {
\r
3132 for (column = 0; column < BOARD_SIZE; column++) {
\r
3134 SquareToPos(row, column, &x, &y);
\r
3136 piece = board[row][column];
\r
3138 square_color = ((column + row) % 2) == 1;
\r
3139 piece_color = (int) piece < (int) BlackPawn;
\r
3141 if (appData.monoMode) {
\r
3142 if (piece == EmptySquare) {
\r
3143 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3144 square_color ? WHITENESS : BLACKNESS);
\r
3146 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3149 else if( backTextureSquareInfo[row][column].mode > 0 ) {
3150 /* [AS] Draw the square using a texture bitmap */
3151 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
3154 squareSize, squareSize,
3157 backTextureSquareInfo[row][column].mode,
3158 backTextureSquareInfo[row][column].x,
3159 backTextureSquareInfo[row][column].y );
3161 SelectObject( texture_hdc, hbm );
3163 if (piece != EmptySquare) {
3164 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
3168 oldBrush = SelectObject(hdc, square_color ?
\r
3169 lightSquareBrush : darkSquareBrush);
\r
3170 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3171 SelectObject(hdc, oldBrush);
\r
3172 if (piece != EmptySquare)
\r
3173 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3178 if( texture_hdc != NULL ) {
3179 DeleteDC( texture_hdc );
3183 #define MAX_CLIPS 200 /* more than enough */
\r
3186 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3188 static Board lastReq, lastDrawn;
\r
3189 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3190 static int lastDrawnFlipView = 0;
\r
3191 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3192 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3195 HBITMAP bufferBitmap;
\r
3196 HBITMAP oldBitmap;
\r
3198 HRGN clips[MAX_CLIPS];
\r
3199 ChessSquare dragged_piece = EmptySquare;
\r
3201 /* I'm undecided on this - this function figures out whether a full
\r
3202 * repaint is necessary on its own, so there's no real reason to have the
\r
3203 * caller tell it that. I think this can safely be set to FALSE - but
\r
3204 * if we trust the callers not to request full repaints unnessesarily, then
\r
3205 * we could skip some clipping work. In other words, only request a full
\r
3206 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3207 * gamestart and similar) --Hawk
\r
3209 Boolean fullrepaint = repaint;
\r
3211 if (board == NULL) {
\r
3212 if (!lastReqValid) {
\r
3217 CopyBoard(lastReq, board);
\r
3221 if (doingSizing) {
\r
3225 if (IsIconic(hwndMain)) {
\r
3229 if (hdc == NULL) {
\r
3230 hdc = GetDC(hwndMain);
\r
3231 if (!appData.monoMode) {
\r
3232 SelectPalette(hdc, hPal, FALSE);
\r
3233 RealizePalette(hdc);
\r
3237 releaseDC = FALSE;
\r
3241 fprintf(debugFP, "*******************************\n"
\r
3243 "dragInfo.from (%d,%d)\n"
\r
3244 "dragInfo.start (%d,%d)\n"
\r
3245 "dragInfo.pos (%d,%d)\n"
\r
3246 "dragInfo.lastpos (%d,%d)\n",
\r
3247 repaint ? "TRUE" : "FALSE",
\r
3248 dragInfo.from.x, dragInfo.from.y,
\r
3249 dragInfo.start.x, dragInfo.start.y,
\r
3250 dragInfo.pos.x, dragInfo.pos.y,
\r
3251 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
3252 fprintf(debugFP, "prev: ");
\r
3253 for (row = 0; row < 8; row++) {
\r
3254 for (column = 0; column < 8; column++) {
\r
3255 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
3258 fprintf(debugFP, "\n");
\r
3259 fprintf(debugFP, "board: ");
\r
3260 for (row = 0; row < 8; row++) {
\r
3261 for (column = 0; column < 8; column++) {
\r
3262 fprintf(debugFP, "%d ", board[row][column]);
\r
3265 fprintf(debugFP, "\n");
\r
3269 /* Create some work-DCs */
\r
3270 hdcmem = CreateCompatibleDC(hdc);
\r
3271 tmphdc = CreateCompatibleDC(hdc);
\r
3273 /* Figure out which squares need updating by comparing the
\r
3274 * newest board with the last drawn board and checking if
\r
3275 * flipping has changed.
\r
3277 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3278 for (row = 0; row < 8; row++) {
\r
3279 for (column = 0; column < 8; column++) {
\r
3280 if (lastDrawn[row][column] != board[row][column]) {
\r
3281 SquareToPos(row, column, &x, &y);
\r
3282 clips[num_clips++] =
\r
3283 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3287 for (i=0; i<2; i++) {
\r
3288 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3289 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3290 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3291 lastDrawnHighlight.sq[i].y >= 0) {
\r
3292 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3293 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3294 clips[num_clips++] =
\r
3295 CreateRectRgn(x - lineGap, y - lineGap,
\r
3296 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3298 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3299 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3300 clips[num_clips++] =
\r
3301 CreateRectRgn(x - lineGap, y - lineGap,
\r
3302 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3306 for (i=0; i<2; i++) {
\r
3307 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3308 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3309 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3310 lastDrawnPremove.sq[i].y >= 0) {
\r
3311 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3312 lastDrawnPremove.sq[i].x, &x, &y);
\r
3313 clips[num_clips++] =
\r
3314 CreateRectRgn(x - lineGap, y - lineGap,
\r
3315 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3317 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3318 premoveHighlightInfo.sq[i].y >= 0) {
\r
3319 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3320 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3321 clips[num_clips++] =
\r
3322 CreateRectRgn(x - lineGap, y - lineGap,
\r
3323 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3328 fullrepaint = TRUE;
\r
3331 /* Create a buffer bitmap - this is the actual bitmap
\r
3332 * being written to. When all the work is done, we can
\r
3333 * copy it to the real DC (the screen). This avoids
\r
3334 * the problems with flickering.
\r
3336 GetClientRect(hwndMain, &Rect);
\r
3337 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3338 Rect.bottom-Rect.top+1);
\r
3339 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3340 if (!appData.monoMode) {
\r
3341 SelectPalette(hdcmem, hPal, FALSE);
\r
3344 /* Create clips for dragging */
\r
3345 if (!fullrepaint) {
\r
3346 if (dragInfo.from.x >= 0) {
\r
3347 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3348 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3350 if (dragInfo.start.x >= 0) {
\r
3351 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3352 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3354 if (dragInfo.pos.x >= 0) {
\r
3355 x = dragInfo.pos.x - squareSize / 2;
\r
3356 y = dragInfo.pos.y - squareSize / 2;
\r
3357 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3359 if (dragInfo.lastpos.x >= 0) {
\r
3360 x = dragInfo.lastpos.x - squareSize / 2;
\r
3361 y = dragInfo.lastpos.y - squareSize / 2;
\r
3362 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3366 /* If dragging is in progress, we temporarely remove the piece */
\r
3367 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3368 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3369 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3372 /* Are we animating a move?
\r
3374 * - remove the piece from the board (temporarely)
\r
3375 * - calculate the clipping region
\r
3377 if (!fullrepaint) {
\r
3378 if (animInfo.piece != EmptySquare) {
\r
3379 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3380 x = boardRect.left + animInfo.lastpos.x;
\r
3381 y = boardRect.top + animInfo.lastpos.y;
\r
3382 x2 = boardRect.left + animInfo.pos.x;
\r
3383 y2 = boardRect.top + animInfo.pos.y;
\r
3384 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3385 /* Slight kludge. The real problem is that after AnimateMove is
\r
3386 done, the position on the screen does not match lastDrawn.
\r
3387 This currently causes trouble only on e.p. captures in
\r
3388 atomic, where the piece moves to an empty square and then
\r
3389 explodes. The old and new positions both had an empty square
\r
3390 at the destination, but animation has drawn a piece there and
\r
3391 we have to remember to erase it. */
\r
3392 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3396 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3397 if (num_clips == 0)
\r
3398 fullrepaint = TRUE;
\r
3400 /* Set clipping on the memory DC */
\r
3401 if (!fullrepaint) {
\r
3402 SelectClipRgn(hdcmem, clips[0]);
\r
3403 for (x = 1; x < num_clips; x++) {
\r
3404 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3405 abort(); // this should never ever happen!
\r
3409 /* Do all the drawing to the memory DC */
\r
3410 DrawGridOnDC(hdcmem);
\r
3411 DrawHighlightsOnDC(hdcmem);
\r
3412 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3413 DrawCoordsOnDC(hdcmem);
\r
3415 /* Put the dragged piece back into place and draw it */
\r
3416 if (dragged_piece != EmptySquare) {
\r
3417 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3418 x = dragInfo.pos.x - squareSize / 2;
\r
3419 y = dragInfo.pos.y - squareSize / 2;
\r
3420 DrawPieceOnDC(hdcmem, dragged_piece,
\r
3421 ((int) dragged_piece < (int) BlackPawn),
\r
3422 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3425 /* Put the animated piece back into place and draw it */
\r
3426 if (animInfo.piece != EmptySquare) {
\r
3427 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3428 x = boardRect.left + animInfo.pos.x;
\r
3429 y = boardRect.top + animInfo.pos.y;
\r
3430 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3431 ((int) animInfo.piece < (int) BlackPawn),
\r
3432 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3435 /* Release the bufferBitmap by selecting in the old bitmap
\r
3436 * and delete the memory DC
\r
3438 SelectObject(hdcmem, oldBitmap);
\r
3441 /* Set clipping on the target DC */
\r
3442 if (!fullrepaint) {
\r
3443 SelectClipRgn(hdc, clips[0]);
\r
3444 for (x = 1; x < num_clips; x++) {
\r
3445 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3446 abort(); // this should never ever happen!
\r
3450 /* Copy the new bitmap onto the screen in one go.
\r
3451 * This way we avoid any flickering
\r
3453 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3454 BitBlt(hdc, boardRect.left, boardRect.top,
\r
3455 boardRect.right - boardRect.left,
\r
3456 boardRect.bottom - boardRect.top,
\r
3457 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3458 SelectObject(tmphdc, oldBitmap);
\r
3460 /* Massive cleanup */
\r
3461 for (x = 0; x < num_clips; x++)
\r
3462 DeleteObject(clips[x]);
\r
3465 DeleteObject(bufferBitmap);
\r
3468 ReleaseDC(hwndMain, hdc);
\r
3470 if (lastDrawnFlipView != flipView) {
\r
3472 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
3474 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
3477 CopyBoard(lastDrawn, board);
\r
3478 lastDrawnHighlight = highlightInfo;
\r
3479 lastDrawnPremove = premoveHighlightInfo;
\r
3480 lastDrawnFlipView = flipView;
\r
3481 lastDrawnValid = 1;
\r
3485 /*---------------------------------------------------------------------------*\
\r
3486 | CLIENT PAINT PROCEDURE
\r
3487 | This is the main event-handler for the WM_PAINT message.
\r
3489 \*---------------------------------------------------------------------------*/
\r
3491 PaintProc(HWND hwnd)
\r
3497 if(hdc = BeginPaint(hwnd, &ps)) {
\r
3498 if (IsIconic(hwnd)) {
\r
3499 DrawIcon(hdc, 2, 2, iconCurrent);
\r
3501 if (!appData.monoMode) {
\r
3502 SelectPalette(hdc, hPal, FALSE);
\r
3503 RealizePalette(hdc);
\r
3505 HDCDrawPosition(hdc, 1, NULL);
\r
3507 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3508 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
3509 ETO_CLIPPED|ETO_OPAQUE,
\r
3510 &messageRect, messageText, strlen(messageText), NULL);
\r
3511 SelectObject(hdc, oldFont);
\r
3512 DisplayBothClocks();
\r
3514 EndPaint(hwnd,&ps);
\r
3522 * If the user selects on a border boundary, return -1; if off the board,
\r
3523 * return -2. Otherwise map the event coordinate to the square.
\r
3524 * The offset boardRect.left or boardRect.top must already have been
\r
3525 * subtracted from x.
\r
3528 EventToSquare(int x)
\r
3535 if ((x % (squareSize + lineGap)) >= squareSize)
\r
3537 x /= (squareSize + lineGap);
\r
3538 if (x >= BOARD_SIZE)
\r
3549 DropEnable dropEnables[] = {
\r
3550 { 'P', DP_Pawn, "Pawn" },
\r
3551 { 'N', DP_Knight, "Knight" },
\r
3552 { 'B', DP_Bishop, "Bishop" },
\r
3553 { 'R', DP_Rook, "Rook" },
\r
3554 { 'Q', DP_Queen, "Queen" },
\r
3558 SetupDropMenu(HMENU hmenu)
\r
3560 int i, count, enable;
\r
3562 extern char white_holding[], black_holding[];
\r
3563 char item[MSG_SIZ];
\r
3565 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
3566 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
3567 dropEnables[i].piece);
\r
3569 while (p && *p++ == dropEnables[i].piece) count++;
\r
3570 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
3571 enable = count > 0 || !appData.testLegality
\r
3572 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
3573 && !appData.icsActive);
\r
3574 ModifyMenu(hmenu, dropEnables[i].command,
\r
3575 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
3576 dropEnables[i].command, item);
\r
3580 static int fromX = -1, fromY = -1, toX, toY;
\r
3582 /* Event handler for mouse messages */
\r
3584 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3588 static int recursive = 0;
\r
3590 BOOLEAN saveAnimate;
\r
3591 static BOOLEAN sameAgain = FALSE;
\r
3594 if (message == WM_MBUTTONUP) {
\r
3595 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
3596 to the middle button: we simulate pressing the left button too!
\r
3598 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
3599 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
3605 pt.x = LOWORD(lParam);
\r
3606 pt.y = HIWORD(lParam);
\r
3607 x = EventToSquare(pt.x - boardRect.left);
\r
3608 y = EventToSquare(pt.y - boardRect.top);
\r
3609 if (!flipView && y >= 0) {
\r
3610 y = BOARD_SIZE - 1 - y;
\r
3612 if (flipView && x >= 0) {
\r
3613 x = BOARD_SIZE - 1 - x;
\r
3616 switch (message) {
\r
3617 case WM_LBUTTONDOWN:
\r
3619 sameAgain = FALSE;
\r
3621 /* Downclick vertically off board; check if on clock */
\r
3622 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
3623 if (gameMode == EditPosition) {
\r
3624 SetWhiteToPlayEvent();
\r
3625 } else if (gameMode == IcsPlayingBlack ||
\r
3626 gameMode == MachinePlaysWhite) {
\r
3629 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
3630 if (gameMode == EditPosition) {
\r
3631 SetBlackToPlayEvent();
\r
3632 } else if (gameMode == IcsPlayingWhite ||
\r
3633 gameMode == MachinePlaysBlack) {
\r
3637 if (!appData.highlightLastMove) {
\r
3638 ClearHighlights();
\r
3639 DrawPosition(FALSE, NULL);
\r
3641 fromX = fromY = -1;
\r
3642 dragInfo.start.x = dragInfo.start.y = -1;
\r
3643 dragInfo.from = dragInfo.start;
\r
3645 } else if (x < 0 || y < 0) {
\r
3647 } else if (fromX == x && fromY == y) {
\r
3648 /* Downclick on same square again */
\r
3649 ClearHighlights();
\r
3650 DrawPosition(FALSE, NULL);
\r
3651 sameAgain = TRUE;
\r
3652 } else if (fromX != -1) {
\r
3653 /* Downclick on different square */
\r
3654 ChessSquare pdown, pup;
\r
3655 pdown = boards[currentMove][fromY][fromX];
\r
3656 pup = boards[currentMove][y][x];
\r
3657 if (gameMode == EditPosition ||
\r
3658 !((WhitePawn <= pdown && pdown <= WhiteKing &&
\r
3659 WhitePawn <= pup && pup <= WhiteKing) ||
\r
3660 (BlackPawn <= pdown && pdown <= BlackKing &&
\r
3661 BlackPawn <= pup && pup <= BlackKing))) {
\r
3662 /* EditPosition, empty square, or different color piece;
\r
3663 click-click move is possible */
\r
3666 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
3667 if (appData.alwaysPromoteToQueen) {
\r
3668 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3669 if (!appData.highlightLastMove) {
\r
3670 ClearHighlights();
\r
3671 DrawPosition(FALSE, NULL);
\r
3674 SetHighlights(fromX, fromY, toX, toY);
\r
3675 DrawPosition(FALSE, NULL);
\r
3676 PromotionPopup(hwnd);
\r
3678 } else { /* not a promotion */
\r
3679 if (appData.animate || appData.highlightLastMove) {
\r
3680 SetHighlights(fromX, fromY, toX, toY);
\r
3682 ClearHighlights();
\r
3684 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3685 if (appData.animate && !appData.highlightLastMove) {
\r
3686 ClearHighlights();
\r
3687 DrawPosition(FALSE, NULL);
\r
3690 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3691 fromX = fromY = -1;
\r
3694 ClearHighlights();
\r
3695 DrawPosition(FALSE, NULL);
\r
3697 /* First downclick, or restart on a square with same color piece */
\r
3698 if (!frozen && OKToStartUserMove(x, y)) {
\r
3701 dragInfo.lastpos = pt;
\r
3702 dragInfo.from.x = fromX;
\r
3703 dragInfo.from.y = fromY;
\r
3704 dragInfo.start = dragInfo.from;
\r
3705 SetCapture(hwndMain);
\r
3707 fromX = fromY = -1;
\r
3708 dragInfo.start.x = dragInfo.start.y = -1;
\r
3709 dragInfo.from = dragInfo.start;
\r
3713 case WM_LBUTTONUP:
\r
3715 if (fromX == -1) break;
\r
3716 if (x == fromX && y == fromY) {
\r
3717 dragInfo.from.x = dragInfo.from.y = -1;
\r
3718 /* Upclick on same square */
\r
3720 /* Clicked same square twice: abort click-click move */
\r
3721 fromX = fromY = -1;
\r
3723 ClearPremoveHighlights();
\r
3725 /* First square clicked: start click-click move */
\r
3726 SetHighlights(fromX, fromY, -1, -1);
\r
3728 DrawPosition(FALSE, NULL);
\r
3729 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
3730 /* Errant click; ignore */
\r
3733 /* Finish drag move */
\r
3734 dragInfo.from.x = dragInfo.from.y = -1;
\r
3737 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
3738 appData.animate = appData.animate && !appData.animateDragging;
\r
3739 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
3740 if (appData.alwaysPromoteToQueen) {
\r
3741 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3743 DrawPosition(FALSE, NULL);
\r
3744 PromotionPopup(hwnd);
\r
3747 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3749 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3750 appData.animate = saveAnimate;
\r
3751 fromX = fromY = -1;
\r
3752 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
3753 ClearHighlights();
\r
3755 if (appData.animate || appData.animateDragging ||
\r
3756 appData.highlightDragging || gotPremove) {
\r
3757 DrawPosition(FALSE, NULL);
\r
3760 dragInfo.start.x = dragInfo.start.y = -1;
\r
3761 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
3764 case WM_MOUSEMOVE:
\r
3765 if ((appData.animateDragging || appData.highlightDragging)
\r
3766 && (wParam & MK_LBUTTON)
\r
3767 && dragInfo.from.x >= 0) {
\r
3768 if (appData.animateDragging) {
\r
3769 dragInfo.pos = pt;
\r
3771 if (appData.highlightDragging) {
\r
3772 SetHighlights(fromX, fromY, x, y);
\r
3774 DrawPosition(FALSE, NULL);
\r
3775 dragInfo.lastpos = dragInfo.pos;
\r
3779 case WM_MBUTTONDOWN:
\r
3780 case WM_RBUTTONDOWN:
\r
3783 fromX = fromY = -1;
\r
3784 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
3785 dragInfo.start.x = dragInfo.start.y = -1;
\r
3786 dragInfo.from = dragInfo.start;
\r
3787 dragInfo.lastpos = dragInfo.pos;
\r
3788 if (appData.highlightDragging) {
\r
3789 ClearHighlights();
\r
3791 DrawPosition(TRUE, NULL);
\r
3793 switch (gameMode) {
\r
3794 case EditPosition:
\r
3795 case IcsExamining:
\r
3796 if (x < 0 || y < 0) break;
\r
3799 if (message == WM_MBUTTONDOWN) {
\r
3800 buttonCount = 3; /* even if system didn't think so */
\r
3801 if (wParam & MK_SHIFT)
\r
3802 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3804 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3805 } else { /* message == WM_RBUTTONDOWN */
\r
3807 if (buttonCount == 3) {
\r
3808 if (wParam & MK_SHIFT)
\r
3809 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3811 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3813 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3816 /* Just have one menu, on the right button. Windows users don't
\r
3817 think to try the middle one, and sometimes other software steals
\r
3818 it, or it doesn't really exist. */
\r
3819 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3823 case IcsPlayingWhite:
\r
3824 case IcsPlayingBlack:
\r
3826 case MachinePlaysWhite:
\r
3827 case MachinePlaysBlack:
\r
3828 if (appData.testLegality &&
\r
3829 gameInfo.variant != VariantBughouse &&
\r
3830 gameInfo.variant != VariantCrazyhouse) break;
\r
3831 if (x < 0 || y < 0) break;
\r
3834 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
3835 SetupDropMenu(hmenu);
\r
3836 MenuPopup(hwnd, pt, hmenu, -1);
\r
3847 /* Preprocess messages for buttons in main window */
\r
3849 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3851 int id = GetWindowLong(hwnd, GWL_ID);
\r
3854 for (i=0; i<N_BUTTONS; i++) {
\r
3855 if (buttonDesc[i].id == id) break;
\r
3857 if (i == N_BUTTONS) return 0;
\r
3858 switch (message) {
\r
3863 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
3864 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
3871 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
3874 if (appData.icsActive) {
\r
3875 if (GetKeyState(VK_SHIFT) < 0) {
\r
3877 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3878 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3882 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3883 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3890 if (appData.icsActive) {
\r
3891 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3892 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3894 SendMessage(h, WM_CHAR, wParam, lParam);
\r
3896 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
3897 PopUpMoveDialog((char)wParam);
\r
3903 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
3906 /* Process messages for Promotion dialog box */
\r
3908 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
3912 switch (message) {
\r
3913 case WM_INITDIALOG: /* message: initialize dialog box */
\r
3914 /* Center the dialog over the application window */
\r
3915 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
3916 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
3917 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
3918 gameInfo.variant == VariantGiveaway) ?
\r
3919 SW_SHOW : SW_HIDE);
\r
3922 case WM_COMMAND: /* message: received a command */
\r
3923 switch (LOWORD(wParam)) {
\r
3925 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3926 ClearHighlights();
\r
3927 DrawPosition(FALSE, NULL);
\r
3947 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3948 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
3949 if (!appData.highlightLastMove) {
\r
3950 ClearHighlights();
\r
3951 DrawPosition(FALSE, NULL);
\r
3958 /* Pop up promotion dialog */
\r
3960 PromotionPopup(HWND hwnd)
\r
3964 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
3965 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
3966 hwnd, (DLGPROC)lpProc);
\r
3967 FreeProcInstance(lpProc);
\r
3970 /* Toggle ShowThinking */
\r
3972 ToggleShowThinking()
\r
3974 ShowThinkingEvent(!appData.showThinking);
\r
3978 LoadGameDialog(HWND hwnd, char* title)
\r
3982 char fileTitle[MSG_SIZ];
\r
3983 f = OpenFileDialog(hwnd, FALSE, "",
\r
3984 appData.oldSaveStyle ? "gam" : "pgn",
\r
3986 title, &number, fileTitle, NULL);
\r
3988 cmailMsgLoaded = FALSE;
\r
3989 if (number == 0) {
\r
3990 int error = GameListBuild(f);
\r
3992 DisplayError("Cannot build game list", error);
\r
3993 } else if (!ListEmpty(&gameList) &&
\r
3994 ((ListGame *) gameList.tailPred)->number > 1) {
\r
3995 GameListPopUp(f, fileTitle);
\r
3998 GameListDestroy();
\r
4001 LoadGame(f, number, fileTitle, FALSE);
\r
4006 ChangedConsoleFont()
\r
4009 CHARRANGE tmpsel, sel;
\r
4010 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4011 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4012 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4015 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4016 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4017 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4018 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4019 * size. This was undocumented in the version of MSVC++ that I had
\r
4020 * when I wrote the code, but is apparently documented now.
\r
4022 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4023 cfmt.bCharSet = f->lf.lfCharSet;
\r
4024 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4025 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4026 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4027 /* Why are the following seemingly needed too? */
\r
4028 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4029 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4030 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4032 tmpsel.cpMax = -1; /*999999?*/
\r
4033 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4034 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4035 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4036 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4038 paraf.cbSize = sizeof(paraf);
\r
4039 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4040 paraf.dxStartIndent = 0;
\r
4041 paraf.dxOffset = WRAP_INDENT;
\r
4042 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4043 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4046 /*---------------------------------------------------------------------------*\
\r
4048 * Window Proc for main window
\r
4050 \*---------------------------------------------------------------------------*/
\r
4052 /* Process messages for main window, etc. */
\r
4054 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4057 int wmId, wmEvent;
\r
4061 char fileTitle[MSG_SIZ];
\r
4063 switch (message) {
\r
4065 case WM_PAINT: /* message: repaint portion of window */
\r
4069 case WM_ERASEBKGND:
\r
4070 if (IsIconic(hwnd)) {
\r
4071 /* Cheat; change the message */
\r
4072 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4074 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4078 case WM_LBUTTONDOWN:
\r
4079 case WM_MBUTTONDOWN:
\r
4080 case WM_RBUTTONDOWN:
\r
4081 case WM_LBUTTONUP:
\r
4082 case WM_MBUTTONUP:
\r
4083 case WM_RBUTTONUP:
\r
4084 case WM_MOUSEMOVE:
\r
4085 MouseEvent(hwnd, message, wParam, lParam);
\r
4090 if (appData.icsActive) {
\r
4091 if (wParam == '\t') {
\r
4092 if (GetKeyState(VK_SHIFT) < 0) {
\r
4094 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4095 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4099 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4100 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4104 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4105 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4107 SendMessage(h, message, wParam, lParam);
\r
4109 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4110 PopUpMoveDialog((char)wParam);
\r
4114 case WM_PALETTECHANGED:
\r
4115 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4117 HDC hdc = GetDC(hwndMain);
\r
4118 SelectPalette(hdc, hPal, TRUE);
\r
4119 nnew = RealizePalette(hdc);
\r
4121 paletteChanged = TRUE;
\r
4123 UpdateColors(hdc);
\r
4125 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
4128 ReleaseDC(hwnd, hdc);
\r
4132 case WM_QUERYNEWPALETTE:
\r
4133 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4135 HDC hdc = GetDC(hwndMain);
\r
4136 paletteChanged = FALSE;
\r
4137 SelectPalette(hdc, hPal, FALSE);
\r
4138 nnew = RealizePalette(hdc);
\r
4140 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4142 ReleaseDC(hwnd, hdc);
\r
4147 case WM_COMMAND: /* message: command from application menu */
\r
4148 wmId = LOWORD(wParam);
\r
4149 wmEvent = HIWORD(wParam);
\r
4154 AnalysisPopDown();
\r
4157 case IDM_NewGameFRC:
4158 if( NewGameFRC() == 0 ) {
4164 case IDM_LoadGame:
\r
4165 LoadGameDialog(hwnd, "Load Game from File");
\r
4168 case IDM_LoadNextGame:
\r
4172 case IDM_LoadPrevGame:
\r
4176 case IDM_ReloadGame:
\r
4180 case IDM_LoadPosition:
\r
4181 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4182 Reset(FALSE, TRUE);
\r
4185 f = OpenFileDialog(hwnd, FALSE, "",
\r
4186 appData.oldSaveStyle ? "pos" : "fen",
\r
4188 "Load Position from File", &number, fileTitle, NULL);
\r
4190 LoadPosition(f, number, fileTitle);
\r
4194 case IDM_LoadNextPosition:
\r
4195 ReloadPosition(1);
\r
4198 case IDM_LoadPrevPosition:
\r
4199 ReloadPosition(-1);
\r
4202 case IDM_ReloadPosition:
\r
4203 ReloadPosition(0);
\r
4206 case IDM_SaveGame:
\r
4207 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4208 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4209 appData.oldSaveStyle ? "gam" : "pgn",
\r
4211 "Save Game to File", NULL, fileTitle, NULL);
\r
4213 SaveGame(f, 0, "");
\r
4217 case IDM_SavePosition:
\r
4218 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4219 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4220 appData.oldSaveStyle ? "pos" : "fen",
\r
4222 "Save Position to File", NULL, fileTitle, NULL);
\r
4224 SavePosition(f, 0, "");
\r
4228 case IDM_CopyGame:
\r
4229 CopyGameToClipboard();
\r
4232 case IDM_PasteGame:
\r
4233 PasteGameFromClipboard();
\r
4236 /* [AS] Autodetect FEN or PGN data */
4238 PasteGameOrFENFromClipboard();
4241 /* [AS] User adjudication */
4242 case IDM_UserAdjudication_White:
4243 UserAdjudicationEvent( +1 );
4246 case IDM_UserAdjudication_Black:
4247 UserAdjudicationEvent( -1 );
4250 case IDM_UserAdjudication_Draw:
4251 UserAdjudicationEvent( 0 );
4254 case IDM_CopyPosition:
\r
4255 CopyFENToClipboard();
\r
4258 case IDM_PastePosition:
\r
4259 PasteFENFromClipboard();
\r
4262 case IDM_MailMove:
\r
4266 case IDM_ReloadCMailMsg:
\r
4267 Reset(TRUE, TRUE);
\r
4268 ReloadCmailMsgEvent(FALSE);
\r
4271 case IDM_Minimize:
\r
4272 ShowWindow(hwnd, SW_MINIMIZE);
\r
4279 case IDM_MachineWhite:
\r
4280 MachineWhiteEvent();
\r
4282 * refresh the tags dialog only if it's visible
\r
4284 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4286 tags = PGNTags(&gameInfo);
\r
4287 TagsPopUp(tags, CmailMsg());
\r
4292 case IDM_MachineBlack:
\r
4293 MachineBlackEvent();
\r
4295 * refresh the tags dialog only if it's visible
\r
4297 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
4299 tags = PGNTags(&gameInfo);
\r
4300 TagsPopUp(tags, CmailMsg());
\r
4305 case IDM_TwoMachines:
\r
4306 TwoMachinesEvent();
\r
4308 * refresh the tags dialog only if it's visible
\r
4310 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
4312 tags = PGNTags(&gameInfo);
\r
4313 TagsPopUp(tags, CmailMsg());
\r
4318 case IDM_AnalysisMode:
\r
4319 if (!first.analysisSupport) {
\r
4320 char buf[MSG_SIZ];
\r
4321 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4322 DisplayError(buf, 0);
\r
4324 if (!appData.showThinking) ToggleShowThinking();
\r
4325 AnalyzeModeEvent();
\r
4329 case IDM_AnalyzeFile:
\r
4330 if (!first.analysisSupport) {
\r
4331 char buf[MSG_SIZ];
\r
4332 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4333 DisplayError(buf, 0);
\r
4335 if (!appData.showThinking) ToggleShowThinking();
\r
4336 AnalyzeFileEvent();
\r
4337 LoadGameDialog(hwnd, "Analyze Game from File");
\r
4338 AnalysisPeriodicEvent(1);
\r
4342 case IDM_IcsClient:
\r
4346 case IDM_EditGame:
\r
4350 case IDM_EditPosition:
\r
4351 EditPositionEvent();
\r
4354 case IDM_Training:
\r
4358 case IDM_ShowGameList:
\r
4359 ShowGameListProc();
\r
4362 case IDM_EditTags:
\r
4366 case IDM_EditComment:
\r
4367 if (commentDialogUp && editComment) {
\r
4370 EditCommentEvent();
\r
4390 case IDM_CallFlag:
\r
4410 case IDM_StopObserving:
\r
4411 StopObservingEvent();
\r
4414 case IDM_StopExamining:
\r
4415 StopExaminingEvent();
\r
4418 case IDM_TypeInMove:
\r
4419 PopUpMoveDialog('\000');
\r
4422 case IDM_Backward:
\r
4424 SetFocus(hwndMain);
\r
4429 SetFocus(hwndMain);
\r
4434 SetFocus(hwndMain);
\r
4439 SetFocus(hwndMain);
\r
4446 case IDM_TruncateGame:
\r
4447 TruncateGameEvent();
\r
4454 case IDM_RetractMove:
\r
4455 RetractMoveEvent();
\r
4458 case IDM_FlipView:
\r
4459 flipView = !flipView;
\r
4460 DrawPosition(FALSE, NULL);
\r
4463 case IDM_GeneralOptions:
\r
4464 GeneralOptionsPopup(hwnd);
\r
4467 case IDM_BoardOptions:
\r
4468 BoardOptionsPopup(hwnd);
\r
4471 case IDM_IcsOptions:
\r
4472 IcsOptionsPopup(hwnd);
\r
4476 FontsOptionsPopup(hwnd);
\r
4480 SoundOptionsPopup(hwnd);
\r
4483 case IDM_CommPort:
\r
4484 CommPortOptionsPopup(hwnd);
\r
4487 case IDM_LoadOptions:
\r
4488 LoadOptionsPopup(hwnd);
\r
4491 case IDM_SaveOptions:
\r
4492 SaveOptionsPopup(hwnd);
\r
4495 case IDM_TimeControl:
\r
4496 TimeControlOptionsPopup(hwnd);
\r
4499 case IDM_SaveSettings:
\r
4500 SaveSettings(settingsFileName);
\r
4503 case IDM_SaveSettingsOnExit:
\r
4504 saveSettingsOnExit = !saveSettingsOnExit;
\r
4505 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
4506 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
4507 MF_CHECKED : MF_UNCHECKED));
\r
4518 case IDM_AboutGame:
\r
4523 appData.debugMode = !appData.debugMode;
\r
4524 if (appData.debugMode) {
\r
4525 char dir[MSG_SIZ];
\r
4526 GetCurrentDirectory(MSG_SIZ, dir);
\r
4527 SetCurrentDirectory(installDir);
\r
4528 debugFP = fopen(appData.nameOfDebugFile, "w");
4529 SetCurrentDirectory(dir);
\r
4530 setbuf(debugFP, NULL);
\r
4537 case IDM_HELPCONTENTS:
\r
4538 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
4539 MessageBox (GetFocus(),
\r
4540 "Unable to activate help",
\r
4541 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4545 case IDM_HELPSEARCH:
\r
4546 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
4547 MessageBox (GetFocus(),
\r
4548 "Unable to activate help",
\r
4549 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4553 case IDM_HELPHELP:
\r
4554 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
4555 MessageBox (GetFocus(),
\r
4556 "Unable to activate help",
\r
4557 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4562 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
4564 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
4565 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
4566 FreeProcInstance(lpProc);
\r
4569 case IDM_DirectCommand1:
\r
4570 AskQuestionEvent("Direct Command",
\r
4571 "Send to chess program:", "", "1");
\r
4573 case IDM_DirectCommand2:
\r
4574 AskQuestionEvent("Direct Command",
\r
4575 "Send to second chess program:", "", "2");
\r
4578 case EP_WhitePawn:
\r
4579 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
4580 fromX = fromY = -1;
\r
4583 case EP_WhiteKnight:
\r
4584 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
4585 fromX = fromY = -1;
\r
4588 case EP_WhiteBishop:
\r
4589 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
4590 fromX = fromY = -1;
\r
4593 case EP_WhiteRook:
\r
4594 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
4595 fromX = fromY = -1;
\r
4598 case EP_WhiteQueen:
\r
4599 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
4600 fromX = fromY = -1;
\r
4603 case EP_WhiteKing:
\r
4604 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
4605 fromX = fromY = -1;
\r
4608 case EP_BlackPawn:
\r
4609 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
4610 fromX = fromY = -1;
\r
4613 case EP_BlackKnight:
\r
4614 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
4615 fromX = fromY = -1;
\r
4618 case EP_BlackBishop:
\r
4619 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
4620 fromX = fromY = -1;
\r
4623 case EP_BlackRook:
\r
4624 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
4625 fromX = fromY = -1;
\r
4628 case EP_BlackQueen:
\r
4629 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
4630 fromX = fromY = -1;
\r
4633 case EP_BlackKing:
\r
4634 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
4635 fromX = fromY = -1;
\r
4638 case EP_EmptySquare:
\r
4639 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
4640 fromX = fromY = -1;
\r
4643 case EP_ClearBoard:
\r
4644 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
4645 fromX = fromY = -1;
\r
4649 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
4650 fromX = fromY = -1;
\r
4654 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
4655 fromX = fromY = -1;
\r
4659 DropMenuEvent(WhitePawn, fromX, fromY);
\r
4660 fromX = fromY = -1;
\r
4664 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
4665 fromX = fromY = -1;
\r
4669 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
4670 fromX = fromY = -1;
\r
4674 DropMenuEvent(WhiteRook, fromX, fromY);
\r
4675 fromX = fromY = -1;
\r
4679 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
4680 fromX = fromY = -1;
\r
4684 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4690 case CLOCK_TIMER_ID:
\r
4691 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
4692 clockTimerEvent = 0;
\r
4693 DecrementClocks(); /* call into back end */
\r
4695 case LOAD_GAME_TIMER_ID:
\r
4696 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
4697 loadGameTimerEvent = 0;
\r
4698 AutoPlayGameLoop(); /* call into back end */
\r
4700 case ANALYSIS_TIMER_ID:
\r
4701 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
4702 appData.periodicUpdates) {
\r
4703 AnalysisPeriodicEvent(0);
\r
4705 KillTimer(hwnd, analysisTimerEvent);
\r
4706 analysisTimerEvent = 0;
\r
4709 case DELAYED_TIMER_ID:
\r
4710 KillTimer(hwnd, delayedTimerEvent);
\r
4711 delayedTimerEvent = 0;
\r
4712 delayedTimerCallback();
\r
4717 case WM_USER_Input:
\r
4718 InputEvent(hwnd, message, wParam, lParam);
\r
4721 case WM_ENTERSIZEMOVE:
\r
4722 if (hwnd == hwndMain) {
\r
4723 doingSizing = TRUE;
\r
4729 if (hwnd == hwndMain) {
\r
4730 lastSizing = wParam;
\r
4734 case WM_EXITSIZEMOVE:
\r
4735 if (hwnd == hwndMain) {
\r
4737 doingSizing = FALSE;
\r
4738 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4739 GetClientRect(hwnd, &client);
\r
4740 ResizeBoard(client.right, client.bottom, lastSizing);
\r
4745 case WM_DESTROY: /* message: window being destroyed */
\r
4746 PostQuitMessage(0);
\r
4750 if (hwnd == hwndMain) {
\r
4755 default: /* Passes it on if unprocessed */
\r
4756 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4761 /*---------------------------------------------------------------------------*\
\r
4763 * Misc utility routines
\r
4765 \*---------------------------------------------------------------------------*/
\r
4768 * Decent random number generator, at least not as bad as Windows
\r
4769 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
4771 unsigned int randstate;
\r
4776 randstate = randstate * 1664525 + 1013904223;
\r
4777 return (int) randstate & 0x7fffffff;
\r
4781 mysrandom(unsigned int seed)
\r
4788 * returns TRUE if user selects a different color, FALSE otherwise
\r
4792 ChangeColor(HWND hwnd, COLORREF *which)
\r
4794 static BOOL firstTime = TRUE;
\r
4795 static DWORD customColors[16];
\r
4797 COLORREF newcolor;
\r
4802 /* Make initial colors in use available as custom colors */
\r
4803 /* Should we put the compiled-in defaults here instead? */
\r
4805 customColors[i++] = lightSquareColor & 0xffffff;
\r
4806 customColors[i++] = darkSquareColor & 0xffffff;
\r
4807 customColors[i++] = whitePieceColor & 0xffffff;
\r
4808 customColors[i++] = blackPieceColor & 0xffffff;
\r
4809 customColors[i++] = highlightSquareColor & 0xffffff;
\r
4810 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
4812 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
4813 customColors[i++] = textAttribs[ccl].color;
\r
4815 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
4816 firstTime = FALSE;
\r
4819 cc.lStructSize = sizeof(cc);
\r
4820 cc.hwndOwner = hwnd;
\r
4821 cc.hInstance = NULL;
\r
4822 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
4823 cc.lpCustColors = (LPDWORD) customColors;
\r
4824 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
4826 if (!ChooseColor(&cc)) return FALSE;
\r
4828 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
4829 if (newcolor == *which) return FALSE;
\r
4830 *which = newcolor;
\r
4834 InitDrawingColors();
\r
4835 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4840 MyLoadSound(MySound *ms)
\r
4846 if (ms->data) free(ms->data);
\r
4849 switch (ms->name[0]) {
\r
4855 /* System sound from Control Panel. Don't preload here. */
\r
4859 if (ms->name[1] == NULLCHAR) {
\r
4860 /* "!" alone = silence */
\r
4863 /* Builtin wave resource. Error if not found. */
\r
4864 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
4865 if (h == NULL) break;
\r
4866 ms->data = (void *)LoadResource(hInst, h);
\r
4867 if (h == NULL) break;
\r
4872 /* .wav file. Error if not found. */
\r
4873 f = fopen(ms->name, "rb");
\r
4874 if (f == NULL) break;
\r
4875 if (fstat(fileno(f), &st) < 0) break;
\r
4876 ms->data = malloc(st.st_size);
\r
4877 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
4883 char buf[MSG_SIZ];
\r
4884 sprintf(buf, "Error loading sound %s", ms->name);
\r
4885 DisplayError(buf, GetLastError());
\r
4891 MyPlaySound(MySound *ms)
\r
4893 BOOLEAN ok = FALSE;
\r
4894 switch (ms->name[0]) {
\r
4900 /* System sound from Control Panel (deprecated feature).
\r
4901 "$" alone or an unset sound name gets default beep (still in use). */
\r
4902 if (ms->name[1]) {
\r
4903 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
4905 if (!ok) ok = MessageBeep(MB_OK);
\r
4908 /* Builtin wave resource, or "!" alone for silence */
\r
4909 if (ms->name[1]) {
\r
4910 if (ms->data == NULL) return FALSE;
\r
4911 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4917 /* .wav file. Error if not found. */
\r
4918 if (ms->data == NULL) return FALSE;
\r
4919 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4922 /* Don't print an error: this can happen innocently if the sound driver
\r
4923 is busy; for instance, if another instance of WinBoard is playing
\r
4924 a sound at about the same time. */
\r
4927 char buf[MSG_SIZ];
\r
4928 sprintf(buf, "Error playing sound %s", ms->name);
\r
4929 DisplayError(buf, GetLastError());
\r
4937 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4940 OPENFILENAME *ofn;
\r
4941 static UINT *number; /* gross that this is static */
\r
4943 switch (message) {
\r
4944 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4945 /* Center the dialog over the application window */
\r
4946 ofn = (OPENFILENAME *) lParam;
\r
4947 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
4948 number = (UINT *) ofn->lCustData;
\r
4949 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
4953 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4954 return FALSE; /* Allow for further processing */
\r
4957 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
4958 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
4960 return FALSE; /* Allow for further processing */
\r
4966 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
4968 static UINT *number;
\r
4969 OPENFILENAME *ofname;
\r
4972 case WM_INITDIALOG:
\r
4973 ofname = (OPENFILENAME *)lParam;
\r
4974 number = (UINT *)(ofname->lCustData);
\r
4977 ofnot = (OFNOTIFY *)lParam;
\r
4978 if (ofnot->hdr.code == CDN_FILEOK) {
\r
4979 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
4988 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
4989 char *nameFilt, char *dlgTitle, UINT *number,
\r
4990 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
4992 OPENFILENAME openFileName;
\r
4993 char buf1[MSG_SIZ];
\r
4996 if (fileName == NULL) fileName = buf1;
\r
4997 if (defName == NULL) {
\r
4998 strcpy(fileName, "*.");
\r
4999 strcat(fileName, defExt);
\r
5001 strcpy(fileName, defName);
\r
5003 if (fileTitle) strcpy(fileTitle, "");
\r
5004 if (number) *number = 0;
\r
5006 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5007 openFileName.hwndOwner = hwnd;
\r
5008 openFileName.hInstance = (HANDLE) hInst;
\r
5009 openFileName.lpstrFilter = nameFilt;
\r
5010 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5011 openFileName.nMaxCustFilter = 0L;
\r
5012 openFileName.nFilterIndex = 1L;
\r
5013 openFileName.lpstrFile = fileName;
\r
5014 openFileName.nMaxFile = MSG_SIZ;
\r
5015 openFileName.lpstrFileTitle = fileTitle;
\r
5016 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5017 openFileName.lpstrInitialDir = NULL;
\r
5018 openFileName.lpstrTitle = dlgTitle;
\r
5019 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5020 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
5021 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5022 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5023 openFileName.nFileOffset = 0;
\r
5024 openFileName.nFileExtension = 0;
\r
5025 openFileName.lpstrDefExt = defExt;
\r
5026 openFileName.lCustData = (LONG) number;
\r
5027 openFileName.lpfnHook = oldDialog ?
\r
5028 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5029 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5031 if (write ? GetSaveFileName(&openFileName) :
\r
5032 GetOpenFileName(&openFileName)) {
\r
5033 /* open the file */
\r
5034 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
5036 MessageBox(hwnd, "File open failed", NULL,
\r
5037 MB_OK|MB_ICONEXCLAMATION);
\r
5041 int err = CommDlgExtendedError();
\r
5042 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
5051 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5053 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5056 * Get the first pop-up menu in the menu template. This is the
\r
5057 * menu that TrackPopupMenu displays.
\r
5059 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5061 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5064 * TrackPopup uses screen coordinates, so convert the
\r
5065 * coordinates of the mouse click to screen coordinates.
\r
5067 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5069 /* Draw and track the floating pop-up menu. */
\r
5070 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5071 pt.x, pt.y, 0, hwnd, NULL);
\r
5073 /* Destroy the menu.*/
\r
5074 DestroyMenu(hmenu);
\r
5079 int sizeX, sizeY, newSizeX, newSizeY;
\r
5081 } ResizeEditPlusButtonsClosure;
\r
5084 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5086 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5090 if (hChild == cl->hText) return TRUE;
\r
5091 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5092 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5093 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5094 ScreenToClient(cl->hDlg, &pt);
\r
5095 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5096 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5100 /* Resize a dialog that has a (rich) edit field filling most of
\r
5101 the top, with a row of buttons below */
\r
5103 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
5106 int newTextHeight, newTextWidth;
\r
5107 ResizeEditPlusButtonsClosure cl;
\r
5109 /*if (IsIconic(hDlg)) return;*/
\r
5110 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
5112 cl.hdwp = BeginDeferWindowPos(8);
\r
5114 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
5115 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5116 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5117 if (newTextHeight < 0) {
\r
5118 newSizeY += -newTextHeight;
\r
5119 newTextHeight = 0;
\r
5121 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
5122 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5128 cl.newSizeX = newSizeX;
\r
5129 cl.newSizeY = newSizeY;
\r
5130 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
5132 EndDeferWindowPos(cl.hdwp);
\r
5135 /* Center one window over another */
\r
5136 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
5138 RECT rChild, rParent;
\r
5139 int wChild, hChild, wParent, hParent;
\r
5140 int wScreen, hScreen, xNew, yNew;
\r
5143 /* Get the Height and Width of the child window */
\r
5144 GetWindowRect (hwndChild, &rChild);
\r
5145 wChild = rChild.right - rChild.left;
\r
5146 hChild = rChild.bottom - rChild.top;
\r
5148 /* Get the Height and Width of the parent window */
\r
5149 GetWindowRect (hwndParent, &rParent);
\r
5150 wParent = rParent.right - rParent.left;
\r
5151 hParent = rParent.bottom - rParent.top;
\r
5153 /* Get the display limits */
\r
5154 hdc = GetDC (hwndChild);
\r
5155 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
5156 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
5157 ReleaseDC(hwndChild, hdc);
\r
5159 /* Calculate new X position, then adjust for screen */
\r
5160 xNew = rParent.left + ((wParent - wChild) /2);
\r
5163 } else if ((xNew+wChild) > wScreen) {
\r
5164 xNew = wScreen - wChild;
\r
5167 /* Calculate new Y position, then adjust for screen */
\r
5168 yNew = rParent.top + ((hParent - hChild) /2);
\r
5171 } else if ((yNew+hChild) > hScreen) {
\r
5172 yNew = hScreen - hChild;
\r
5175 /* Set it, and return */
\r
5176 return SetWindowPos (hwndChild, NULL,
\r
5177 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
5180 /*---------------------------------------------------------------------------*\
\r
5182 * Startup Dialog functions
\r
5184 \*---------------------------------------------------------------------------*/
\r
5186 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
5188 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5190 while (*cd != NULL) {
\r
5191 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
5197 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
5199 char buf1[ARG_MAX];
\r
5202 if (str[0] == '@') {
\r
5203 FILE* f = fopen(str + 1, "r");
\r
5205 DisplayFatalError(str + 1, errno, 2);
\r
5208 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
5210 buf1[len] = NULLCHAR;
\r
5214 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5217 char buf[MSG_SIZ];
\r
5218 char *end = strchr(str, '\n');
\r
5219 if (end == NULL) return;
\r
5220 memcpy(buf, str, end - str);
\r
5221 buf[end - str] = NULLCHAR;
\r
5222 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
5228 SetStartupDialogEnables(HWND hDlg)
\r
5230 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5231 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5232 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5233 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5234 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
5235 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
5236 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5237 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
5238 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
5239 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
5240 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5241 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
5242 IsDlgButtonChecked(hDlg, OPT_View));
\r
5246 QuoteForFilename(char *filename)
\r
5248 int dquote, space;
\r
5249 dquote = strchr(filename, '"') != NULL;
\r
5250 space = strchr(filename, ' ') != NULL;
\r
5251 if (dquote || space) {
\r
5263 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
5265 char buf[MSG_SIZ];
\r
5268 InitComboStringsFromOption(hwndCombo, nthnames);
\r
5269 q = QuoteForFilename(nthcp);
\r
5270 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
5271 if (*nthdir != NULLCHAR) {
\r
5272 q = QuoteForFilename(nthdir);
\r
5273 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
5275 if (*nthcp == NULLCHAR) {
\r
5276 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5277 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5278 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5279 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5284 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5286 char buf[MSG_SIZ];
\r
5290 switch (message) {
\r
5291 case WM_INITDIALOG:
\r
5292 /* Center the dialog */
\r
5293 CenterWindow (hDlg, GetDesktopWindow());
\r
5294 /* Initialize the dialog items */
\r
5295 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5296 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
5297 firstChessProgramNames);
\r
5298 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5299 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
5300 secondChessProgramNames);
\r
5301 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
5302 InitComboStringsFromOption(hwndCombo, icsNames);
\r
5303 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
5304 if (*appData.icsHelper != NULLCHAR) {
\r
5305 char *q = QuoteForFilename(appData.icsHelper);
\r
5306 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
5308 if (*appData.icsHost == NULLCHAR) {
\r
5309 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5310 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
5311 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5312 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5313 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5316 if (appData.icsActive) {
5317 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
5319 else if (appData.noChessProgram) {
5320 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
5323 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
5326 SetStartupDialogEnables(hDlg);
\r
5330 switch (LOWORD(wParam)) {
\r
5332 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
5333 strcpy(buf, "/fcp=");
\r
5334 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5336 ParseArgs(StringGet, &p);
\r
5337 strcpy(buf, "/scp=");
\r
5338 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5340 ParseArgs(StringGet, &p);
\r
5341 appData.noChessProgram = FALSE;
\r
5342 appData.icsActive = FALSE;
\r
5343 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
5344 strcpy(buf, "/ics /icshost=");
\r
5345 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5347 ParseArgs(StringGet, &p);
\r
5348 if (appData.zippyPlay) {
\r
5349 strcpy(buf, "/fcp=");
\r
5350 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5352 ParseArgs(StringGet, &p);
\r
5354 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
5355 appData.noChessProgram = TRUE;
\r
5356 appData.icsActive = FALSE;
\r
5358 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
5359 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
5362 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
5363 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
5365 ParseArgs(StringGet, &p);
\r
5367 EndDialog(hDlg, TRUE);
\r
5374 case IDM_HELPCONTENTS:
\r
5375 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5376 MessageBox (GetFocus(),
\r
5377 "Unable to activate help",
\r
5378 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5383 SetStartupDialogEnables(hDlg);
\r
5391 /*---------------------------------------------------------------------------*\
\r
5393 * About box dialog functions
\r
5395 \*---------------------------------------------------------------------------*/
\r
5397 /* Process messages for "About" dialog box */
\r
5399 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5401 switch (message) {
\r
5402 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5403 /* Center the dialog over the application window */
\r
5404 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5405 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
5408 case WM_COMMAND: /* message: received a command */
\r
5409 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
5410 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
5411 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5419 /*---------------------------------------------------------------------------*\
\r
5421 * Comment Dialog functions
\r
5423 \*---------------------------------------------------------------------------*/
\r
5426 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5428 static HANDLE hwndText = NULL;
\r
5429 int len, newSizeX, newSizeY, flags;
\r
5430 static int sizeX, sizeY;
\r
5435 switch (message) {
\r
5436 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5437 /* Initialize the dialog items */
\r
5438 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
5439 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
5440 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
5441 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
5442 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
5443 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
5444 SetWindowText(hDlg, commentTitle);
\r
5445 if (editComment) {
\r
5446 SetFocus(hwndText);
\r
5448 SetFocus(GetDlgItem(hDlg, IDOK));
\r
5450 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
5451 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
5452 MAKELPARAM(FALSE, 0));
\r
5453 /* Size and position the dialog */
\r
5454 if (!commentDialog) {
\r
5455 commentDialog = hDlg;
\r
5456 flags = SWP_NOZORDER;
\r
5457 GetClientRect(hDlg, &rect);
\r
5458 sizeX = rect.right;
\r
5459 sizeY = rect.bottom;
\r
5460 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
5461 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
5462 WINDOWPLACEMENT wp;
\r
5463 EnsureOnScreen(&commentX, &commentY);
\r
5464 wp.length = sizeof(WINDOWPLACEMENT);
\r
5466 wp.showCmd = SW_SHOW;
\r
5467 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
5468 wp.rcNormalPosition.left = commentX;
\r
5469 wp.rcNormalPosition.right = commentX + commentW;
\r
5470 wp.rcNormalPosition.top = commentY;
\r
5471 wp.rcNormalPosition.bottom = commentY + commentH;
\r
5472 SetWindowPlacement(hDlg, &wp);
\r
5474 GetClientRect(hDlg, &rect);
\r
5475 newSizeX = rect.right;
\r
5476 newSizeY = rect.bottom;
\r
5477 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
5478 newSizeX, newSizeY);
\r
5485 case WM_COMMAND: /* message: received a command */
\r
5486 switch (LOWORD(wParam)) {
\r
5488 if (editComment) {
\r
5490 /* Read changed options from the dialog box */
\r
5491 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
5492 len = GetWindowTextLength(hwndText);
\r
5493 str = (char *) malloc(len + 1);
\r
5494 GetWindowText(hwndText, str, len + 1);
\r
5503 ReplaceComment(commentIndex, str);
\r
5510 case OPT_CancelComment:
\r
5514 case OPT_ClearComment:
\r
5515 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
5518 case OPT_EditComment:
\r
5519 EditCommentEvent();
\r
5528 newSizeX = LOWORD(lParam);
\r
5529 newSizeY = HIWORD(lParam);
\r
5530 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
5535 case WM_GETMINMAXINFO:
\r
5536 /* Prevent resizing window too small */
\r
5537 mmi = (MINMAXINFO *) lParam;
\r
5538 mmi->ptMinTrackSize.x = 100;
\r
5539 mmi->ptMinTrackSize.y = 100;
\r
5546 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
5551 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
5553 if (str == NULL) str = "";
\r
5554 p = (char *) malloc(2 * strlen(str) + 2);
\r
5557 if (*str == '\n') *q++ = '\r';
\r
5561 if (commentText != NULL) free(commentText);
\r
5563 commentIndex = index;
\r
5564 commentTitle = title;
\r
5566 editComment = edit;
\r
5568 if (commentDialog) {
\r
5569 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
5570 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
5572 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
5573 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
5574 hwndMain, (DLGPROC)lpProc);
\r
5575 FreeProcInstance(lpProc);
\r
5577 commentDialogUp = TRUE;
\r
5581 /*---------------------------------------------------------------------------*\
\r
5583 * Type-in move dialog functions
\r
5585 \*---------------------------------------------------------------------------*/
\r
5588 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5590 char move[MSG_SIZ];
\r
5592 ChessMove moveType;
\r
5593 int fromX, fromY, toX, toY;
\r
5596 switch (message) {
\r
5597 case WM_INITDIALOG:
\r
5598 move[0] = (char) lParam;
\r
5599 move[1] = NULLCHAR;
\r
5600 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5601 hInput = GetDlgItem(hDlg, OPT_Move);
\r
5602 SetWindowText(hInput, move);
\r
5604 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
5608 switch (LOWORD(wParam)) {
\r
5610 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
5611 gameMode != Training) {
\r
5612 DisplayMoveError("Displayed move is not current");
\r
5614 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
5615 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
5616 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
5617 if (gameMode != Training)
\r
5618 forwardMostMove = currentMove;
\r
5619 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5621 DisplayMoveError("Could not parse move");
\r
5624 EndDialog(hDlg, TRUE);
\r
5627 EndDialog(hDlg, FALSE);
\r
5638 PopUpMoveDialog(char firstchar)
\r
5642 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
5643 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
5644 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
5645 gameMode == EditPosition || gameMode == IcsExamining ||
\r
5646 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
5647 gameMode == Training) {
\r
5648 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
5649 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
5650 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
5651 FreeProcInstance(lpProc);
\r
5655 /*---------------------------------------------------------------------------*\
\r
5659 \*---------------------------------------------------------------------------*/
\r
5661 /* Nonmodal error box */
\r
5662 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
5663 WPARAM wParam, LPARAM lParam);
\r
5666 ErrorPopUp(char *title, char *content)
\r
5670 BOOLEAN modal = hwndMain == NULL;
\r
5688 strncpy(errorTitle, title, sizeof(errorTitle));
\r
5689 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
5692 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
5694 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
5695 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
5696 hwndMain, (DLGPROC)lpProc);
\r
5697 FreeProcInstance(lpProc);
\r
5704 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
5705 if (errorDialog == NULL) return;
\r
5706 DestroyWindow(errorDialog);
\r
5707 errorDialog = NULL;
\r
5711 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5716 switch (message) {
\r
5717 case WM_INITDIALOG:
\r
5718 GetWindowRect(hDlg, &rChild);
\r
5719 SetWindowPos(hDlg, NULL, rChild.left,
\r
5720 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
5721 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
5722 errorDialog = hDlg;
\r
5723 SetWindowText(hDlg, errorTitle);
\r
5724 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
5725 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
5729 switch (LOWORD(wParam)) {
\r
5732 if (errorDialog == hDlg) errorDialog = NULL;
\r
5733 DestroyWindow(hDlg);
\r
5744 /*---------------------------------------------------------------------------*\
\r
5746 * Ics Interaction console functions
\r
5748 \*---------------------------------------------------------------------------*/
\r
5750 #define HISTORY_SIZE 64
\r
5751 static char *history[HISTORY_SIZE];
\r
5752 int histIn = 0, histP = 0;
\r
5755 SaveInHistory(char *cmd)
\r
5757 if (history[histIn] != NULL) {
\r
5758 free(history[histIn]);
\r
5759 history[histIn] = NULL;
\r
5761 if (*cmd == NULLCHAR) return;
\r
5762 history[histIn] = StrSave(cmd);
\r
5763 histIn = (histIn + 1) % HISTORY_SIZE;
\r
5764 if (history[histIn] != NULL) {
\r
5765 free(history[histIn]);
\r
5766 history[histIn] = NULL;
\r
5772 PrevInHistory(char *cmd)
\r
5775 if (histP == histIn) {
\r
5776 if (history[histIn] != NULL) free(history[histIn]);
\r
5777 history[histIn] = StrSave(cmd);
\r
5779 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
5780 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
5782 return history[histP];
\r
5788 if (histP == histIn) return NULL;
\r
5789 histP = (histP + 1) % HISTORY_SIZE;
\r
5790 return history[histP];
\r
5797 BOOLEAN immediate;
\r
5798 } IcsTextMenuEntry;
\r
5799 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
5800 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
5803 ParseIcsTextMenu(char *icsTextMenuString)
\r
5806 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
5807 char *p = icsTextMenuString;
\r
5808 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5811 if (e->command != NULL) {
\r
5813 e->command = NULL;
\r
5817 e = icsTextMenuEntry;
\r
5818 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5819 if (*p == ';' || *p == '\n') {
\r
5820 e->item = strdup("-");
\r
5821 e->command = NULL;
\r
5823 } else if (*p == '-') {
\r
5824 e->item = strdup("-");
\r
5825 e->command = NULL;
\r
5829 char *q, *r, *s, *t;
\r
5831 q = strchr(p, ',');
\r
5832 if (q == NULL) break;
\r
5834 r = strchr(q + 1, ',');
\r
5835 if (r == NULL) break;
\r
5837 s = strchr(r + 1, ',');
\r
5838 if (s == NULL) break;
\r
5841 t = strchr(s + 1, c);
\r
5844 t = strchr(s + 1, c);
\r
5846 if (t != NULL) *t = NULLCHAR;
\r
5847 e->item = strdup(p);
\r
5848 e->command = strdup(q + 1);
\r
5849 e->getname = *(r + 1) != '0';
\r
5850 e->immediate = *(s + 1) != '0';
\r
5854 if (t == NULL) break;
\r
5863 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
5867 hmenu = LoadMenu(hInst, "TextMenu");
\r
5868 h = GetSubMenu(hmenu, 0);
\r
5870 if (strcmp(e->item, "-") == 0) {
\r
5871 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
5873 if (e->item[0] == '|') {
\r
5874 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
5875 IDM_CommandX + i, &e->item[1]);
\r
5877 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
5886 WNDPROC consoleTextWindowProc;
\r
5889 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
5891 char buf[MSG_SIZ], name[MSG_SIZ];
\r
5892 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5896 SetWindowText(hInput, command);
\r
5898 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5900 sel.cpMin = 999999;
\r
5901 sel.cpMax = 999999;
\r
5902 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5907 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5908 if (sel.cpMin == sel.cpMax) {
\r
5909 /* Expand to surrounding word */
\r
5912 tr.chrg.cpMax = sel.cpMin;
\r
5913 tr.chrg.cpMin = --sel.cpMin;
\r
5914 if (sel.cpMin < 0) break;
\r
5915 tr.lpstrText = name;
\r
5916 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5917 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5921 tr.chrg.cpMin = sel.cpMax;
\r
5922 tr.chrg.cpMax = ++sel.cpMax;
\r
5923 tr.lpstrText = name;
\r
5924 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
5925 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5928 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5929 MessageBeep(MB_ICONEXCLAMATION);
\r
5933 tr.lpstrText = name;
\r
5934 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5936 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5937 MessageBeep(MB_ICONEXCLAMATION);
\r
5940 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
5943 sprintf(buf, "%s %s", command, name);
\r
5944 SetWindowText(hInput, buf);
\r
5945 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5947 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
5948 SetWindowText(hInput, buf);
\r
5949 sel.cpMin = 999999;
\r
5950 sel.cpMax = 999999;
\r
5951 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5957 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5962 switch (message) {
\r
5964 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5967 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
5970 sel.cpMin = 999999;
\r
5971 sel.cpMax = 999999;
\r
5972 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5973 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
5978 if (wParam == '\t') {
\r
5979 if (GetKeyState(VK_SHIFT) < 0) {
\r
5981 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5982 if (buttonDesc[0].hwnd) {
\r
5983 SetFocus(buttonDesc[0].hwnd);
\r
5985 SetFocus(hwndMain);
\r
5989 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
5992 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5994 SendMessage(hInput, message, wParam, lParam);
\r
5998 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6000 return SendMessage(hInput, message, wParam, lParam);
\r
6001 case WM_MBUTTONDOWN:
\r
6002 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6003 case WM_RBUTTONDOWN:
\r
6004 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6005 /* Move selection here if it was empty */
\r
6007 pt.x = LOWORD(lParam);
\r
6008 pt.y = HIWORD(lParam);
\r
6009 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6010 if (sel.cpMin == sel.cpMax) {
\r
6011 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6012 sel.cpMax = sel.cpMin;
\r
6013 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6015 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6018 case WM_RBUTTONUP:
\r
6019 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6020 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6021 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6024 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6025 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6026 if (sel.cpMin == sel.cpMax) {
\r
6027 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6028 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6030 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6031 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6033 pt.x = LOWORD(lParam);
\r
6034 pt.y = HIWORD(lParam);
\r
6035 MenuPopup(hwnd, pt, hmenu, -1);
\r
6039 switch (LOWORD(wParam)) {
\r
6040 case IDM_QuickPaste:
\r
6042 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6043 if (sel.cpMin == sel.cpMax) {
\r
6044 MessageBeep(MB_ICONEXCLAMATION);
\r
6047 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6048 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6049 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6054 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6057 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6060 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6064 int i = LOWORD(wParam) - IDM_CommandX;
\r
6065 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
6066 icsTextMenuEntry[i].command != NULL) {
\r
6067 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
6068 icsTextMenuEntry[i].getname,
\r
6069 icsTextMenuEntry[i].immediate);
\r
6077 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
6080 WNDPROC consoleInputWindowProc;
\r
6083 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6085 char buf[MSG_SIZ];
\r
6087 static BOOL sendNextChar = FALSE;
\r
6088 static BOOL quoteNextChar = FALSE;
\r
6089 InputSource *is = consoleInputSource;
\r
6093 switch (message) {
\r
6095 if (!appData.localLineEditing || sendNextChar) {
\r
6096 is->buf[0] = (CHAR) wParam;
\r
6098 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6099 sendNextChar = FALSE;
\r
6102 if (quoteNextChar) {
\r
6103 buf[0] = (char) wParam;
\r
6104 buf[1] = NULLCHAR;
\r
6105 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
6106 quoteNextChar = FALSE;
\r
6110 case '\r': /* Enter key */
\r
6111 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
6112 if (consoleEcho) SaveInHistory(is->buf);
\r
6113 is->buf[is->count++] = '\n';
\r
6114 is->buf[is->count] = NULLCHAR;
\r
6115 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6116 if (consoleEcho) {
\r
6117 ConsoleOutput(is->buf, is->count, TRUE);
\r
6118 } else if (appData.localLineEditing) {
\r
6119 ConsoleOutput("\n", 1, TRUE);
\r
6122 case '\033': /* Escape key */
\r
6123 SetWindowText(hwnd, "");
\r
6124 cf.cbSize = sizeof(CHARFORMAT);
\r
6125 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6126 if (consoleEcho) {
\r
6127 cf.crTextColor = textAttribs[ColorNormal].color;
\r
6129 cf.crTextColor = COLOR_ECHOOFF;
\r
6131 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
6132 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6134 case '\t': /* Tab key */
\r
6135 if (GetKeyState(VK_SHIFT) < 0) {
\r
6137 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
6140 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6141 if (buttonDesc[0].hwnd) {
\r
6142 SetFocus(buttonDesc[0].hwnd);
\r
6144 SetFocus(hwndMain);
\r
6148 case '\023': /* Ctrl+S */
\r
6149 sendNextChar = TRUE;
\r
6151 case '\021': /* Ctrl+Q */
\r
6152 quoteNextChar = TRUE;
\r
6161 GetWindowText(hwnd, buf, MSG_SIZ);
\r
6162 p = PrevInHistory(buf);
\r
6164 SetWindowText(hwnd, p);
\r
6165 sel.cpMin = 999999;
\r
6166 sel.cpMax = 999999;
\r
6167 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6172 p = NextInHistory();
\r
6174 SetWindowText(hwnd, p);
\r
6175 sel.cpMin = 999999;
\r
6176 sel.cpMax = 999999;
\r
6177 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6183 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6187 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
6191 case WM_MBUTTONDOWN:
\r
6192 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6193 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6195 case WM_RBUTTONUP:
\r
6196 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6197 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6198 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6202 hmenu = LoadMenu(hInst, "InputMenu");
\r
6203 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6204 if (sel.cpMin == sel.cpMax) {
\r
6205 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6206 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
6208 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6209 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6211 pt.x = LOWORD(lParam);
\r
6212 pt.y = HIWORD(lParam);
\r
6213 MenuPopup(hwnd, pt, hmenu, -1);
\r
6217 switch (LOWORD(wParam)) {
\r
6219 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
6221 case IDM_SelectAll:
\r
6223 sel.cpMax = -1; /*999999?*/
\r
6224 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6227 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6230 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6233 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6238 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
6241 #define CO_MAX 100000
\r
6242 #define CO_TRIM 1000
\r
6245 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6247 static HWND hText, hInput, hFocus;
\r
6248 InputSource *is = consoleInputSource;
\r
6250 static int sizeX, sizeY;
\r
6251 int newSizeX, newSizeY;
\r
6254 switch (message) {
\r
6255 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6256 hwndConsole = hDlg;
\r
6257 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
6258 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
6260 consoleTextWindowProc = (WNDPROC)
\r
6261 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
6262 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6263 consoleInputWindowProc = (WNDPROC)
\r
6264 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
6265 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6266 Colorize(ColorNormal, TRUE);
\r
6267 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
6268 ChangedConsoleFont();
\r
6269 GetClientRect(hDlg, &rect);
\r
6270 sizeX = rect.right;
\r
6271 sizeY = rect.bottom;
\r
6272 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
6273 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
6274 WINDOWPLACEMENT wp;
\r
6275 EnsureOnScreen(&consoleX, &consoleY);
\r
6276 wp.length = sizeof(WINDOWPLACEMENT);
\r
6278 wp.showCmd = SW_SHOW;
\r
6279 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6280 wp.rcNormalPosition.left = consoleX;
\r
6281 wp.rcNormalPosition.right = consoleX + consoleW;
\r
6282 wp.rcNormalPosition.top = consoleY;
\r
6283 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
6284 SetWindowPlacement(hDlg, &wp);
\r
6298 if (IsIconic(hDlg)) break;
\r
6299 newSizeX = LOWORD(lParam);
\r
6300 newSizeY = HIWORD(lParam);
\r
6301 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
6302 RECT rectText, rectInput;
\r
6304 int newTextHeight, newTextWidth;
\r
6305 GetWindowRect(hText, &rectText);
\r
6306 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6307 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6308 if (newTextHeight < 0) {
\r
6309 newSizeY += -newTextHeight;
\r
6310 newTextHeight = 0;
\r
6312 SetWindowPos(hText, NULL, 0, 0,
\r
6313 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6314 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
6315 pt.x = rectInput.left;
\r
6316 pt.y = rectInput.top + newSizeY - sizeY;
\r
6317 ScreenToClient(hDlg, &pt);
\r
6318 SetWindowPos(hInput, NULL,
\r
6319 pt.x, pt.y, /* needs client coords */
\r
6320 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
6321 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
6327 case WM_GETMINMAXINFO:
\r
6328 /* Prevent resizing window too small */
\r
6329 mmi = (MINMAXINFO *) lParam;
\r
6330 mmi->ptMinTrackSize.x = 100;
\r
6331 mmi->ptMinTrackSize.y = 100;
\r
6334 return DefWindowProc(hDlg, message, wParam, lParam);
\r
6342 if (hwndConsole) return;
\r
6343 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
6344 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
6349 ConsoleOutput(char* data, int length, int forceVisible)
\r
6354 char buf[CO_MAX+1];
\r
6357 static int delayLF = 0;
\r
6358 CHARRANGE savesel, sel;
\r
6360 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
6368 while (length--) {
\r
6376 } else if (*p == '\007') {
\r
6377 MyPlaySound(&sounds[(int)SoundBell]);
\r
6384 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
6385 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6386 /* Save current selection */
\r
6387 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
6388 exlen = GetWindowTextLength(hText);
\r
6389 /* Find out whether current end of text is visible */
\r
6390 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
6391 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
6392 /* Trim existing text if it's too long */
\r
6393 if (exlen + (q - buf) > CO_MAX) {
\r
6394 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
6397 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6398 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
6400 savesel.cpMin -= trim;
\r
6401 savesel.cpMax -= trim;
\r
6402 if (exlen < 0) exlen = 0;
\r
6403 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
6404 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
6406 /* Append the new text */
\r
6407 sel.cpMin = exlen;
\r
6408 sel.cpMax = exlen;
\r
6409 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6410 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
6411 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
6412 if (forceVisible || exlen == 0 ||
\r
6413 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
6414 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
6415 /* Scroll to make new end of text visible if old end of text
\r
6416 was visible or new text is an echo of user typein */
\r
6417 sel.cpMin = 9999999;
\r
6418 sel.cpMax = 9999999;
\r
6419 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6420 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6421 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
6422 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6424 if (savesel.cpMax == exlen || forceVisible) {
\r
6425 /* Move insert point to new end of text if it was at the old
\r
6426 end of text or if the new text is an echo of user typein */
\r
6427 sel.cpMin = 9999999;
\r
6428 sel.cpMax = 9999999;
\r
6429 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6431 /* Restore previous selection */
\r
6432 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
6434 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6441 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
6442 RECT *rect, char *color)
\r
6446 COLORREF oldFg, oldBg;
\r
6449 if (appData.clockMode) {
\r
6451 sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));
\r
6453 sprintf(buf, "%s: %s", color, TimeString(timeRemaining));
\r
6460 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
6461 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
6463 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
6464 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
6466 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
6468 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
6469 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
6470 rect, str, strlen(str), NULL);
\r
6472 (void) SetTextColor(hdc, oldFg);
\r
6473 (void) SetBkColor(hdc, oldBg);
\r
6474 (void) SelectObject(hdc, oldFont);
\r
6479 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6486 if (appData.debugMode) {
6487 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
6490 return ERROR_INVALID_USER_BUFFER;
6493 ResetEvent(ovl->hEvent);
\r
6494 ovl->Offset = ovl->OffsetHigh = 0;
\r
6495 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
6499 err = GetLastError();
\r
6500 if (err == ERROR_IO_PENDING) {
\r
6501 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
6505 err = GetLastError();
\r
6512 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6517 ResetEvent(ovl->hEvent);
\r
6518 ovl->Offset = ovl->OffsetHigh = 0;
\r
6519 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
6523 err = GetLastError();
\r
6524 if (err == ERROR_IO_PENDING) {
\r
6525 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
6529 err = GetLastError();
\r
6535 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
6536 void CheckForInputBufferFull( InputSource * is )
6538 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
6539 /* Look for end of line */
6542 while( p < is->next && *p != '\n' ) {
6546 if( p >= is->next ) {
6547 if (appData.debugMode) {
6548 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
6551 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
6552 is->count = (DWORD) -1;
6559 InputThread(LPVOID arg)
\r
6564 is = (InputSource *) arg;
\r
6565 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
6566 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
6567 while (is->hThread != NULL) {
\r
6568 is->error = DoReadFile(is->hFile, is->next,
\r
6569 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
6570 &is->count, &ovl);
\r
6571 if (is->error == NO_ERROR) {
\r
6572 is->next += is->count;
\r
6574 if (is->error == ERROR_BROKEN_PIPE) {
\r
6575 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
6578 is->count = (DWORD) -1;
\r
6579 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
6584 CheckForInputBufferFull( is );
6586 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6588 if( is->count == ((DWORD) -1) ) break; /* [AS] */
6590 if (is->count <= 0) break; /* Quit on EOF or error */
\r
6593 CloseHandle(ovl.hEvent);
\r
6594 CloseHandle(is->hFile);
\r
6596 if (appData.debugMode) {
6597 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
6604 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
6606 NonOvlInputThread(LPVOID arg)
\r
6613 is = (InputSource *) arg;
\r
6614 while (is->hThread != NULL) {
\r
6615 is->error = ReadFile(is->hFile, is->next,
\r
6616 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
6617 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
6618 if (is->error == NO_ERROR) {
\r
6619 /* Change CRLF to LF */
\r
6620 if (is->next > is->buf) {
\r
6622 i = is->count + 1;
\r
6630 if (prev == '\r' && *p == '\n') {
\r
6642 if (is->error == ERROR_BROKEN_PIPE) {
\r
6643 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
6646 is->count = (DWORD) -1;
\r
6650 CheckForInputBufferFull( is );
6652 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6654 if( is->count == ((DWORD) -1) ) break; /* [AS] */
6656 if (is->count < 0) break; /* Quit on error */
\r
6658 CloseHandle(is->hFile);
\r
6663 SocketInputThread(LPVOID arg)
\r
6667 is = (InputSource *) arg;
\r
6668 while (is->hThread != NULL) {
\r
6669 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
6670 if ((int)is->count == SOCKET_ERROR) {
\r
6671 is->count = (DWORD) -1;
\r
6672 is->error = WSAGetLastError();
\r
6674 is->error = NO_ERROR;
\r
6675 is->next += is->count;
\r
6676 if (is->count == 0 && is->second == is) {
\r
6677 /* End of file on stderr; quit with no message */
\r
6681 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6683 if( is->count == ((DWORD) -1) ) break; /* [AS] */
6685 if (is->count <= 0) break; /* Quit on EOF or error */
\r
6691 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6695 is = (InputSource *) lParam;
\r
6696 if (is->lineByLine) {
\r
6697 /* Feed in lines one by one */
\r
6698 char *p = is->buf;
\r
6700 while (q < is->next) {
\r
6701 if (*q++ == '\n') {
\r
6702 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
6707 /* Move any partial line to the start of the buffer */
\r
6709 while (p < is->next) {
\r
6714 if (is->error != NO_ERROR || is->count == 0) {
\r
6715 /* Notify backend of the error. Note: If there was a partial
\r
6716 line at the end, it is not flushed through. */
\r
6717 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
6720 /* Feed in the whole chunk of input at once */
\r
6721 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
6722 is->next = is->buf;
\r
6726 /*---------------------------------------------------------------------------*\
\r
6728 * Menu enables. Used when setting various modes.
\r
6730 \*---------------------------------------------------------------------------*/
\r
6738 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
6740 while (enab->item > 0) {
\r
6741 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
6746 Enables gnuEnables[] = {
\r
6747 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6748 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6749 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
6750 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
6751 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
6752 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
6753 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6754 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
6755 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
6756 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
6760 Enables icsEnables[] = {
\r
6761 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6762 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6763 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6764 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6765 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6766 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
6767 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
6768 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
6769 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6770 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
6771 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
6772 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
6777 Enables zippyEnables[] = {
\r
6778 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6779 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
6780 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
6785 Enables ncpEnables[] = {
\r
6786 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6787 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6788 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6789 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6790 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6791 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
6792 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
6793 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
6794 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
6795 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
6796 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6797 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6798 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
6799 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
6800 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
6804 Enables trainingOnEnables[] = {
\r
6805 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
6806 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
6807 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
6808 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
6809 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
6810 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
6811 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6812 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
6816 Enables trainingOffEnables[] = {
\r
6817 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
6818 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
6819 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
6820 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
6821 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
6822 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
6823 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6824 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
6828 /* These modify either ncpEnables or gnuEnables */
\r
6829 Enables cmailEnables[] = {
\r
6830 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
6831 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
6832 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
6833 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
6834 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
6835 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6836 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
6840 Enables machineThinkingEnables[] = {
\r
6841 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6842 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
6843 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
6844 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6845 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
6846 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6847 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6848 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6849 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6850 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
6851 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6852 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6853 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6854 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
6855 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6859 Enables userThinkingEnables[] = {
\r
6860 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6861 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
6862 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
6863 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6864 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
6865 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6866 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6867 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6868 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6869 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
6870 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
6871 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
6872 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
6873 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
6874 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
6878 /*---------------------------------------------------------------------------*\
\r
6880 * Front-end interface functions exported by XBoard.
\r
6881 * Functions appear in same order as prototypes in frontend.h.
\r
6883 \*---------------------------------------------------------------------------*/
\r
6887 static UINT prevChecked = 0;
\r
6888 static int prevPausing = 0;
\r
6891 if (pausing != prevPausing) {
\r
6892 prevPausing = pausing;
\r
6893 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
6894 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
6895 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
6898 switch (gameMode) {
\r
6899 case BeginningOfGame:
\r
6900 if (appData.icsActive)
\r
6901 nowChecked = IDM_IcsClient;
\r
6902 else if (appData.noChessProgram)
\r
6903 nowChecked = IDM_EditGame;
\r
6905 nowChecked = IDM_MachineBlack;
\r
6907 case MachinePlaysBlack:
\r
6908 nowChecked = IDM_MachineBlack;
\r
6910 case MachinePlaysWhite:
\r
6911 nowChecked = IDM_MachineWhite;
\r
6913 case TwoMachinesPlay:
\r
6914 nowChecked = IDM_TwoMachines;
\r
6917 nowChecked = IDM_AnalysisMode;
\r
6920 nowChecked = IDM_AnalyzeFile;
\r
6923 nowChecked = IDM_EditGame;
\r
6925 case PlayFromGameFile:
\r
6926 nowChecked = IDM_LoadGame;
\r
6928 case EditPosition:
\r
6929 nowChecked = IDM_EditPosition;
\r
6932 nowChecked = IDM_Training;
\r
6934 case IcsPlayingWhite:
\r
6935 case IcsPlayingBlack:
\r
6936 case IcsObserving:
\r
6938 nowChecked = IDM_IcsClient;
\r
6945 if (prevChecked != 0)
\r
6946 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6947 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
6948 if (nowChecked != 0)
\r
6949 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6950 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
6952 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
6953 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
6954 MF_BYCOMMAND|MF_ENABLED);
\r
6956 (void) EnableMenuItem(GetMenu(hwndMain),
\r
6957 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
6960 prevChecked = nowChecked;
\r
6966 HMENU hmenu = GetMenu(hwndMain);
\r
6967 SetMenuEnables(hmenu, icsEnables);
\r
6968 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
6969 MF_BYPOSITION|MF_ENABLED);
\r
6971 if (appData.zippyPlay) {
\r
6972 SetMenuEnables(hmenu, zippyEnables);
\r
6980 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
6986 HMENU hmenu = GetMenu(hwndMain);
\r
6987 SetMenuEnables(hmenu, ncpEnables);
\r
6988 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
6989 MF_BYPOSITION|MF_GRAYED);
\r
6990 DrawMenuBar(hwndMain);
\r
6996 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
7000 SetTrainingModeOn()
\r
7003 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
7004 for (i = 0; i < N_BUTTONS; i++) {
\r
7005 if (buttonDesc[i].hwnd != NULL)
\r
7006 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
7011 VOID SetTrainingModeOff()
\r
7014 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
7015 for (i = 0; i < N_BUTTONS; i++) {
\r
7016 if (buttonDesc[i].hwnd != NULL)
\r
7017 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
7023 SetUserThinkingEnables()
\r
7025 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
7029 SetMachineThinkingEnables()
\r
7031 HMENU hMenu = GetMenu(hwndMain);
\r
7032 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
7034 SetMenuEnables(hMenu, machineThinkingEnables);
\r
7036 if (gameMode == MachinePlaysBlack) {
\r
7037 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
7038 } else if (gameMode == MachinePlaysWhite) {
\r
7039 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
7040 } else if (gameMode == TwoMachinesPlay) {
\r
7041 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
7047 DisplayTitle(char *str)
\r
7049 char title[MSG_SIZ], *host;
\r
7050 if (str[0] != NULLCHAR) {
\r
7051 strcpy(title, str);
\r
7052 } else if (appData.icsActive) {
\r
7053 if (appData.icsCommPort[0] != NULLCHAR)
\r
7056 host = appData.icsHost;
\r
7057 sprintf(title, "%s: %s", szTitle, host);
\r
7058 } else if (appData.noChessProgram) {
\r
7059 strcpy(title, szTitle);
\r
7061 strcpy(title, szTitle);
\r
7062 strcat(title, ": ");
\r
7063 strcat(title, first.tidy);
\r
7065 SetWindowText(hwndMain, title);
\r
7070 DisplayMessage(char *str1, char *str2)
\r
7074 int remain = MESSAGE_TEXT_MAX - 1;
\r
7077 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
7078 messageText[0] = NULLCHAR;
\r
7080 len = strlen(str1);
\r
7081 if (len > remain) len = remain;
\r
7082 strncpy(messageText, str1, len);
\r
7083 messageText[len] = NULLCHAR;
\r
7086 if (*str2 && remain >= 2) {
\r
7088 strcat(messageText, " ");
\r
7091 len = strlen(str2);
\r
7092 if (len > remain) len = remain;
\r
7093 strncat(messageText, str2, len);
\r
7095 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
7097 if (IsIconic(hwndMain)) return;
\r
7098 hdc = GetDC(hwndMain);
\r
7099 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
7100 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7101 &messageRect, messageText, strlen(messageText), NULL);
\r
7102 (void) SelectObject(hdc, oldFont);
\r
7103 (void) ReleaseDC(hwndMain, hdc);
\r
7107 DisplayError(char *str, int error)
\r
7109 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
7115 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7116 NULL, error, LANG_NEUTRAL,
\r
7117 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7119 sprintf(buf, "%s:\n%s", str, buf2);
\r
7121 ErrorMap *em = errmap;
\r
7122 while (em->err != 0 && em->err != error) em++;
\r
7123 if (em->err != 0) {
\r
7124 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7126 sprintf(buf, "%s:\nError code %d", str, error);
\r
7131 ErrorPopUp("Error", buf);
\r
7136 DisplayMoveError(char *str)
\r
7138 fromX = fromY = -1;
\r
7139 ClearHighlights();
\r
7140 DrawPosition(FALSE, NULL);
\r
7141 if (appData.popupMoveErrors) {
\r
7142 ErrorPopUp("Error", str);
\r
7144 DisplayMessage(str, "");
\r
7145 moveErrorMessageUp = TRUE;
\r
7150 DisplayFatalError(char *str, int error, int exitStatus)
\r
7152 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
7154 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
7157 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7158 NULL, error, LANG_NEUTRAL,
\r
7159 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7161 sprintf(buf, "%s:\n%s", str, buf2);
\r
7163 ErrorMap *em = errmap;
\r
7164 while (em->err != 0 && em->err != error) em++;
\r
7165 if (em->err != 0) {
\r
7166 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7168 sprintf(buf, "%s:\nError code %d", str, error);
\r
7173 if (appData.debugMode) {
\r
7174 fprintf(debugFP, "%s: %s\n", label, str);
\r
7176 if (appData.popupExitMessage) {
\r
7177 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
7178 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
7180 ExitEvent(exitStatus);
\r
7185 DisplayInformation(char *str)
\r
7187 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
7192 DisplayNote(char *str)
\r
7194 ErrorPopUp("Note", str);
\r
7199 char *title, *question, *replyPrefix;
\r
7204 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7206 static QuestionParams *qp;
\r
7207 char reply[MSG_SIZ];
\r
7210 switch (message) {
\r
7211 case WM_INITDIALOG:
\r
7212 qp = (QuestionParams *) lParam;
\r
7213 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7214 SetWindowText(hDlg, qp->title);
\r
7215 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
7216 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
7220 switch (LOWORD(wParam)) {
\r
7222 strcpy(reply, qp->replyPrefix);
\r
7223 if (*reply) strcat(reply, " ");
\r
7224 len = strlen(reply);
\r
7225 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
7226 strcat(reply, "\n");
\r
7227 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
7228 EndDialog(hDlg, TRUE);
\r
7229 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
7232 EndDialog(hDlg, FALSE);
\r
7243 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
7245 QuestionParams qp;
\r
7249 qp.question = question;
\r
7250 qp.replyPrefix = replyPrefix;
\r
7252 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
7253 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
7254 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
7255 FreeProcInstance(lpProc);
\r
7258 /* [AS] Pick FRC position */
7259 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
7261 static int * lpIndexFRC;
7268 lpIndexFRC = (int *) lParam;
7270 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
7272 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
7273 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
7274 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
7275 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
7280 switch( LOWORD(wParam) ) {
7282 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
7283 EndDialog( hDlg, 0 );
7286 EndDialog( hDlg, 1 );
7289 if( HIWORD(wParam) == EN_CHANGE ) {
7290 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
7292 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
7295 case IDC_NFG_Random:
7296 sprintf( buf, "%d", myrandom() % 960 );
7297 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
7310 int index = appData.defaultFrcPosition;
7311 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
7313 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
7316 appData.defaultFrcPosition = index;
7324 DisplayIcsInteractionTitle(char *str)
\r
7326 char consoleTitle[MSG_SIZ];
\r
7328 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
7329 SetWindowText(hwndConsole, consoleTitle);
\r
7333 DrawPosition(int fullRedraw, Board board)
\r
7335 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
7342 fromX = fromY = -1;
\r
7343 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
7344 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
7345 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
7346 dragInfo.lastpos = dragInfo.pos;
\r
7347 dragInfo.start.x = dragInfo.start.y = -1;
\r
7348 dragInfo.from = dragInfo.start;
\r
7350 DrawPosition(TRUE, NULL);
\r
7356 CommentPopUp(char *title, char *str)
\r
7358 HWND hwnd = GetActiveWindow();
\r
7359 EitherCommentPopUp(0, title, str, FALSE);
\r
7360 SetActiveWindow(hwnd);
\r
7364 CommentPopDown(void)
\r
7366 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
7367 if (commentDialog) {
\r
7368 ShowWindow(commentDialog, SW_HIDE);
\r
7370 commentDialogUp = FALSE;
\r
7374 EditCommentPopUp(int index, char *title, char *str)
\r
7376 EitherCommentPopUp(index, title, str, TRUE);
\r
7383 MyPlaySound(&sounds[(int)SoundMove]);
\r
7386 VOID PlayIcsWinSound()
\r
7388 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
7391 VOID PlayIcsLossSound()
\r
7393 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
7396 VOID PlayIcsDrawSound()
\r
7398 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
7401 VOID PlayIcsUnfinishedSound()
\r
7403 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
7409 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
7417 consoleEcho = TRUE;
\r
7418 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7419 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
7420 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7429 consoleEcho = FALSE;
\r
7430 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7431 /* This works OK: set text and background both to the same color */
\r
7433 cf.crTextColor = COLOR_ECHOOFF;
\r
7434 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7435 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
7438 /* No Raw()...? */
\r
7440 void Colorize(ColorClass cc, int continuation)
\r
7442 currentColorClass = cc;
\r
7443 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7444 consoleCF.crTextColor = textAttribs[cc].color;
\r
7445 consoleCF.dwEffects = textAttribs[cc].effects;
\r
7446 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
7452 static char buf[MSG_SIZ];
\r
7453 DWORD bufsiz = MSG_SIZ;
\r
7455 if (!GetUserName(buf, &bufsiz)) {
\r
7456 /*DisplayError("Error getting user name", GetLastError());*/
\r
7457 strcpy(buf, "User");
\r
7465 static char buf[MSG_SIZ];
\r
7466 DWORD bufsiz = MSG_SIZ;
\r
7468 if (!GetComputerName(buf, &bufsiz)) {
\r
7469 /*DisplayError("Error getting host name", GetLastError());*/
\r
7470 strcpy(buf, "Unknown");
\r
7477 ClockTimerRunning()
\r
7479 return clockTimerEvent != 0;
\r
7485 if (clockTimerEvent == 0) return FALSE;
\r
7486 KillTimer(hwndMain, clockTimerEvent);
\r
7487 clockTimerEvent = 0;
\r
7492 StartClockTimer(long millisec)
\r
7494 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
7495 (UINT) millisec, NULL);
\r
7499 DisplayWhiteClock(long timeRemaining, int highlight)
\r
7502 hdc = GetDC(hwndMain);
\r
7503 if (!IsIconic(hwndMain)) {
\r
7504 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");
\r
7506 if (highlight && iconCurrent == iconBlack) {
\r
7507 iconCurrent = iconWhite;
\r
7508 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
7509 if (IsIconic(hwndMain)) {
\r
7510 DrawIcon(hdc, 2, 2, iconCurrent);
\r
7513 (void) ReleaseDC(hwndMain, hdc);
\r
7515 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
7519 DisplayBlackClock(long timeRemaining, int highlight)
\r
7522 hdc = GetDC(hwndMain);
\r
7523 if (!IsIconic(hwndMain)) {
\r
7524 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");
\r
7526 if (highlight && iconCurrent == iconWhite) {
\r
7527 iconCurrent = iconBlack;
\r
7528 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
7529 if (IsIconic(hwndMain)) {
\r
7530 DrawIcon(hdc, 2, 2, iconCurrent);
\r
7533 (void) ReleaseDC(hwndMain, hdc);
\r
7535 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
7540 LoadGameTimerRunning()
\r
7542 return loadGameTimerEvent != 0;
\r
7546 StopLoadGameTimer()
\r
7548 if (loadGameTimerEvent == 0) return FALSE;
\r
7549 KillTimer(hwndMain, loadGameTimerEvent);
\r
7550 loadGameTimerEvent = 0;
\r
7555 StartLoadGameTimer(long millisec)
\r
7557 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
7558 (UINT) millisec, NULL);
\r
7566 char fileTitle[MSG_SIZ];
\r
7568 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
7569 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
7570 appData.oldSaveStyle ? "gam" : "pgn",
\r
7572 "Save Game to File", NULL, fileTitle, NULL);
\r
7574 SaveGame(f, 0, "");
\r
7581 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
7583 if (delayedTimerEvent != 0) {
\r
7584 if (appData.debugMode) {
\r
7585 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
7587 KillTimer(hwndMain, delayedTimerEvent);
\r
7588 delayedTimerEvent = 0;
\r
7589 delayedTimerCallback();
\r
7591 delayedTimerCallback = cb;
\r
7592 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
7593 (UINT) millisec, NULL);
\r
7596 DelayedEventCallback
\r
7599 if (delayedTimerEvent) {
\r
7600 return delayedTimerCallback;
\r
7607 CancelDelayedEvent()
\r
7609 if (delayedTimerEvent) {
\r
7610 KillTimer(hwndMain, delayedTimerEvent);
\r
7611 delayedTimerEvent = 0;
\r
7615 /* Start a child process running the given program.
\r
7616 The process's standard output can be read from "from", and its
\r
7617 standard input can be written to "to".
\r
7618 Exit with fatal error if anything goes wrong.
\r
7619 Returns an opaque pointer that can be used to destroy the process
\r
7623 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
7625 #define BUFSIZE 4096
\r
7627 HANDLE hChildStdinRd, hChildStdinWr,
\r
7628 hChildStdoutRd, hChildStdoutWr;
\r
7629 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
7630 SECURITY_ATTRIBUTES saAttr;
\r
7632 PROCESS_INFORMATION piProcInfo;
\r
7633 STARTUPINFO siStartInfo;
\r
7635 char buf[MSG_SIZ];
\r
7638 if (appData.debugMode) {
\r
7639 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
7644 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
7645 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
7646 saAttr.bInheritHandle = TRUE;
\r
7647 saAttr.lpSecurityDescriptor = NULL;
\r
7650 * The steps for redirecting child's STDOUT:
\r
7651 * 1. Create anonymous pipe to be STDOUT for child.
\r
7652 * 2. Create a noninheritable duplicate of read handle,
\r
7653 * and close the inheritable read handle.
\r
7656 /* Create a pipe for the child's STDOUT. */
\r
7657 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
7658 return GetLastError();
\r
7661 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
7662 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
7663 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
7664 FALSE, /* not inherited */
\r
7665 DUPLICATE_SAME_ACCESS);
\r
7667 return GetLastError();
\r
7669 CloseHandle(hChildStdoutRd);
\r
7672 * The steps for redirecting child's STDIN:
\r
7673 * 1. Create anonymous pipe to be STDIN for child.
\r
7674 * 2. Create a noninheritable duplicate of write handle,
\r
7675 * and close the inheritable write handle.
\r
7678 /* Create a pipe for the child's STDIN. */
\r
7679 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
7680 return GetLastError();
\r
7683 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
7684 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
7685 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
7686 FALSE, /* not inherited */
\r
7687 DUPLICATE_SAME_ACCESS);
\r
7689 return GetLastError();
\r
7691 CloseHandle(hChildStdinWr);
\r
7693 /* Arrange to (1) look in dir for the child .exe file, and
\r
7694 * (2) have dir be the child's working directory. Interpret
\r
7695 * dir relative to the directory WinBoard loaded from. */
\r
7696 GetCurrentDirectory(MSG_SIZ, buf);
\r
7697 SetCurrentDirectory(installDir);
\r
7698 SetCurrentDirectory(dir);
\r
7700 /* Now create the child process. */
\r
7702 siStartInfo.cb = sizeof(STARTUPINFO);
\r
7703 siStartInfo.lpReserved = NULL;
\r
7704 siStartInfo.lpDesktop = NULL;
\r
7705 siStartInfo.lpTitle = NULL;
\r
7706 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
7707 siStartInfo.cbReserved2 = 0;
\r
7708 siStartInfo.lpReserved2 = NULL;
\r
7709 siStartInfo.hStdInput = hChildStdinRd;
\r
7710 siStartInfo.hStdOutput = hChildStdoutWr;
\r
7711 siStartInfo.hStdError = hChildStdoutWr;
\r
7713 fSuccess = CreateProcess(NULL,
\r
7714 cmdLine, /* command line */
\r
7715 NULL, /* process security attributes */
\r
7716 NULL, /* primary thread security attrs */
\r
7717 TRUE, /* handles are inherited */
\r
7718 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
7719 NULL, /* use parent's environment */
\r
7721 &siStartInfo, /* STARTUPINFO pointer */
\r
7722 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
7724 err = GetLastError();
\r
7725 SetCurrentDirectory(buf); /* return to prev directory */
\r
7730 /* Close the handles we don't need in the parent */
\r
7731 CloseHandle(piProcInfo.hThread);
\r
7732 CloseHandle(hChildStdinRd);
\r
7733 CloseHandle(hChildStdoutWr);
\r
7735 /* Prepare return value */
\r
7736 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7737 cp->kind = CPReal;
\r
7738 cp->hProcess = piProcInfo.hProcess;
\r
7739 cp->pid = piProcInfo.dwProcessId;
\r
7740 cp->hFrom = hChildStdoutRdDup;
\r
7741 cp->hTo = hChildStdinWrDup;
\r
7743 *pr = (void *) cp;
\r
7745 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
7746 2000 where engines sometimes don't see the initial command(s)
\r
7747 from WinBoard and hang. I don't understand how that can happen,
\r
7748 but the Sleep is harmless, so I've put it in. Others have also
\r
7749 reported what may be the same problem, so hopefully this will fix
\r
7750 it for them too. */
\r
7758 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
7762 cp = (ChildProc *) pr;
\r
7763 if (cp == NULL) return;
\r
7765 switch (cp->kind) {
\r
7767 /* TerminateProcess is considered harmful, so... */
\r
7768 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
7769 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
7770 /* The following doesn't work because the chess program
\r
7771 doesn't "have the same console" as WinBoard. Maybe
\r
7772 we could arrange for this even though neither WinBoard
\r
7773 nor the chess program uses a console for stdio? */
\r
7774 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
7776 /* [AS] Special termination modes for misbehaving programs... */
7778 if ( appData.debugMode) {
7779 fprintf( debugFP, "Terminating process %u\n", cp->pid );
7782 TerminateProcess( cp->hProcess, 0 );
7784 else if( signal == 10 ) {
7785 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
7787 if( dw != WAIT_OBJECT_0 ) {
7788 if ( appData.debugMode) {
7789 fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
7792 TerminateProcess( cp->hProcess, 0 );
7796 CloseHandle(cp->hProcess);
\r
7800 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
7804 closesocket(cp->sock);
\r
7809 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
7810 closesocket(cp->sock);
\r
7811 closesocket(cp->sock2);
\r
7819 InterruptChildProcess(ProcRef pr)
\r
7823 cp = (ChildProc *) pr;
\r
7824 if (cp == NULL) return;
\r
7825 switch (cp->kind) {
\r
7827 /* The following doesn't work because the chess program
\r
7828 doesn't "have the same console" as WinBoard. Maybe
\r
7829 we could arrange for this even though neither WinBoard
\r
7830 nor the chess program uses a console for stdio */
\r
7831 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
7836 /* Can't interrupt */
\r
7840 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
7847 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
7849 char cmdLine[MSG_SIZ];
\r
7851 if (port[0] == NULLCHAR) {
\r
7852 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
7854 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
7856 return StartChildProcess(cmdLine, "", pr);
\r
7860 /* Code to open TCP sockets */
\r
7863 OpenTCP(char *host, char *port, ProcRef *pr)
\r
7868 struct sockaddr_in sa, mysa;
\r
7869 struct hostent FAR *hp;
\r
7870 unsigned short uport;
\r
7871 WORD wVersionRequested;
\r
7874 /* Initialize socket DLL */
\r
7875 wVersionRequested = MAKEWORD(1, 1);
\r
7876 err = WSAStartup(wVersionRequested, &wsaData);
\r
7877 if (err != 0) return err;
\r
7880 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7881 err = WSAGetLastError();
\r
7886 /* Bind local address using (mostly) don't-care values.
\r
7888 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7889 mysa.sin_family = AF_INET;
\r
7890 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7891 uport = (unsigned short) 0;
\r
7892 mysa.sin_port = htons(uport);
\r
7893 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7894 == SOCKET_ERROR) {
\r
7895 err = WSAGetLastError();
\r
7900 /* Resolve remote host name */
\r
7901 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7902 if (!(hp = gethostbyname(host))) {
\r
7903 unsigned int b0, b1, b2, b3;
\r
7905 err = WSAGetLastError();
\r
7907 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7908 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7909 hp->h_addrtype = AF_INET;
\r
7911 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7912 hp->h_addr_list[0] = (char *) malloc(4);
\r
7913 hp->h_addr_list[0][0] = (char) b0;
\r
7914 hp->h_addr_list[0][1] = (char) b1;
\r
7915 hp->h_addr_list[0][2] = (char) b2;
\r
7916 hp->h_addr_list[0][3] = (char) b3;
\r
7922 sa.sin_family = hp->h_addrtype;
\r
7923 uport = (unsigned short) atoi(port);
\r
7924 sa.sin_port = htons(uport);
\r
7925 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7927 /* Make connection */
\r
7928 if (connect(s, (struct sockaddr *) &sa,
\r
7929 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7930 err = WSAGetLastError();
\r
7935 /* Prepare return value */
\r
7936 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7937 cp->kind = CPSock;
\r
7939 *pr = (ProcRef *) cp;
\r
7945 OpenCommPort(char *name, ProcRef *pr)
\r
7950 char fullname[MSG_SIZ];
\r
7952 if (*name != '\\')
\r
7953 sprintf(fullname, "\\\\.\\%s", name);
\r
7955 strcpy(fullname, name);
\r
7957 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
7958 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
7959 if (h == (HANDLE) -1) {
\r
7960 return GetLastError();
\r
7964 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
7966 /* Accumulate characters until a 100ms pause, then parse */
\r
7967 ct.ReadIntervalTimeout = 100;
\r
7968 ct.ReadTotalTimeoutMultiplier = 0;
\r
7969 ct.ReadTotalTimeoutConstant = 0;
\r
7970 ct.WriteTotalTimeoutMultiplier = 0;
\r
7971 ct.WriteTotalTimeoutConstant = 0;
\r
7972 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
7974 /* Prepare return value */
\r
7975 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7976 cp->kind = CPComm;
\r
7979 *pr = (ProcRef *) cp;
\r
7985 OpenLoopback(ProcRef *pr)
\r
7987 DisplayFatalError("Not implemented", 0, 1);
\r
7993 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
7998 struct sockaddr_in sa, mysa;
\r
7999 struct hostent FAR *hp;
\r
8000 unsigned short uport;
\r
8001 WORD wVersionRequested;
\r
8004 char stderrPortStr[MSG_SIZ];
\r
8006 /* Initialize socket DLL */
\r
8007 wVersionRequested = MAKEWORD(1, 1);
\r
8008 err = WSAStartup(wVersionRequested, &wsaData);
\r
8009 if (err != 0) return err;
\r
8011 /* Resolve remote host name */
\r
8012 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8013 if (!(hp = gethostbyname(host))) {
\r
8014 unsigned int b0, b1, b2, b3;
\r
8016 err = WSAGetLastError();
\r
8018 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8019 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8020 hp->h_addrtype = AF_INET;
\r
8022 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8023 hp->h_addr_list[0] = (char *) malloc(4);
\r
8024 hp->h_addr_list[0][0] = (char) b0;
\r
8025 hp->h_addr_list[0][1] = (char) b1;
\r
8026 hp->h_addr_list[0][2] = (char) b2;
\r
8027 hp->h_addr_list[0][3] = (char) b3;
\r
8033 sa.sin_family = hp->h_addrtype;
\r
8034 uport = (unsigned short) 514;
\r
8035 sa.sin_port = htons(uport);
\r
8036 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8038 /* Bind local socket to unused "privileged" port address
\r
8040 s = INVALID_SOCKET;
\r
8041 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8042 mysa.sin_family = AF_INET;
\r
8043 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8044 for (fromPort = 1023;; fromPort--) {
\r
8045 if (fromPort < 0) {
\r
8047 return WSAEADDRINUSE;
\r
8049 if (s == INVALID_SOCKET) {
\r
8050 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8051 err = WSAGetLastError();
\r
8056 uport = (unsigned short) fromPort;
\r
8057 mysa.sin_port = htons(uport);
\r
8058 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8059 == SOCKET_ERROR) {
\r
8060 err = WSAGetLastError();
\r
8061 if (err == WSAEADDRINUSE) continue;
\r
8065 if (connect(s, (struct sockaddr *) &sa,
\r
8066 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8067 err = WSAGetLastError();
\r
8068 if (err == WSAEADDRINUSE) {
\r
8079 /* Bind stderr local socket to unused "privileged" port address
\r
8081 s2 = INVALID_SOCKET;
\r
8082 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8083 mysa.sin_family = AF_INET;
\r
8084 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8085 for (fromPort = 1023;; fromPort--) {
\r
8086 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
8087 if (fromPort < 0) {
\r
8088 (void) closesocket(s);
\r
8090 return WSAEADDRINUSE;
\r
8092 if (s2 == INVALID_SOCKET) {
\r
8093 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8094 err = WSAGetLastError();
\r
8100 uport = (unsigned short) fromPort;
\r
8101 mysa.sin_port = htons(uport);
\r
8102 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8103 == SOCKET_ERROR) {
\r
8104 err = WSAGetLastError();
\r
8105 if (err == WSAEADDRINUSE) continue;
\r
8106 (void) closesocket(s);
\r
8110 if (listen(s2, 1) == SOCKET_ERROR) {
\r
8111 err = WSAGetLastError();
\r
8112 if (err == WSAEADDRINUSE) {
\r
8114 s2 = INVALID_SOCKET;
\r
8117 (void) closesocket(s);
\r
8118 (void) closesocket(s2);
\r
8124 prevStderrPort = fromPort; // remember port used
\r
8125 sprintf(stderrPortStr, "%d", fromPort);
\r
8127 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
8128 err = WSAGetLastError();
\r
8129 (void) closesocket(s);
\r
8130 (void) closesocket(s2);
\r
8135 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
8136 err = WSAGetLastError();
\r
8137 (void) closesocket(s);
\r
8138 (void) closesocket(s2);
\r
8142 if (*user == NULLCHAR) user = UserName();
\r
8143 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
8144 err = WSAGetLastError();
\r
8145 (void) closesocket(s);
\r
8146 (void) closesocket(s2);
\r
8150 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
8151 err = WSAGetLastError();
\r
8152 (void) closesocket(s);
\r
8153 (void) closesocket(s2);
\r
8158 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
8159 err = WSAGetLastError();
\r
8160 (void) closesocket(s);
\r
8161 (void) closesocket(s2);
\r
8165 (void) closesocket(s2); /* Stop listening */
\r
8167 /* Prepare return value */
\r
8168 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8169 cp->kind = CPRcmd;
\r
8172 *pr = (ProcRef *) cp;
\r
8179 AddInputSource(ProcRef pr, int lineByLine,
\r
8180 InputCallback func, VOIDSTAR closure)
\r
8182 InputSource *is, *is2 = NULL;
8183 ChildProc *cp = (ChildProc *) pr;
\r
8185 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
8186 is->lineByLine = lineByLine;
\r
8188 is->closure = closure;
\r
8189 is->second = NULL;
\r
8190 is->next = is->buf;
\r
8191 if (pr == NoProc) {
\r
8192 is->kind = CPReal;
\r
8193 consoleInputSource = is;
\r
8195 is->kind = cp->kind;
\r
8197 [AS] Try to avoid a race condition if the thread is given control too early:
8198 we create all threads suspended so that the is->hThread variable can be
8199 safely assigned, then let the threads start with ResumeThread.
8201 switch (cp->kind) {
\r
8203 is->hFile = cp->hFrom;
\r
8204 cp->hFrom = NULL; /* now owned by InputThread */
\r
8206 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
8207 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8211 is->hFile = cp->hFrom;
\r
8212 cp->hFrom = NULL; /* now owned by InputThread */
\r
8214 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
8215 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8219 is->sock = cp->sock;
\r
8221 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8222 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8226 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
8228 is->sock = cp->sock;
\r
8230 is2->sock = cp->sock2;
\r
8231 is2->second = is2;
\r
8233 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8234 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8236 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8237 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
8241 if( is->hThread != NULL ) {
8242 ResumeThread( is->hThread );
8245 if( is2 != NULL && is2->hThread != NULL ) {
8246 ResumeThread( is2->hThread );
8250 return (InputSourceRef) is;
\r
8254 RemoveInputSource(InputSourceRef isr)
\r
8258 is = (InputSource *) isr;
\r
8259 is->hThread = NULL; /* tell thread to stop */
\r
8260 CloseHandle(is->hThread);
\r
8261 if (is->second != NULL) {
\r
8262 is->second->hThread = NULL;
\r
8263 CloseHandle(is->second->hThread);
\r
8269 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
8272 int outCount = SOCKET_ERROR;
\r
8273 ChildProc *cp = (ChildProc *) pr;
\r
8274 static OVERLAPPED ovl;
\r
8276 if (pr == NoProc) {
\r
8277 ConsoleOutput(message, count, FALSE);
\r
8281 if (ovl.hEvent == NULL) {
\r
8282 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8284 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8286 switch (cp->kind) {
\r
8289 outCount = send(cp->sock, message, count, 0);
\r
8290 if (outCount == SOCKET_ERROR) {
\r
8291 *outError = WSAGetLastError();
\r
8293 *outError = NO_ERROR;
\r
8298 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
8299 &dOutCount, NULL)) {
\r
8300 *outError = NO_ERROR;
\r
8301 outCount = (int) dOutCount;
\r
8303 *outError = GetLastError();
\r
8308 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
8309 &dOutCount, &ovl);
\r
8310 if (*outError == NO_ERROR) {
\r
8311 outCount = (int) dOutCount;
\r
8319 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
8322 /* Ignore delay, not implemented for WinBoard */
\r
8323 return OutputToProcess(pr, message, count, outError);
\r
8328 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
8329 char *buf, int count, int error)
\r
8331 DisplayFatalError("Not implemented", 0, 1);
\r
8334 /* see wgamelist.c for Game List functions */
\r
8335 /* see wedittags.c for Edit Tags functions */
\r
8342 char buf[MSG_SIZ];
\r
8345 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
8346 f = fopen(buf, "r");
\r
8348 ProcessICSInitScript(f);
\r
8356 StartAnalysisClock()
\r
8358 if (analysisTimerEvent) return;
\r
8359 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
8360 (UINT) 2000, NULL);
\r
8364 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8366 static HANDLE hwndText;
\r
8368 static int sizeX, sizeY;
\r
8369 int newSizeX, newSizeY, flags;
\r
8372 switch (message) {
\r
8373 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8374 /* Initialize the dialog items */
\r
8375 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
8376 SetWindowText(hDlg, analysisTitle);
\r
8377 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
8378 /* Size and position the dialog */
\r
8379 if (!analysisDialog) {
\r
8380 analysisDialog = hDlg;
\r
8381 flags = SWP_NOZORDER;
\r
8382 GetClientRect(hDlg, &rect);
\r
8383 sizeX = rect.right;
\r
8384 sizeY = rect.bottom;
\r
8385 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
8386 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
8387 WINDOWPLACEMENT wp;
\r
8388 EnsureOnScreen(&analysisX, &analysisY);
\r
8389 wp.length = sizeof(WINDOWPLACEMENT);
\r
8391 wp.showCmd = SW_SHOW;
\r
8392 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8393 wp.rcNormalPosition.left = analysisX;
\r
8394 wp.rcNormalPosition.right = analysisX + analysisW;
\r
8395 wp.rcNormalPosition.top = analysisY;
\r
8396 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
8397 SetWindowPlacement(hDlg, &wp);
\r
8399 GetClientRect(hDlg, &rect);
\r
8400 newSizeX = rect.right;
\r
8401 newSizeY = rect.bottom;
\r
8402 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
8403 newSizeX, newSizeY);
\r
8410 case WM_COMMAND: /* message: received a command */
\r
8411 switch (LOWORD(wParam)) {
\r
8421 newSizeX = LOWORD(lParam);
\r
8422 newSizeY = HIWORD(lParam);
\r
8423 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
8428 case WM_GETMINMAXINFO:
\r
8429 /* Prevent resizing window too small */
\r
8430 mmi = (MINMAXINFO *) lParam;
\r
8431 mmi->ptMinTrackSize.x = 100;
\r
8432 mmi->ptMinTrackSize.y = 100;
\r
8439 AnalysisPopUp(char* title, char* str)
\r
8444 if (str == NULL) str = "";
\r
8445 p = (char *) malloc(2 * strlen(str) + 2);
\r
8448 if (*str == '\n') *q++ = '\r';
\r
8452 if (analysisText != NULL) free(analysisText);
\r
8455 if (analysisDialog) {
\r
8456 SetWindowText(analysisDialog, title);
\r
8457 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
8458 ShowWindow(analysisDialog, SW_SHOW);
\r
8460 analysisTitle = title;
\r
8461 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
8462 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
8463 hwndMain, (DLGPROC)lpProc);
\r
8464 FreeProcInstance(lpProc);
\r
8466 analysisDialogUp = TRUE;
\r
8472 if (analysisDialog) {
\r
8473 ShowWindow(analysisDialog, SW_HIDE);
\r
8475 analysisDialogUp = FALSE;
\r
8480 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
8482 highlightInfo.sq[0].x = fromX;
\r
8483 highlightInfo.sq[0].y = fromY;
\r
8484 highlightInfo.sq[1].x = toX;
\r
8485 highlightInfo.sq[1].y = toY;
\r
8491 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
8492 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
8496 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
8498 premoveHighlightInfo.sq[0].x = fromX;
\r
8499 premoveHighlightInfo.sq[0].y = fromY;
\r
8500 premoveHighlightInfo.sq[1].x = toX;
\r
8501 premoveHighlightInfo.sq[1].y = toY;
\r
8505 ClearPremoveHighlights()
\r
8507 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
8508 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
8512 ShutDownFrontEnd()
\r
8514 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
8515 DeleteClipboardTempFiles();
\r
8521 if (IsIconic(hwndMain))
\r
8522 ShowWindow(hwndMain, SW_RESTORE);
\r
8524 SetActiveWindow(hwndMain);
\r
8528 * Prototypes for animation support routines
\r
8530 static void ScreenSquare(int column, int row, POINT * pt);
\r
8531 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
8532 POINT frames[], int * nFrames);
\r
8538 AnimateMove(board, fromX, fromY, toX, toY)
\r
8545 ChessSquare piece;
\r
8546 POINT start, finish, mid;
\r
8547 POINT frames[kFactor * 2 + 1];
\r
8550 if (!appData.animate) return;
\r
8551 if (doingSizing) return;
\r
8552 if (fromY < 0 || fromX < 0) return;
\r
8553 piece = board[fromY][fromX];
\r
8554 if (piece >= EmptySquare) return;
\r
8556 ScreenSquare(fromX, fromY, &start);
\r
8557 ScreenSquare(toX, toY, &finish);
\r
8559 /* All pieces except knights move in straight line */
\r
8560 if (piece != WhiteKnight && piece != BlackKnight) {
\r
8561 mid.x = start.x + (finish.x - start.x) / 2;
\r
8562 mid.y = start.y + (finish.y - start.y) / 2;
\r
8564 /* Knight: make diagonal movement then straight */
\r
8565 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
8566 mid.x = start.x + (finish.x - start.x) / 2;
\r
8570 mid.y = start.y + (finish.y - start.y) / 2;
\r
8574 /* Don't use as many frames for very short moves */
\r
8575 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
8576 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
8578 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
8580 animInfo.from.x = fromX;
\r
8581 animInfo.from.y = fromY;
\r
8582 animInfo.to.x = toX;
\r
8583 animInfo.to.y = toY;
\r
8584 animInfo.lastpos = start;
\r
8585 animInfo.piece = piece;
\r
8586 for (n = 0; n < nFrames; n++) {
\r
8587 animInfo.pos = frames[n];
\r
8588 DrawPosition(FALSE, NULL);
\r
8589 animInfo.lastpos = animInfo.pos;
\r
8590 Sleep(appData.animSpeed);
\r
8592 animInfo.pos = finish;
\r
8593 DrawPosition(FALSE, NULL);
\r
8594 animInfo.piece = EmptySquare;
\r
8597 /* Convert board position to corner of screen rect and color */
\r
8600 ScreenSquare(column, row, pt)
\r
8601 int column; int row; POINT * pt;
\r
8604 pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
8605 pt->y = lineGap + row * (squareSize + lineGap);
\r
8607 pt->x = lineGap + column * (squareSize + lineGap);
\r
8608 pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
8612 /* Generate a series of frame coords from start->mid->finish.
\r
8613 The movement rate doubles until the half way point is
\r
8614 reached, then halves back down to the final destination,
\r
8615 which gives a nice slow in/out effect. The algorithmn
\r
8616 may seem to generate too many intermediates for short
\r
8617 moves, but remember that the purpose is to attract the
\r
8618 viewers attention to the piece about to be moved and
\r
8619 then to where it ends up. Too few frames would be less
\r
8623 Tween(start, mid, finish, factor, frames, nFrames)
\r
8624 POINT * start; POINT * mid;
\r
8625 POINT * finish; int factor;
\r
8626 POINT frames[]; int * nFrames;
\r
8628 int n, fraction = 1, count = 0;
\r
8630 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
8631 for (n = 0; n < factor; n++)
\r
8633 for (n = 0; n < factor; n++) {
\r
8634 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
8635 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
8637 fraction = fraction / 2;
\r
8641 frames[count] = *mid;
\r
8644 /* Slow out, stepping 1/2, then 1/4, ... */
\r
8646 for (n = 0; n < factor; n++) {
\r
8647 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
8648 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
8650 fraction = fraction * 2;
\r
8656 HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current)
\r
8658 /* Currently not implemented in WinBoard */
\r
8660 /* [AS] Let's see what this function is for... */
8663 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
8664 first, last, current, current >= 0 ? movelist[current] : "n/a" );
8666 OutputDebugString( buf );