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
420 * Setting "frozen" should disable all user input other than deleting
\r
421 * the window. We do this while engines are initializing themselves.
\r
423 static int frozen = 0;
\r
424 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
430 if (frozen) return;
\r
432 hmenu = GetMenu(hwndMain);
\r
433 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
434 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
436 DrawMenuBar(hwndMain);
\r
439 /* Undo a FreezeUI */
\r
445 if (!frozen) return;
\r
447 hmenu = GetMenu(hwndMain);
\r
448 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
449 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
451 DrawMenuBar(hwndMain);
\r
454 /*---------------------------------------------------------------------------*\
\r
458 \*---------------------------------------------------------------------------*/
\r
461 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
462 LPSTR lpCmdLine, int nCmdShow)
\r
465 HANDLE hAccelMain, hAccelNoAlt;
\r
469 LoadLibrary("RICHED32.DLL");
\r
470 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
472 if (!InitApplication(hInstance)) {
\r
475 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
479 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
480 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
482 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
484 while (GetMessage(&msg, /* message structure */
\r
485 NULL, /* handle of window receiving the message */
\r
486 0, /* lowest message to examine */
\r
487 0)) /* highest message to examine */
\r
489 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
490 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
491 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
492 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
493 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
494 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
495 TranslateMessage(&msg); /* Translates virtual key codes */
\r
496 DispatchMessage(&msg); /* Dispatches message to window */
\r
501 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
504 /*---------------------------------------------------------------------------*\
\r
506 * Initialization functions
\r
508 \*---------------------------------------------------------------------------*/
\r
511 InitApplication(HINSTANCE hInstance)
\r
515 /* Fill in window class structure with parameters that describe the */
\r
518 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
519 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
520 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
521 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
522 wc.hInstance = hInstance; /* Owner of this class */
\r
523 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
524 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
525 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
526 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
527 wc.lpszClassName = szAppName; /* Name to register as */
\r
529 /* Register the window class and return success/failure code. */
\r
530 if (!RegisterClass(&wc)) return FALSE;
\r
532 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
533 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
535 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
536 wc.hInstance = hInstance;
\r
537 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
538 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
539 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
540 wc.lpszMenuName = NULL;
\r
541 wc.lpszClassName = szConsoleName;
\r
543 if (!RegisterClass(&wc)) return FALSE;
\r
548 /* Set by InitInstance, used by EnsureOnScreen */
\r
549 int screenHeight, screenWidth;
\r
552 EnsureOnScreen(int *x, int *y)
\r
554 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
555 if (*x > screenWidth - 32) *x = 0;
\r
556 if (*y > screenHeight - 32) *y = 0;
\r
560 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
562 HWND hwnd; /* Main window handle. */
\r
564 WINDOWPLACEMENT wp;
\r
567 hInst = hInstance; /* Store instance handle in our global variable */
\r
569 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
570 *filepart = NULLCHAR;
\r
572 GetCurrentDirectory(MSG_SIZ, installDir);
\r
574 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
575 if (appData.debugMode) {
\r
576 debugFP = fopen(appData.nameOfDebugFile, "w");
577 setbuf(debugFP, NULL);
\r
582 /* Create a main window for this application instance. */
\r
583 hwnd = CreateWindow(szAppName, szTitle,
\r
584 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
585 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
586 NULL, NULL, hInstance, NULL);
\r
589 /* If window could not be created, return "failure" */
\r
594 iconWhite = LoadIcon(hInstance, "icon_white");
\r
595 iconBlack = LoadIcon(hInstance, "icon_black");
\r
596 iconCurrent = iconWhite;
\r
597 InitDrawingColors();
\r
598 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
599 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
600 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
601 /* Compute window size for each board size, and use the largest
\r
602 size that fits on this screen as the default. */
\r
603 InitDrawingSizes((BoardSize)ibs, 0);
\r
604 if (boardSize == (BoardSize)-1 &&
\r
605 winHeight <= screenHeight && winWidth <= screenWidth) {
\r
606 boardSize = (BoardSize)ibs;
\r
609 InitDrawingSizes(boardSize, 0);
\r
611 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
613 /* [AS] Load textures if specified */
614 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
616 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
617 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
618 liteBackTextureMode = appData.liteBackTextureMode;
620 if (liteBackTexture == NULL && appData.debugMode) {
621 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
625 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
626 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
627 darkBackTextureMode = appData.darkBackTextureMode;
629 if (darkBackTexture == NULL && appData.debugMode) {
630 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
634 mysrandom( (unsigned) time(NULL) );
636 /* Make a console window if needed */
\r
637 if (appData.icsActive) {
\r
643 /* Make the window visible; update its client area; and return "success" */
\r
644 EnsureOnScreen(&boardX, &boardY);
\r
645 wp.length = sizeof(WINDOWPLACEMENT);
\r
647 wp.showCmd = nCmdShow;
\r
648 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
649 wp.rcNormalPosition.left = boardX;
\r
650 wp.rcNormalPosition.right = boardX + winWidth;
\r
651 wp.rcNormalPosition.top = boardY;
\r
652 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
653 SetWindowPlacement(hwndMain, &wp);
\r
655 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
656 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
659 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
660 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
662 ShowWindow(hwndConsole, nCmdShow);
\r
664 UpdateWindow(hwnd);
\r
672 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
673 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
674 ArgSettingsFilename
\r
682 String *pString; // ArgString
\r
683 int *pInt; // ArgInt
\r
684 float *pFloat; // ArgFloat
\r
685 Boolean *pBoolean; // ArgBoolean
\r
686 COLORREF *pColor; // ArgColor
\r
687 ColorClass cc; // ArgAttribs
\r
688 String *pFilename; // ArgFilename
\r
689 BoardSize *pBoardSize; // ArgBoardSize
\r
690 int whichFont; // ArgFont
\r
691 DCB *pDCB; // ArgCommSettings
\r
692 String *pFilename; // ArgSettingsFilename
\r
700 ArgDescriptor argDescriptors[] = {
\r
701 /* positional arguments */
\r
702 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
703 { "", ArgNone, NULL },
\r
704 /* keyword arguments */
\r
705 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
706 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
707 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
708 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
709 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
710 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
711 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
712 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
713 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
714 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
715 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
716 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
717 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
718 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
719 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
720 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
721 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
722 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
724 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
726 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
728 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
729 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
731 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
732 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
733 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
734 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
735 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
736 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
737 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
738 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
739 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
740 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
741 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
742 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
743 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
744 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
745 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
746 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
747 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
748 /*!!bitmapDirectory?*/
\r
749 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
750 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
751 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
752 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
753 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
754 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
755 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
756 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
757 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
758 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
759 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
760 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
761 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
762 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
763 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
764 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
765 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
766 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
767 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
768 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
769 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
770 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
771 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
772 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
773 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
774 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
775 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
776 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
777 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
778 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
779 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
780 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
781 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
782 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
783 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
784 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
785 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
786 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
787 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
788 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
789 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
790 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
791 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
792 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
793 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
794 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
795 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
796 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
797 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
798 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
799 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
800 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
801 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
802 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
803 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
804 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
805 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
806 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
807 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
808 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
809 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
810 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
811 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
812 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
813 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
814 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
815 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
816 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
817 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
818 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
819 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
820 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
821 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
822 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
823 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
824 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
825 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
826 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
827 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
828 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
829 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
830 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
831 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
832 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
833 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
834 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
835 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
836 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
837 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
838 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
839 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
840 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
841 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
842 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
843 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
844 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
845 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
846 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
847 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
848 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
849 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
850 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
851 TRUE }, /* must come after all fonts */
\r
852 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
853 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
854 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
855 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
856 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
857 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
858 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
859 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
860 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
861 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
862 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
863 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
864 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
865 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
866 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
867 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
868 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
869 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
870 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
871 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
872 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
873 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
874 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
875 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
876 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
877 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
878 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
879 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
880 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
881 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
882 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
884 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
885 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
887 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
888 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
889 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
890 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
891 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
892 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
893 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
894 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
895 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
896 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
897 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
898 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
899 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
900 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
901 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
902 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
903 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
904 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
905 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
906 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
907 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
908 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
909 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
910 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
911 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
912 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
913 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
914 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
915 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
916 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
917 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
918 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
919 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
920 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
921 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
922 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
923 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
924 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
925 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
926 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
927 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
928 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
929 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
930 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
931 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
932 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
933 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
934 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
935 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
936 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
937 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
938 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
939 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
940 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
941 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
942 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
943 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
944 { "highlightLastMove", ArgBoolean,
\r
945 (LPVOID) &appData.highlightLastMove, TRUE },
\r
946 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
947 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
948 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
949 { "highlightDragging", ArgBoolean,
\r
950 (LPVOID) &appData.highlightDragging, TRUE },
\r
951 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
952 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
953 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
954 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
955 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
956 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
957 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
958 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
959 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
960 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
961 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
962 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
963 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
964 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
965 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
966 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
967 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
968 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
969 { "soundShout", ArgFilename,
\r
970 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
971 { "soundSShout", ArgFilename,
\r
972 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
973 { "soundChannel1", ArgFilename,
\r
974 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
975 { "soundChannel", ArgFilename,
\r
976 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
977 { "soundKibitz", ArgFilename,
\r
978 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
979 { "soundTell", ArgFilename,
\r
980 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
981 { "soundChallenge", ArgFilename,
\r
982 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
983 { "soundRequest", ArgFilename,
\r
984 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
985 { "soundSeek", ArgFilename,
\r
986 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
987 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
988 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
989 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
990 { "soundIcsLoss", ArgFilename,
\r
991 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
992 { "soundIcsDraw", ArgFilename,
\r
993 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
994 { "soundIcsUnfinished", ArgFilename,
\r
995 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
996 { "soundIcsAlarm", ArgFilename,
\r
997 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
998 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
999 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1000 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1001 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1002 { "reuseChessPrograms", ArgBoolean,
\r
1003 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1004 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1005 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1006 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1007 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1008 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1009 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1010 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1011 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1012 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1013 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1014 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1015 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1016 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1017 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1018 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1019 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1020 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1021 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1022 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1023 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1024 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1025 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1026 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1027 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1028 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1029 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1030 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1031 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1032 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1033 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1034 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1035 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1036 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1037 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1038 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1039 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1040 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1042 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1044 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1045 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1046 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1047 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
1048 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
1049 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1050 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1051 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1052 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1053 /* [AS] New features */
1054 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, TRUE },
1055 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, TRUE },
1056 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
1057 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
1058 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
1059 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
1060 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
1061 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
1062 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
1063 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
1064 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
1065 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
1066 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
1067 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
1068 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
1069 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
1070 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
1071 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
1072 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
1073 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
1074 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
1075 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
1077 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1078 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1079 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1080 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1081 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1082 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1083 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1084 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1085 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1086 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1087 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1088 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1089 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1091 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1092 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1093 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1094 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1095 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1096 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1097 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1099 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1100 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1101 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1102 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1103 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1104 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1105 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1106 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1107 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1108 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1109 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1110 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1111 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1112 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1113 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1114 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1115 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1116 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1118 { NULL, ArgNone, NULL, FALSE }
\r
1122 /* Kludge for indirection files on command line */
\r
1123 char* lastIndirectionFilename;
\r
1124 ArgDescriptor argDescriptorIndirection =
\r
1125 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1129 ExitArgError(char *msg, char *badArg)
\r
1131 char buf[MSG_SIZ];
\r
1133 sprintf(buf, "%s %s", msg, badArg);
\r
1134 DisplayFatalError(buf, 0, 2);
\r
1138 /* Command line font name parser. NULL name means do nothing.
\r
1139 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1140 For backward compatibility, syntax without the colon is also
\r
1141 accepted, but font names with digits in them won't work in that case.
\r
1144 ParseFontName(char *name, MyFontParams *mfp)
\r
1147 if (name == NULL) return;
\r
1149 q = strchr(p, ':');
\r
1151 if (q - p >= sizeof(mfp->faceName))
\r
1152 ExitArgError("Font name too long:", name);
\r
1153 memcpy(mfp->faceName, p, q - p);
\r
1154 mfp->faceName[q - p] = NULLCHAR;
\r
1157 q = mfp->faceName;
\r
1158 while (*p && !isdigit(*p)) {
\r
1160 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1161 ExitArgError("Font name too long:", name);
\r
1163 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1166 if (!*p) ExitArgError("Font point size missing:", name);
\r
1167 mfp->pointSize = (float) atof(p);
\r
1168 mfp->bold = (strchr(p, 'b') != NULL);
\r
1169 mfp->italic = (strchr(p, 'i') != NULL);
\r
1170 mfp->underline = (strchr(p, 'u') != NULL);
\r
1171 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1174 /* Color name parser.
\r
1175 X version accepts X color names, but this one
\r
1176 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1178 ParseColorName(char *name)
\r
1180 int red, green, blue, count;
\r
1181 char buf[MSG_SIZ];
\r
1183 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1185 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1186 &red, &green, &blue);
\r
1189 sprintf(buf, "Can't parse color name %s", name);
\r
1190 DisplayError(buf, 0);
\r
1191 return RGB(0, 0, 0);
\r
1193 return PALETTERGB(red, green, blue);
\r
1197 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1199 char *e = argValue;
\r
1203 if (*e == 'b') eff |= CFE_BOLD;
\r
1204 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1205 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1206 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1207 else if (*e == '#' || isdigit(*e)) break;
\r
1211 *color = ParseColorName(e);
\r
1216 ParseBoardSize(char *name)
\r
1218 BoardSize bs = SizeTiny;
\r
1219 while (sizeInfo[bs].name != NULL) {
\r
1220 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1223 ExitArgError("Unrecognized board size value", name);
\r
1224 return bs; /* not reached */
\r
1229 StringGet(void *getClosure)
\r
1231 char **p = (char **) getClosure;
\r
1236 FileGet(void *getClosure)
\r
1239 FILE* f = (FILE*) getClosure;
\r
1248 /* Parse settings file named "name". If file found, return the
\r
1249 full name in fullname and return TRUE; else return FALSE */
\r
1251 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1256 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1257 f = fopen(fullname, "r");
\r
1259 ParseArgs(FileGet, f);
\r
1268 ParseArgs(GetFunc get, void *cl)
\r
1270 char argName[ARG_MAX];
\r
1271 char argValue[ARG_MAX];
\r
1272 ArgDescriptor *ad;
\r
1281 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1282 if (ch == NULLCHAR) break;
\r
1284 /* Comment to end of line */
\r
1286 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1288 } else if (ch == '/' || ch == '-') {
\r
1291 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1292 ch != '\n' && ch != '\t') {
\r
1298 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1299 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1301 if (ad->argName == NULL)
\r
1302 ExitArgError("Unrecognized argument", argName);
\r
1304 } else if (ch == '@') {
\r
1305 /* Indirection file */
\r
1306 ad = &argDescriptorIndirection;
\r
1309 /* Positional argument */
\r
1310 ad = &argDescriptors[posarg++];
\r
1311 strcpy(argName, ad->argName);
\r
1314 if (ad->argType == ArgTrue) {
\r
1315 *(Boolean *) ad->argLoc = TRUE;
\r
1318 if (ad->argType == ArgFalse) {
\r
1319 *(Boolean *) ad->argLoc = FALSE;
\r
1323 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1324 if (ch == NULLCHAR || ch == '\n') {
\r
1325 ExitArgError("No value provided for argument", argName);
\r
1329 // Quoting with { }. No characters have to (or can) be escaped.
\r
1330 // Thus the string cannot contain a '}' character.
\r
1350 } else if (ch == '\'' || ch == '"') {
\r
1351 // Quoting with ' ' or " ", with \ as escape character.
\r
1352 // Inconvenient for long strings that may contain Windows filenames.
\r
1369 if (ch == start) {
\r
1378 if (ad->argType == ArgFilename
\r
1379 || ad->argType == ArgSettingsFilename) {
\r
1385 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1409 for (i = 0; i < 3; i++) {
\r
1410 if (ch >= '0' && ch <= '7') {
\r
1411 octval = octval*8 + (ch - '0');
\r
1418 *q++ = (char) octval;
\r
1429 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1436 switch (ad->argType) {
\r
1438 *(int *) ad->argLoc = atoi(argValue);
\r
1442 *(float *) ad->argLoc = (float) atof(argValue);
\r
1447 *(char **) ad->argLoc = strdup(argValue);
\r
1450 case ArgSettingsFilename:
\r
1452 char fullname[MSG_SIZ];
\r
1453 if (ParseSettingsFile(argValue, fullname)) {
\r
1454 if (ad->argLoc != NULL) {
\r
1455 *(char **) ad->argLoc = strdup(fullname);
\r
1458 if (ad->argLoc != NULL) {
\r
1460 ExitArgError("Failed to open indirection file", argValue);
\r
1467 switch (argValue[0]) {
\r
1470 *(Boolean *) ad->argLoc = TRUE;
\r
1474 *(Boolean *) ad->argLoc = FALSE;
\r
1477 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1483 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1486 case ArgAttribs: {
\r
1487 ColorClass cc = (ColorClass)ad->argLoc;
\r
1488 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1492 case ArgBoardSize:
\r
1493 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1497 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1500 case ArgCommSettings:
\r
1501 ParseCommSettings(argValue, &dcb);
\r
1505 ExitArgError("Unrecognized argument", argValue);
\r
1512 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1514 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1515 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1518 lf->lfEscapement = 0;
\r
1519 lf->lfOrientation = 0;
\r
1520 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1521 lf->lfItalic = mfp->italic;
\r
1522 lf->lfUnderline = mfp->underline;
\r
1523 lf->lfStrikeOut = mfp->strikeout;
\r
1524 lf->lfCharSet = DEFAULT_CHARSET;
\r
1525 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1526 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1527 lf->lfQuality = DEFAULT_QUALITY;
\r
1528 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1529 strcpy(lf->lfFaceName, mfp->faceName);
\r
1533 CreateFontInMF(MyFont *mf)
\r
1535 LFfromMFP(&mf->lf, &mf->mfp);
\r
1536 if (mf->hf) DeleteObject(mf->hf);
\r
1537 mf->hf = CreateFontIndirect(&mf->lf);
\r
1541 SetDefaultTextAttribs()
\r
1544 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1545 ParseAttribs(&textAttribs[cc].color,
\r
1546 &textAttribs[cc].effects,
\r
1547 defaultTextAttribs[cc]);
\r
1552 SetDefaultSounds()
\r
1556 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1557 textAttribs[cc].sound.name = strdup("");
\r
1558 textAttribs[cc].sound.data = NULL;
\r
1560 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1561 sounds[sc].name = strdup("");
\r
1562 sounds[sc].data = NULL;
\r
1564 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1572 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1573 MyLoadSound(&textAttribs[cc].sound);
\r
1575 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1576 MyLoadSound(&sounds[sc]);
\r
1581 InitAppData(LPSTR lpCmdLine)
\r
1584 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1587 programName = szAppName;
\r
1589 /* Initialize to defaults */
\r
1590 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1591 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1592 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1593 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1594 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1595 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1596 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1597 SetDefaultTextAttribs();
\r
1598 SetDefaultSounds();
\r
1599 appData.movesPerSession = MOVES_PER_SESSION;
\r
1600 appData.initString = INIT_STRING;
\r
1601 appData.secondInitString = INIT_STRING;
\r
1602 appData.firstComputerString = COMPUTER_STRING;
\r
1603 appData.secondComputerString = COMPUTER_STRING;
\r
1604 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1605 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1606 appData.firstPlaysBlack = FALSE;
\r
1607 appData.noChessProgram = FALSE;
\r
1608 chessProgram = FALSE;
\r
1609 appData.firstHost = FIRST_HOST;
\r
1610 appData.secondHost = SECOND_HOST;
\r
1611 appData.firstDirectory = FIRST_DIRECTORY;
\r
1612 appData.secondDirectory = SECOND_DIRECTORY;
\r
1613 appData.bitmapDirectory = "";
\r
1614 appData.remoteShell = REMOTE_SHELL;
\r
1615 appData.remoteUser = "";
\r
1616 appData.timeDelay = TIME_DELAY;
\r
1617 appData.timeControl = TIME_CONTROL;
\r
1618 appData.timeIncrement = TIME_INCREMENT;
\r
1619 appData.icsActive = FALSE;
\r
1620 appData.icsHost = "";
\r
1621 appData.icsPort = ICS_PORT;
\r
1622 appData.icsCommPort = ICS_COMM_PORT;
\r
1623 appData.icsLogon = ICS_LOGON;
\r
1624 appData.icsHelper = "";
\r
1625 appData.useTelnet = FALSE;
\r
1626 appData.telnetProgram = TELNET_PROGRAM;
\r
1627 appData.gateway = "";
\r
1628 appData.loadGameFile = "";
\r
1629 appData.loadGameIndex = 0;
\r
1630 appData.saveGameFile = "";
\r
1631 appData.autoSaveGames = FALSE;
\r
1632 appData.loadPositionFile = "";
\r
1633 appData.loadPositionIndex = 1;
\r
1634 appData.savePositionFile = "";
\r
1635 appData.matchMode = FALSE;
\r
1636 appData.matchGames = 0;
\r
1637 appData.monoMode = FALSE;
\r
1638 appData.debugMode = FALSE;
\r
1639 appData.clockMode = TRUE;
\r
1640 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1641 appData.Iconic = FALSE; /*unused*/
\r
1642 appData.searchTime = "";
\r
1643 appData.searchDepth = 0;
\r
1644 appData.showCoords = FALSE;
\r
1645 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1646 appData.autoCallFlag = FALSE;
\r
1647 appData.flipView = FALSE;
\r
1648 appData.autoFlipView = TRUE;
\r
1649 appData.cmailGameName = "";
\r
1650 appData.alwaysPromoteToQueen = FALSE;
\r
1651 appData.oldSaveStyle = FALSE;
\r
1652 appData.quietPlay = FALSE;
\r
1653 appData.showThinking = FALSE;
\r
1654 appData.ponderNextMove = TRUE;
\r
1655 appData.periodicUpdates = TRUE;
\r
1656 appData.popupExitMessage = TRUE;
\r
1657 appData.popupMoveErrors = FALSE;
\r
1658 appData.autoObserve = FALSE;
\r
1659 appData.autoComment = FALSE;
\r
1660 appData.animate = TRUE;
\r
1661 appData.animSpeed = 10;
\r
1662 appData.animateDragging = TRUE;
\r
1663 appData.highlightLastMove = TRUE;
\r
1664 appData.getMoveList = TRUE;
\r
1665 appData.testLegality = TRUE;
\r
1666 appData.premove = TRUE;
\r
1667 appData.premoveWhite = FALSE;
\r
1668 appData.premoveWhiteText = "";
\r
1669 appData.premoveBlack = FALSE;
\r
1670 appData.premoveBlackText = "";
\r
1671 appData.icsAlarm = TRUE;
\r
1672 appData.icsAlarmTime = 5000;
\r
1673 appData.autoRaiseBoard = TRUE;
\r
1674 appData.localLineEditing = TRUE;
\r
1675 appData.colorize = TRUE;
\r
1676 appData.reuseFirst = TRUE;
\r
1677 appData.reuseSecond = TRUE;
\r
1678 appData.blindfold = FALSE;
\r
1679 dcb.DCBlength = sizeof(DCB);
\r
1680 dcb.BaudRate = 9600;
\r
1681 dcb.fBinary = TRUE;
\r
1682 dcb.fParity = FALSE;
\r
1683 dcb.fOutxCtsFlow = FALSE;
\r
1684 dcb.fOutxDsrFlow = FALSE;
\r
1685 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1686 dcb.fDsrSensitivity = FALSE;
\r
1687 dcb.fTXContinueOnXoff = TRUE;
\r
1688 dcb.fOutX = FALSE;
\r
1690 dcb.fNull = FALSE;
\r
1691 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1692 dcb.fAbortOnError = FALSE;
\r
1693 dcb.wReserved = 0;
\r
1695 dcb.Parity = SPACEPARITY;
\r
1696 dcb.StopBits = ONESTOPBIT;
\r
1697 settingsFileName = SETTINGS_FILE;
\r
1698 saveSettingsOnExit = TRUE;
\r
1699 boardX = CW_USEDEFAULT;
\r
1700 boardY = CW_USEDEFAULT;
\r
1701 consoleX = CW_USEDEFAULT;
\r
1702 consoleY = CW_USEDEFAULT;
\r
1703 consoleW = CW_USEDEFAULT;
\r
1704 consoleH = CW_USEDEFAULT;
\r
1705 analysisX = CW_USEDEFAULT;
\r
1706 analysisY = CW_USEDEFAULT;
\r
1707 analysisW = CW_USEDEFAULT;
\r
1708 analysisH = CW_USEDEFAULT;
\r
1709 commentX = CW_USEDEFAULT;
\r
1710 commentY = CW_USEDEFAULT;
\r
1711 commentW = CW_USEDEFAULT;
\r
1712 commentH = CW_USEDEFAULT;
\r
1713 editTagsX = CW_USEDEFAULT;
\r
1714 editTagsY = CW_USEDEFAULT;
\r
1715 editTagsW = CW_USEDEFAULT;
\r
1716 editTagsH = CW_USEDEFAULT;
\r
1717 gameListX = CW_USEDEFAULT;
\r
1718 gameListY = CW_USEDEFAULT;
\r
1719 gameListW = CW_USEDEFAULT;
\r
1720 gameListH = CW_USEDEFAULT;
\r
1721 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1722 icsNames = ICS_NAMES;
\r
1723 firstChessProgramNames = FCP_NAMES;
\r
1724 secondChessProgramNames = SCP_NAMES;
\r
1725 appData.initialMode = "";
\r
1726 appData.variant = "normal";
\r
1727 appData.firstProtocolVersion = PROTOVER;
\r
1728 appData.secondProtocolVersion = PROTOVER;
\r
1729 appData.showButtonBar = TRUE;
\r
1731 /* [AS] New properties (see comments in header file) */
1732 appData.firstScoreIsAbsolute = FALSE;
1733 appData.secondScoreIsAbsolute = FALSE;
1734 appData.saveExtendedInfoInPGN = FALSE;
1735 appData.hideThinkingFromHuman = FALSE;
1736 appData.liteBackTextureFile = "";
1737 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
1738 appData.darkBackTextureFile = "";
1739 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
1740 appData.renderPiecesWithFont = "";
1741 appData.fontToPieceTable = "";
1742 appData.fontBackColorWhite = 0;
1743 appData.fontForeColorWhite = 0;
1744 appData.fontBackColorBlack = 0;
1745 appData.fontForeColorBlack = 0;
1746 appData.fontPieceSize = 80;
1747 appData.overrideLineGap = 1;
1748 appData.adjudicateLossThreshold = 0;
1749 appData.delayBeforeQuit = 0;
1750 appData.delayAfterQuit = 0;
1751 appData.nameOfDebugFile = "winboard.debug";
1752 appData.pgnEventHeader = "Computer Chess Game";
1755 appData.zippyTalk = ZIPPY_TALK;
\r
1756 appData.zippyPlay = ZIPPY_PLAY;
\r
1757 appData.zippyLines = ZIPPY_LINES;
\r
1758 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1759 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1760 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1761 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1762 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1763 appData.zippyUseI = ZIPPY_USE_I;
\r
1764 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1765 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1766 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1767 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1768 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1769 appData.zippyAbort = ZIPPY_ABORT;
\r
1770 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1771 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1772 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1775 /* Point font array elements to structures and
\r
1776 parse default font names */
\r
1777 for (i=0; i<NUM_FONTS; i++) {
\r
1778 for (j=0; j<NUM_SIZES; j++) {
\r
1779 font[j][i] = &fontRec[j][i];
\r
1780 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1784 /* Parse default settings file if any */
\r
1785 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1786 settingsFileName = strdup(buf);
\r
1789 /* Parse command line */
\r
1790 ParseArgs(StringGet, &lpCmdLine);
\r
1792 /* Propagate options that affect others */
\r
1793 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1794 if (appData.icsActive || appData.noChessProgram) {
\r
1795 chessProgram = FALSE; /* not local chess program mode */
\r
1798 /* Open startup dialog if needed */
\r
1799 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1800 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1801 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1802 *appData.secondChessProgram == NULLCHAR))) {
\r
1805 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1806 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1807 FreeProcInstance(lpProc);
\r
1810 /* Make sure save files land in the right (?) directory */
\r
1811 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1812 appData.saveGameFile = strdup(buf);
\r
1814 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1815 appData.savePositionFile = strdup(buf);
\r
1818 /* Finish initialization for fonts and sounds */
\r
1819 for (i=0; i<NUM_FONTS; i++) {
\r
1820 for (j=0; j<NUM_SIZES; j++) {
\r
1821 CreateFontInMF(font[j][i]);
\r
1824 /* xboard, and older WinBoards, controlled the move sound with the
\r
1825 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1826 always turn the option on (so that the backend will call us),
\r
1827 then let the user turn the sound off by setting it to silence if
\r
1828 desired. To accommodate old winboard.ini files saved by old
\r
1829 versions of WinBoard, we also turn off the sound if the option
\r
1830 was initially set to false. */
\r
1831 if (!appData.ringBellAfterMoves) {
\r
1832 sounds[(int)SoundMove].name = strdup("");
\r
1833 appData.ringBellAfterMoves = TRUE;
\r
1835 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1836 SetCurrentDirectory(installDir);
\r
1838 SetCurrentDirectory(currDir);
\r
1840 p = icsTextMenuString;
\r
1841 if (p[0] == '@') {
\r
1842 FILE* f = fopen(p + 1, "r");
\r
1844 DisplayFatalError(p + 1, errno, 2);
\r
1847 i = fread(buf, 1, sizeof(buf)-1, f);
\r
1849 buf[i] = NULLCHAR;
\r
1852 ParseIcsTextMenu(strdup(p));
\r
1859 HMENU hmenu = GetMenu(hwndMain);
\r
1861 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1862 MF_BYCOMMAND|((appData.icsActive &&
\r
1863 *appData.icsCommPort != NULLCHAR) ?
\r
1864 MF_ENABLED : MF_GRAYED));
\r
1865 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1866 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1867 MF_CHECKED : MF_UNCHECKED));
\r
1872 SaveSettings(char* name)
\r
1875 ArgDescriptor *ad;
\r
1876 WINDOWPLACEMENT wp;
\r
1877 char dir[MSG_SIZ];
\r
1879 if (!hwndMain) return;
\r
1881 GetCurrentDirectory(MSG_SIZ, dir);
\r
1882 SetCurrentDirectory(installDir);
\r
1883 f = fopen(name, "w");
\r
1884 SetCurrentDirectory(dir);
\r
1886 DisplayError(name, errno);
\r
1889 fprintf(f, ";\n");
\r
1890 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
1891 fprintf(f, ";\n");
\r
1892 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
1893 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
1894 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
1895 fprintf(f, ";\n");
\r
1897 wp.length = sizeof(WINDOWPLACEMENT);
\r
1898 GetWindowPlacement(hwndMain, &wp);
\r
1899 boardX = wp.rcNormalPosition.left;
\r
1900 boardY = wp.rcNormalPosition.top;
\r
1902 if (hwndConsole) {
\r
1903 GetWindowPlacement(hwndConsole, &wp);
\r
1904 consoleX = wp.rcNormalPosition.left;
\r
1905 consoleY = wp.rcNormalPosition.top;
\r
1906 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1907 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1910 if (analysisDialog) {
\r
1911 GetWindowPlacement(analysisDialog, &wp);
\r
1912 analysisX = wp.rcNormalPosition.left;
\r
1913 analysisY = wp.rcNormalPosition.top;
\r
1914 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1915 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1918 if (commentDialog) {
\r
1919 GetWindowPlacement(commentDialog, &wp);
\r
1920 commentX = wp.rcNormalPosition.left;
\r
1921 commentY = wp.rcNormalPosition.top;
\r
1922 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1923 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1926 if (editTagsDialog) {
\r
1927 GetWindowPlacement(editTagsDialog, &wp);
\r
1928 editTagsX = wp.rcNormalPosition.left;
\r
1929 editTagsY = wp.rcNormalPosition.top;
\r
1930 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1931 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1934 if (gameListDialog) {
\r
1935 GetWindowPlacement(gameListDialog, &wp);
\r
1936 gameListX = wp.rcNormalPosition.left;
\r
1937 gameListY = wp.rcNormalPosition.top;
\r
1938 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1939 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1942 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
1943 if (!ad->save) continue;
\r
1944 switch (ad->argType) {
\r
1947 char *p = *(char **)ad->argLoc;
\r
1948 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
1949 /* Quote multiline values or \-containing values
\r
1950 with { } if possible */
\r
1951 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
1953 /* Else quote with " " */
\r
1954 fprintf(f, "/%s=\"", ad->argName);
\r
1956 if (*p == '\n') fprintf(f, "\n");
\r
1957 else if (*p == '\r') fprintf(f, "\\r");
\r
1958 else if (*p == '\t') fprintf(f, "\\t");
\r
1959 else if (*p == '\b') fprintf(f, "\\b");
\r
1960 else if (*p == '\f') fprintf(f, "\\f");
\r
1961 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
1962 else if (*p == '\"') fprintf(f, "\\\"");
\r
1963 else if (*p == '\\') fprintf(f, "\\\\");
\r
1967 fprintf(f, "\"\n");
\r
1972 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
1975 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
1978 fprintf(f, "/%s=%s\n", ad->argName,
\r
1979 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
1982 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1985 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1989 COLORREF color = *(COLORREF *)ad->argLoc;
\r
1990 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
1991 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1996 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1997 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
1998 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1999 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2000 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2001 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2002 (ta->effects) ? " " : "",
\r
2003 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2007 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2008 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2010 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2013 case ArgBoardSize:
\r
2014 fprintf(f, "/%s=%s\n", ad->argName,
\r
2015 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2020 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2021 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2022 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2023 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2024 ad->argName, mfp->faceName, mfp->pointSize,
\r
2025 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2026 mfp->bold ? "b" : "",
\r
2027 mfp->italic ? "i" : "",
\r
2028 mfp->underline ? "u" : "",
\r
2029 mfp->strikeout ? "s" : "");
\r
2033 case ArgCommSettings:
\r
2034 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2042 /*---------------------------------------------------------------------------*\
\r
2044 * GDI board drawing routines
\r
2046 \*---------------------------------------------------------------------------*/
\r
2048 /* [AS] Draw square using background texture */
2049 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
2054 return; /* Should never happen! */
2057 SetGraphicsMode( dst, GM_ADVANCED );
2069 x.eDx = (FLOAT) dw + dx - 1;
2072 SetWorldTransform( dst, &x );
2081 x.eDy = (FLOAT) dh + dy - 1;
2083 SetWorldTransform( dst, &x );
2095 SetWorldTransform( dst, &x );
2099 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
2107 SetWorldTransform( dst, &x );
2109 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
2128 static HFONT hPieceFont = NULL;
2129 static HBITMAP hPieceMask[12];
2130 static HBITMAP hPieceFace[12];
2131 static int fontBitmapSquareSize = 0;
2132 static char pieceToFontChar[12] = { 'p', 'n', 'b', 'r', 'q', 'k', 'o', 'm', 'v', 't', 'w', 'l' };
2134 static BOOL SetPieceToFontCharTable( const char * map )
2136 BOOL result = FALSE;
2138 if( map != NULL && strlen(map) == 12 ) {
2141 for( i=0; i<12; i++ ) {
2142 pieceToFontChar[i] = map[i];
2151 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
2154 BYTE r1 = GetRValue( color );
2155 BYTE g1 = GetGValue( color );
2156 BYTE b1 = GetBValue( color );
2162 /* Create a uniform background first */
2163 hbrush = CreateSolidBrush( color );
2164 SetRect( &rc, 0, 0, squareSize, squareSize );
2165 FillRect( hdc, &rc, hbrush );
2166 DeleteObject( hbrush );
2169 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
2170 int steps = squareSize / 2;
2173 for( i=0; i<steps; i++ ) {
2174 BYTE r = r1 - (r1-r2) * i / steps;
2175 BYTE g = g1 - (g1-g2) * i / steps;
2176 BYTE b = b1 - (b1-b2) * i / steps;
2178 hbrush = CreateSolidBrush( RGB(r,g,b) );
2179 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
2180 FillRect( hdc, &rc, hbrush );
2181 DeleteObject(hbrush);
2184 else if( mode == 2 ) {
2185 /* Diagonal gradient, good more or less for every piece */
2187 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
2189 int steps = squareSize;
2192 triangle[0].x = squareSize - steps;
2193 triangle[0].y = squareSize;
2194 triangle[1].x = squareSize;
2195 triangle[1].y = squareSize;
2196 triangle[2].x = squareSize;
2197 triangle[2].y = squareSize - steps;
2199 for( i=0; i<steps; i++ ) {
2200 BYTE r = r1 - (r1-r2) * i / steps;
2201 BYTE g = g1 - (g1-g2) * i / steps;
2202 BYTE b = b1 - (b1-b2) * i / steps;
2204 hbrush = CreateSolidBrush( RGB(r,g,b) );
2205 hbrush_old = SelectObject( hdc, hbrush );
2206 Polygon( hdc, triangle, 3 );
2207 SelectObject( hdc, hbrush_old );
2208 DeleteObject(hbrush);
2213 SelectObject( hdc, hpen );
2218 [AS] The method I use to create the bitmaps it a bit tricky, but it
2219 seems to work ok. The main problem here is to find the "inside" of a chess
2220 piece: follow the steps as explained below.
2222 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
2226 COLORREF chroma = RGB(0xFF,0x00,0xFF);
2230 int backColor = whitePieceColor;
2231 int foreColor = blackPieceColor;
2232 int shapeIndex = index < 6 ? index+6 : index;
2234 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
2235 backColor = appData.fontBackColorWhite;
2236 foreColor = appData.fontForeColorWhite;
2238 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
2239 backColor = appData.fontBackColorBlack;
2240 foreColor = appData.fontForeColorBlack;
2244 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2246 hbm_old = SelectObject( hdc, hbm );
2250 rc.right = squareSize;
2251 rc.bottom = squareSize;
2253 /* Step 1: background is now black */
2254 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
2256 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
2258 pt.x = (squareSize - sz.cx) / 2;
2259 pt.y = (squareSize - sz.cy) / 2;
2261 SetBkMode( hdc, TRANSPARENT );
2262 SetTextColor( hdc, chroma );
2263 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
2264 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2266 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
2267 /* Step 3: the area outside the piece is filled with white */
2268 FloodFill( hdc, 0, 0, chroma );
2269 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
2271 Step 4: this is the tricky part, the area inside the piece is filled with black,
2272 but if the start point is not inside the piece we're lost!
2273 There should be a better way to do this... if we could create a region or path
2274 from the fill operation we would be fine for example.
2276 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
2278 SetTextColor( hdc, 0 );
2280 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
2281 draw the piece again in black for safety.
2283 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2285 SelectObject( hdc, hbm_old );
2287 if( hPieceMask[index] != NULL ) {
2288 DeleteObject( hPieceMask[index] );
2291 hPieceMask[index] = hbm;
2294 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2296 SelectObject( hdc, hbm );
2299 HDC dc1 = CreateCompatibleDC( hdc_window );
2300 HDC dc2 = CreateCompatibleDC( hdc_window );
2301 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2303 SelectObject( dc1, hPieceMask[index] );
2304 SelectObject( dc2, bm2 );
2305 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
2306 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
2309 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
2310 the piece background and deletes (makes transparent) the rest.
2311 Thanks to that mask, we are free to paint the background with the greates
2312 freedom, as we'll be able to mask off the unwanted parts when finished.
2313 We use this, to make gradients and give the pieces a "roundish" look.
2315 SetPieceBackground( hdc, backColor, 2 );
2316 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
2320 DeleteObject( bm2 );
2323 SetTextColor( hdc, foreColor );
2324 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2326 SelectObject( hdc, hbm_old );
2328 hPieceFace[index] = hbm;
2331 static int TranslatePieceToFontPiece( int piece )
2363 void CreatePiecesFromFont()
2366 HDC hdc_window = NULL;
2372 if( fontBitmapSquareSize < 0 ) {
2373 /* Something went seriously wrong in the past: do not try to recreate fonts! */
2377 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
2378 fontBitmapSquareSize = -1;
2382 if( fontBitmapSquareSize != squareSize ) {
2383 hdc_window = GetDC( hwndMain );
2384 hdc = CreateCompatibleDC( hdc_window );
2386 if( hPieceFont != NULL ) {
2387 DeleteObject( hPieceFont );
2390 for( i=0; i<12; i++ ) {
2391 hPieceMask[i] = NULL;
2397 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
2398 fontHeight = appData.fontPieceSize;
2401 fontHeight = (fontHeight * squareSize) / 100;
2403 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
2405 lf.lfEscapement = 0;
2406 lf.lfOrientation = 0;
2407 lf.lfWeight = FW_NORMAL;
2411 lf.lfCharSet = DEFAULT_CHARSET;
2412 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
2413 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2414 lf.lfQuality = PROOF_QUALITY;
2415 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
2416 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
2417 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
2419 hPieceFont = CreateFontIndirect( &lf );
2421 if( hPieceFont == NULL ) {
2422 fontBitmapSquareSize = -2;
2425 /* Setup font-to-piece character table */
2426 if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) {
2427 /* No (or wrong) global settings, try to detect the font */
2428 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
2430 SetPieceToFontCharTable("phbrqkojntwl");
2432 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
2433 /* DiagramTT* family */
2434 SetPieceToFontCharTable("PNLRQKpnlrqk");
2437 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
2438 SetPieceToFontCharTable("pnbrqkomvtwl");
2442 /* Create bitmaps */
2443 hfont_old = SelectObject( hdc, hPieceFont );
2445 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
2446 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
2447 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
2448 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
2449 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
2450 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
2451 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
2452 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
2453 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
2454 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
2455 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
2456 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
2458 SelectObject( hdc, hfont_old );
2460 fontBitmapSquareSize = squareSize;
2468 if( hdc_window != NULL ) {
2469 ReleaseDC( hwndMain, hdc_window );
2474 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2478 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2479 if (gameInfo.event &&
\r
2480 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2481 strcmp(name, "k80s") == 0) {
\r
2482 strcpy(name, "tim");
\r
2484 return LoadBitmap(hinst, name);
\r
2488 /* Insert a color into the program's logical palette
\r
2489 structure. This code assumes the given color is
\r
2490 the result of the RGB or PALETTERGB macro, and it
\r
2491 knows how those macros work (which is documented).
\r
2494 InsertInPalette(COLORREF color)
\r
2496 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2498 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2499 DisplayFatalError("Too many colors", 0, 1);
\r
2500 pLogPal->palNumEntries--;
\r
2504 pe->peFlags = (char) 0;
\r
2505 pe->peRed = (char) (0xFF & color);
\r
2506 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2507 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2513 InitDrawingColors()
\r
2515 if (pLogPal == NULL) {
\r
2516 /* Allocate enough memory for a logical palette with
\r
2517 * PALETTESIZE entries and set the size and version fields
\r
2518 * of the logical palette structure.
\r
2520 pLogPal = (NPLOGPALETTE)
\r
2521 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2522 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2523 pLogPal->palVersion = 0x300;
\r
2525 pLogPal->palNumEntries = 0;
\r
2527 InsertInPalette(lightSquareColor);
\r
2528 InsertInPalette(darkSquareColor);
\r
2529 InsertInPalette(whitePieceColor);
\r
2530 InsertInPalette(blackPieceColor);
\r
2531 InsertInPalette(highlightSquareColor);
\r
2532 InsertInPalette(premoveHighlightColor);
\r
2534 /* create a logical color palette according the information
\r
2535 * in the LOGPALETTE structure.
\r
2537 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2539 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2540 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2541 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2542 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2543 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2545 /* [AS] Force rendering of the font-based pieces */
2546 if( fontBitmapSquareSize > 0 ) {
2547 fontBitmapSquareSize = 0;
2553 BoardWidth(int boardSize)
\r
2555 int lineGap = sizeInfo[boardSize].lineGap;
2557 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
2558 lineGap = appData.overrideLineGap;
2561 return (BOARD_SIZE + 1) * lineGap +
2562 BOARD_SIZE * sizeInfo[boardSize].squareSize;
\r
2565 /* Respond to board resize by dragging edge */
\r
2567 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2569 BoardSize newSize = NUM_SIZES - 1;
\r
2570 static int recurse = 0;
\r
2571 if (IsIconic(hwndMain)) return;
\r
2572 if (recurse > 0) return;
\r
2574 while (newSize > 0 &&
\r
2575 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2576 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2579 boardSize = newSize;
\r
2580 InitDrawingSizes(boardSize, flags);
\r
2587 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2589 int i, boardWidth;
\r
2590 ChessSquare piece;
\r
2591 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2593 SIZE clockSize, messageSize;
\r
2595 char buf[MSG_SIZ];
\r
2597 HMENU hmenu = GetMenu(hwndMain);
\r
2598 RECT crect, wrect;
\r
2600 LOGBRUSH logbrush;
\r
2602 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2603 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2604 squareSize = sizeInfo[boardSize].squareSize;
\r
2605 lineGap = sizeInfo[boardSize].lineGap;
\r
2607 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
2608 lineGap = appData.overrideLineGap;
2611 if (tinyLayout != oldTinyLayout) {
\r
2612 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2614 style &= ~WS_SYSMENU;
\r
2615 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2616 "&Minimize\tCtrl+F4");
\r
2618 style |= WS_SYSMENU;
\r
2619 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2621 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2623 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2624 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2625 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2627 DrawMenuBar(hwndMain);
\r
2630 boardWidth = BoardWidth(boardSize);
\r
2632 /* Get text area sizes */
\r
2633 hdc = GetDC(hwndMain);
\r
2634 if (appData.clockMode) {
\r
2635 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2637 sprintf(buf, "White");
\r
2639 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2640 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2641 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2642 str = "We only care about the height here";
\r
2643 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2644 SelectObject(hdc, oldFont);
\r
2645 ReleaseDC(hwndMain, hdc);
\r
2647 /* Compute where everything goes */
\r
2648 whiteRect.left = OUTER_MARGIN;
\r
2649 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2650 whiteRect.top = OUTER_MARGIN;
\r
2651 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2653 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2654 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2655 blackRect.top = whiteRect.top;
\r
2656 blackRect.bottom = whiteRect.bottom;
\r
2658 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2659 if (appData.showButtonBar) {
\r
2660 messageRect.right = blackRect.right
\r
2661 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2663 messageRect.right = blackRect.right;
\r
2665 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2666 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2668 boardRect.left = whiteRect.left;
\r
2669 boardRect.right = boardRect.left + boardWidth;
\r
2670 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2671 boardRect.bottom = boardRect.top + boardWidth;
\r
2673 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2674 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2675 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2676 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2677 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2678 GetWindowRect(hwndMain, &wrect);
\r
2679 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2680 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2681 /* compensate if menu bar wrapped */
\r
2682 GetClientRect(hwndMain, &crect);
\r
2683 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2684 winHeight += offby;
\r
2686 case WMSZ_TOPLEFT:
\r
2687 SetWindowPos(hwndMain, NULL,
\r
2688 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2689 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2692 case WMSZ_TOPRIGHT:
\r
2694 SetWindowPos(hwndMain, NULL,
\r
2695 wrect.left, wrect.bottom - winHeight,
\r
2696 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2699 case WMSZ_BOTTOMLEFT:
\r
2701 SetWindowPos(hwndMain, NULL,
\r
2702 wrect.right - winWidth, wrect.top,
\r
2703 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2706 case WMSZ_BOTTOMRIGHT:
\r
2710 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2711 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2716 for (i = 0; i < N_BUTTONS; i++) {
\r
2717 if (buttonDesc[i].hwnd != NULL) {
\r
2718 DestroyWindow(buttonDesc[i].hwnd);
\r
2719 buttonDesc[i].hwnd = NULL;
\r
2721 if (appData.showButtonBar) {
\r
2722 buttonDesc[i].hwnd =
\r
2723 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2724 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2725 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2726 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2727 (HMENU) buttonDesc[i].id,
\r
2728 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2730 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2731 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2732 MAKELPARAM(FALSE, 0));
\r
2734 if (buttonDesc[i].id == IDM_Pause)
\r
2735 hwndPause = buttonDesc[i].hwnd;
\r
2736 buttonDesc[i].wndproc = (WNDPROC)
\r
2737 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2740 if (gridPen != NULL) DeleteObject(gridPen);
\r
2741 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2742 if (premovePen != NULL) DeleteObject(premovePen);
\r
2743 if (lineGap != 0) {
\r
2744 logbrush.lbStyle = BS_SOLID;
\r
2745 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2747 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2748 lineGap, &logbrush, 0, NULL);
\r
2749 logbrush.lbColor = highlightSquareColor;
\r
2751 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2752 lineGap, &logbrush, 0, NULL);
\r
2754 logbrush.lbColor = premoveHighlightColor;
\r
2756 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2757 lineGap, &logbrush, 0, NULL);
\r
2759 for (i = 0; i < BOARD_SIZE + 1; i++) {
\r
2760 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2761 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2;
\r
2762 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2763 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2764 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2765 BOARD_SIZE * (squareSize + lineGap);
\r
2766 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x =
\r
2767 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left +
\r
2768 lineGap / 2 + (i * (squareSize + lineGap));
\r
2769 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y =
\r
2770 boardRect.top + BOARD_SIZE * (squareSize + lineGap);
\r
2771 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2775 if (boardSize == oldBoardSize) return;
\r
2776 oldBoardSize = boardSize;
\r
2777 oldTinyLayout = tinyLayout;
\r
2779 /* Load piece bitmaps for this board size */
\r
2780 for (i=0; i<=2; i++) {
\r
2781 for (piece = WhitePawn;
\r
2782 (int) piece <= (int) WhiteKing;
\r
2783 piece = (ChessSquare) ((int) piece + 1)) {
\r
2784 if (pieceBitmap[i][piece] != NULL)
\r
2785 DeleteObject(pieceBitmap[i][piece]);
\r
2789 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2790 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2791 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2792 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2793 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2794 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2795 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2796 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2797 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2798 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2799 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2800 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2801 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2802 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2803 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2804 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2805 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2806 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2811 PieceBitmap(ChessSquare p, int kind)
\r
2813 if ((int) p >= (int) BlackPawn)
\r
2814 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2816 return pieceBitmap[kind][(int) p];
\r
2819 /***************************************************************/
\r
2821 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2822 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2824 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2825 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2829 SquareToPos(int row, int column, int * x, int * y)
\r
2832 *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
2833 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2835 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2836 *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
2841 DrawCoordsOnDC(HDC hdc)
\r
2843 static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'};
\r
2844 static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'};
\r
2845 char str[2] = { NULLCHAR, NULLCHAR };
\r
2846 int oldMode, oldAlign, x, y, start, i;
\r
2850 if (!appData.showCoords)
\r
2853 start = flipView ? 0 : 8;
\r
2855 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2856 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2857 oldAlign = GetTextAlign(hdc);
\r
2858 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2860 y = boardRect.top + lineGap;
\r
2861 x = boardRect.left + lineGap;
\r
2863 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2864 for (i = 0; i < 8; i++) {
\r
2865 str[0] = files[start + i];
\r
2866 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2867 y += squareSize + lineGap;
\r
2870 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2871 for (i = 0; i < 8; i++) {
\r
2872 str[0] = ranks[start + i];
\r
2873 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2874 x += squareSize + lineGap;
\r
2877 SelectObject(hdc, oldBrush);
\r
2878 SetBkMode(hdc, oldMode);
\r
2879 SetTextAlign(hdc, oldAlign);
\r
2880 SelectObject(hdc, oldFont);
\r
2884 DrawGridOnDC(HDC hdc)
\r
2888 if (lineGap != 0) {
\r
2889 oldPen = SelectObject(hdc, gridPen);
\r
2890 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2);
\r
2891 SelectObject(hdc, oldPen);
\r
2895 #define HIGHLIGHT_PEN 0
\r
2896 #define PREMOVE_PEN 1
\r
2899 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2902 HPEN oldPen, hPen;
\r
2903 if (lineGap == 0) return;
\r
2905 x1 = boardRect.left +
\r
2906 lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap);
\r
2907 y1 = boardRect.top +
\r
2908 lineGap/2 + y * (squareSize + lineGap);
\r
2910 x1 = boardRect.left +
\r
2911 lineGap/2 + x * (squareSize + lineGap);
\r
2912 y1 = boardRect.top +
\r
2913 lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap);
\r
2915 hPen = pen ? premovePen : highlightPen;
\r
2916 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2917 MoveToEx(hdc, x1, y1, NULL);
\r
2918 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2919 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2920 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2921 LineTo(hdc, x1, y1);
\r
2922 SelectObject(hdc, oldPen);
\r
2926 DrawHighlightsOnDC(HDC hdc)
\r
2929 for (i=0; i<2; i++) {
\r
2930 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
2931 DrawHighlightOnDC(hdc, TRUE,
\r
2932 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
2935 for (i=0; i<2; i++) {
\r
2936 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2937 premoveHighlightInfo.sq[i].y >= 0) {
\r
2938 DrawHighlightOnDC(hdc, TRUE,
\r
2939 premoveHighlightInfo.sq[i].x,
\r
2940 premoveHighlightInfo.sq[i].y,
\r
2946 /* Note: sqcolor is used only in monoMode */
\r
2947 /* Note that this code is largely duplicated in woptions.c,
\r
2948 function DrawSampleSquare, so that needs to be updated too */
\r
2950 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2952 HBITMAP oldBitmap;
\r
2955 if (appData.blindfold) return;
\r
2957 /* [AS] Use font-based pieces if needed */
2958 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
2959 /* Create piece bitmaps, or do nothing if piece set is up to data */
2960 CreatePiecesFromFont();
2962 if( fontBitmapSquareSize == squareSize ) {
2963 int index = TranslatePieceToFontPiece( piece );
2965 SelectObject( tmphdc, hPieceMask[ index ] );
2969 squareSize, squareSize,
2974 SelectObject( tmphdc, hPieceFace[ index ] );
2978 squareSize, squareSize,
2987 if (appData.monoMode) {
\r
2988 SelectObject(tmphdc, PieceBitmap(piece,
\r
2989 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2990 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2991 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2994 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2995 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2996 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
2998 /* Use black piece color for outline of white pieces */
\r
2999 /* Not sure this looks really good (though xboard does it).
\r
3000 Maybe better to have another selectable color, default black */
\r
3001 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3002 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3003 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3005 /* Use black for outline of white pieces */
\r
3006 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3007 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
3011 /* Use white piece color for details of black pieces */
\r
3012 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3013 WHITE_PIECE ones aren't always the right shape. */
\r
3014 /* Not sure this looks really good (though xboard does it).
\r
3015 Maybe better to have another selectable color, default medium gray? */
\r
3016 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3017 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3018 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3019 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3020 SelectObject(hdc, blackPieceBrush);
\r
3021 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3023 /* Use square color for details of black pieces */
\r
3024 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3025 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3026 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3029 SelectObject(hdc, oldBrush);
\r
3030 SelectObject(tmphdc, oldBitmap);
\r
3034 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
3035 int GetBackTextureMode( int algo )
3037 int result = BACK_TEXTURE_MODE_DISABLED;
3041 case BACK_TEXTURE_MODE_PLAIN:
3042 result = 1; /* Always use identity map */
3044 case BACK_TEXTURE_MODE_FULL_RANDOM:
3045 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
3053 [AS] Compute and save texture drawing info, otherwise we may not be able
3054 to handle redraws cleanly (as random numbers would always be different).
3056 VOID RebuildTextureSquareInfo()
3066 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
3068 if( liteBackTexture != NULL ) {
3069 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
3070 lite_w = bi.bmWidth;
3071 lite_h = bi.bmHeight;
3075 if( darkBackTexture != NULL ) {
3076 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
3077 dark_w = bi.bmWidth;
3078 dark_h = bi.bmHeight;
3082 for( row=0; row<BOARD_SIZE; row++ ) {
3083 for( col=0; col<BOARD_SIZE; col++ ) {
3084 if( (col + row) & 1 ) {
3086 if( lite_w >= squareSize && lite_h >= squareSize ) {
3087 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_SIZE;
3088 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_SIZE;
3089 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
3094 if( dark_w >= squareSize && dark_h >= squareSize ) {
3095 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_SIZE;
3096 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_SIZE;
3097 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
3105 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3107 int row, column, x, y, square_color, piece_color;
\r
3108 ChessSquare piece;
\r
3110 HDC texture_hdc = NULL;
3112 /* [AS] Initialize background textures if needed */
3113 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
3114 if( backTextureSquareSize != squareSize ) {
3115 backTextureSquareSize = squareSize;
3116 RebuildTextureSquareInfo();
3119 texture_hdc = CreateCompatibleDC( hdc );
3122 for (row = 0; row < BOARD_SIZE; row++) {
\r
3123 for (column = 0; column < BOARD_SIZE; column++) {
\r
3125 SquareToPos(row, column, &x, &y);
\r
3127 piece = board[row][column];
\r
3129 square_color = ((column + row) % 2) == 1;
\r
3130 piece_color = (int) piece < (int) BlackPawn;
\r
3132 if (appData.monoMode) {
\r
3133 if (piece == EmptySquare) {
\r
3134 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3135 square_color ? WHITENESS : BLACKNESS);
\r
3137 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3140 else if( backTextureSquareInfo[row][column].mode > 0 ) {
3141 /* [AS] Draw the square using a texture bitmap */
3142 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
3145 squareSize, squareSize,
3148 backTextureSquareInfo[row][column].mode,
3149 backTextureSquareInfo[row][column].x,
3150 backTextureSquareInfo[row][column].y );
3152 SelectObject( texture_hdc, hbm );
3154 if (piece != EmptySquare) {
3155 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
3159 oldBrush = SelectObject(hdc, square_color ?
\r
3160 lightSquareBrush : darkSquareBrush);
\r
3161 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3162 SelectObject(hdc, oldBrush);
\r
3163 if (piece != EmptySquare)
\r
3164 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3169 if( texture_hdc != NULL ) {
3170 DeleteDC( texture_hdc );
3174 #define MAX_CLIPS 200 /* more than enough */
\r
3177 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3179 static Board lastReq, lastDrawn;
\r
3180 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3181 static int lastDrawnFlipView = 0;
\r
3182 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3183 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3186 HBITMAP bufferBitmap;
\r
3187 HBITMAP oldBitmap;
\r
3189 HRGN clips[MAX_CLIPS];
\r
3190 ChessSquare dragged_piece = EmptySquare;
\r
3192 /* I'm undecided on this - this function figures out whether a full
\r
3193 * repaint is necessary on its own, so there's no real reason to have the
\r
3194 * caller tell it that. I think this can safely be set to FALSE - but
\r
3195 * if we trust the callers not to request full repaints unnessesarily, then
\r
3196 * we could skip some clipping work. In other words, only request a full
\r
3197 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3198 * gamestart and similar) --Hawk
\r
3200 Boolean fullrepaint = repaint;
\r
3202 if (board == NULL) {
\r
3203 if (!lastReqValid) {
\r
3208 CopyBoard(lastReq, board);
\r
3212 if (doingSizing) {
\r
3216 if (IsIconic(hwndMain)) {
\r
3220 if (hdc == NULL) {
\r
3221 hdc = GetDC(hwndMain);
\r
3222 if (!appData.monoMode) {
\r
3223 SelectPalette(hdc, hPal, FALSE);
\r
3224 RealizePalette(hdc);
\r
3228 releaseDC = FALSE;
\r
3232 fprintf(debugFP, "*******************************\n"
\r
3234 "dragInfo.from (%d,%d)\n"
\r
3235 "dragInfo.start (%d,%d)\n"
\r
3236 "dragInfo.pos (%d,%d)\n"
\r
3237 "dragInfo.lastpos (%d,%d)\n",
\r
3238 repaint ? "TRUE" : "FALSE",
\r
3239 dragInfo.from.x, dragInfo.from.y,
\r
3240 dragInfo.start.x, dragInfo.start.y,
\r
3241 dragInfo.pos.x, dragInfo.pos.y,
\r
3242 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
3243 fprintf(debugFP, "prev: ");
\r
3244 for (row = 0; row < 8; row++) {
\r
3245 for (column = 0; column < 8; column++) {
\r
3246 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
3249 fprintf(debugFP, "\n");
\r
3250 fprintf(debugFP, "board: ");
\r
3251 for (row = 0; row < 8; row++) {
\r
3252 for (column = 0; column < 8; column++) {
\r
3253 fprintf(debugFP, "%d ", board[row][column]);
\r
3256 fprintf(debugFP, "\n");
\r
3260 /* Create some work-DCs */
\r
3261 hdcmem = CreateCompatibleDC(hdc);
\r
3262 tmphdc = CreateCompatibleDC(hdc);
\r
3264 /* Figure out which squares need updating by comparing the
\r
3265 * newest board with the last drawn board and checking if
\r
3266 * flipping has changed.
\r
3268 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3269 for (row = 0; row < 8; row++) {
\r
3270 for (column = 0; column < 8; column++) {
\r
3271 if (lastDrawn[row][column] != board[row][column]) {
\r
3272 SquareToPos(row, column, &x, &y);
\r
3273 clips[num_clips++] =
\r
3274 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3278 for (i=0; i<2; i++) {
\r
3279 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3280 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3281 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3282 lastDrawnHighlight.sq[i].y >= 0) {
\r
3283 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3284 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3285 clips[num_clips++] =
\r
3286 CreateRectRgn(x - lineGap, y - lineGap,
\r
3287 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3289 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3290 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3291 clips[num_clips++] =
\r
3292 CreateRectRgn(x - lineGap, y - lineGap,
\r
3293 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3297 for (i=0; i<2; i++) {
\r
3298 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3299 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3300 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3301 lastDrawnPremove.sq[i].y >= 0) {
\r
3302 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3303 lastDrawnPremove.sq[i].x, &x, &y);
\r
3304 clips[num_clips++] =
\r
3305 CreateRectRgn(x - lineGap, y - lineGap,
\r
3306 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3308 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3309 premoveHighlightInfo.sq[i].y >= 0) {
\r
3310 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3311 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3312 clips[num_clips++] =
\r
3313 CreateRectRgn(x - lineGap, y - lineGap,
\r
3314 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3319 fullrepaint = TRUE;
\r
3322 /* Create a buffer bitmap - this is the actual bitmap
\r
3323 * being written to. When all the work is done, we can
\r
3324 * copy it to the real DC (the screen). This avoids
\r
3325 * the problems with flickering.
\r
3327 GetClientRect(hwndMain, &Rect);
\r
3328 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3329 Rect.bottom-Rect.top+1);
\r
3330 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3331 if (!appData.monoMode) {
\r
3332 SelectPalette(hdcmem, hPal, FALSE);
\r
3335 /* Create clips for dragging */
\r
3336 if (!fullrepaint) {
\r
3337 if (dragInfo.from.x >= 0) {
\r
3338 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3339 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3341 if (dragInfo.start.x >= 0) {
\r
3342 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3343 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3345 if (dragInfo.pos.x >= 0) {
\r
3346 x = dragInfo.pos.x - squareSize / 2;
\r
3347 y = dragInfo.pos.y - squareSize / 2;
\r
3348 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3350 if (dragInfo.lastpos.x >= 0) {
\r
3351 x = dragInfo.lastpos.x - squareSize / 2;
\r
3352 y = dragInfo.lastpos.y - squareSize / 2;
\r
3353 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3357 /* If dragging is in progress, we temporarely remove the piece */
\r
3358 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3359 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3360 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3363 /* Are we animating a move?
\r
3365 * - remove the piece from the board (temporarely)
\r
3366 * - calculate the clipping region
\r
3368 if (!fullrepaint) {
\r
3369 if (animInfo.piece != EmptySquare) {
\r
3370 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3371 x = boardRect.left + animInfo.lastpos.x;
\r
3372 y = boardRect.top + animInfo.lastpos.y;
\r
3373 x2 = boardRect.left + animInfo.pos.x;
\r
3374 y2 = boardRect.top + animInfo.pos.y;
\r
3375 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3376 /* Slight kludge. The real problem is that after AnimateMove is
\r
3377 done, the position on the screen does not match lastDrawn.
\r
3378 This currently causes trouble only on e.p. captures in
\r
3379 atomic, where the piece moves to an empty square and then
\r
3380 explodes. The old and new positions both had an empty square
\r
3381 at the destination, but animation has drawn a piece there and
\r
3382 we have to remember to erase it. */
\r
3383 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3387 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3388 if (num_clips == 0)
\r
3389 fullrepaint = TRUE;
\r
3391 /* Set clipping on the memory DC */
\r
3392 if (!fullrepaint) {
\r
3393 SelectClipRgn(hdcmem, clips[0]);
\r
3394 for (x = 1; x < num_clips; x++) {
\r
3395 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3396 abort(); // this should never ever happen!
\r
3400 /* Do all the drawing to the memory DC */
\r
3401 DrawGridOnDC(hdcmem);
\r
3402 DrawHighlightsOnDC(hdcmem);
\r
3403 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3404 DrawCoordsOnDC(hdcmem);
\r
3406 /* Put the dragged piece back into place and draw it */
\r
3407 if (dragged_piece != EmptySquare) {
\r
3408 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3409 x = dragInfo.pos.x - squareSize / 2;
\r
3410 y = dragInfo.pos.y - squareSize / 2;
\r
3411 DrawPieceOnDC(hdcmem, dragged_piece,
\r
3412 ((int) dragged_piece < (int) BlackPawn),
\r
3413 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3416 /* Put the animated piece back into place and draw it */
\r
3417 if (animInfo.piece != EmptySquare) {
\r
3418 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3419 x = boardRect.left + animInfo.pos.x;
\r
3420 y = boardRect.top + animInfo.pos.y;
\r
3421 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3422 ((int) animInfo.piece < (int) BlackPawn),
\r
3423 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3426 /* Release the bufferBitmap by selecting in the old bitmap
\r
3427 * and delete the memory DC
\r
3429 SelectObject(hdcmem, oldBitmap);
\r
3432 /* Set clipping on the target DC */
\r
3433 if (!fullrepaint) {
\r
3434 SelectClipRgn(hdc, clips[0]);
\r
3435 for (x = 1; x < num_clips; x++) {
\r
3436 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3437 abort(); // this should never ever happen!
\r
3441 /* Copy the new bitmap onto the screen in one go.
\r
3442 * This way we avoid any flickering
\r
3444 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3445 BitBlt(hdc, boardRect.left, boardRect.top,
\r
3446 boardRect.right - boardRect.left,
\r
3447 boardRect.bottom - boardRect.top,
\r
3448 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3449 SelectObject(tmphdc, oldBitmap);
\r
3451 /* Massive cleanup */
\r
3452 for (x = 0; x < num_clips; x++)
\r
3453 DeleteObject(clips[x]);
\r
3456 DeleteObject(bufferBitmap);
\r
3459 ReleaseDC(hwndMain, hdc);
\r
3461 if (lastDrawnFlipView != flipView) {
\r
3463 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
3465 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
3468 CopyBoard(lastDrawn, board);
\r
3469 lastDrawnHighlight = highlightInfo;
\r
3470 lastDrawnPremove = premoveHighlightInfo;
\r
3471 lastDrawnFlipView = flipView;
\r
3472 lastDrawnValid = 1;
\r
3476 /*---------------------------------------------------------------------------*\
\r
3477 | CLIENT PAINT PROCEDURE
\r
3478 | This is the main event-handler for the WM_PAINT message.
\r
3480 \*---------------------------------------------------------------------------*/
\r
3482 PaintProc(HWND hwnd)
\r
3488 if(hdc = BeginPaint(hwnd, &ps)) {
\r
3489 if (IsIconic(hwnd)) {
\r
3490 DrawIcon(hdc, 2, 2, iconCurrent);
\r
3492 if (!appData.monoMode) {
\r
3493 SelectPalette(hdc, hPal, FALSE);
\r
3494 RealizePalette(hdc);
\r
3496 HDCDrawPosition(hdc, 1, NULL);
\r
3498 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3499 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
3500 ETO_CLIPPED|ETO_OPAQUE,
\r
3501 &messageRect, messageText, strlen(messageText), NULL);
\r
3502 SelectObject(hdc, oldFont);
\r
3503 DisplayBothClocks();
\r
3505 EndPaint(hwnd,&ps);
\r
3513 * If the user selects on a border boundary, return -1; if off the board,
\r
3514 * return -2. Otherwise map the event coordinate to the square.
\r
3515 * The offset boardRect.left or boardRect.top must already have been
\r
3516 * subtracted from x.
\r
3519 EventToSquare(int x)
\r
3526 if ((x % (squareSize + lineGap)) >= squareSize)
\r
3528 x /= (squareSize + lineGap);
\r
3529 if (x >= BOARD_SIZE)
\r
3540 DropEnable dropEnables[] = {
\r
3541 { 'P', DP_Pawn, "Pawn" },
\r
3542 { 'N', DP_Knight, "Knight" },
\r
3543 { 'B', DP_Bishop, "Bishop" },
\r
3544 { 'R', DP_Rook, "Rook" },
\r
3545 { 'Q', DP_Queen, "Queen" },
\r
3549 SetupDropMenu(HMENU hmenu)
\r
3551 int i, count, enable;
\r
3553 extern char white_holding[], black_holding[];
\r
3554 char item[MSG_SIZ];
\r
3556 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
3557 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
3558 dropEnables[i].piece);
\r
3560 while (p && *p++ == dropEnables[i].piece) count++;
\r
3561 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
3562 enable = count > 0 || !appData.testLegality
\r
3563 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
3564 && !appData.icsActive);
\r
3565 ModifyMenu(hmenu, dropEnables[i].command,
\r
3566 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
3567 dropEnables[i].command, item);
\r
3571 static int fromX = -1, fromY = -1, toX, toY;
\r
3573 /* Event handler for mouse messages */
\r
3575 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3579 static int recursive = 0;
\r
3581 BOOLEAN saveAnimate;
\r
3582 static BOOLEAN sameAgain = FALSE;
\r
3585 if (message == WM_MBUTTONUP) {
\r
3586 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
3587 to the middle button: we simulate pressing the left button too!
\r
3589 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
3590 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
3596 pt.x = LOWORD(lParam);
\r
3597 pt.y = HIWORD(lParam);
\r
3598 x = EventToSquare(pt.x - boardRect.left);
\r
3599 y = EventToSquare(pt.y - boardRect.top);
\r
3600 if (!flipView && y >= 0) {
\r
3601 y = BOARD_SIZE - 1 - y;
\r
3603 if (flipView && x >= 0) {
\r
3604 x = BOARD_SIZE - 1 - x;
\r
3607 switch (message) {
\r
3608 case WM_LBUTTONDOWN:
\r
3610 sameAgain = FALSE;
\r
3612 /* Downclick vertically off board; check if on clock */
\r
3613 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
3614 if (gameMode == EditPosition) {
\r
3615 SetWhiteToPlayEvent();
\r
3616 } else if (gameMode == IcsPlayingBlack ||
\r
3617 gameMode == MachinePlaysWhite) {
\r
3620 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
3621 if (gameMode == EditPosition) {
\r
3622 SetBlackToPlayEvent();
\r
3623 } else if (gameMode == IcsPlayingWhite ||
\r
3624 gameMode == MachinePlaysBlack) {
\r
3628 if (!appData.highlightLastMove) {
\r
3629 ClearHighlights();
\r
3630 DrawPosition(FALSE, NULL);
\r
3632 fromX = fromY = -1;
\r
3633 dragInfo.start.x = dragInfo.start.y = -1;
\r
3634 dragInfo.from = dragInfo.start;
\r
3636 } else if (x < 0 || y < 0) {
\r
3638 } else if (fromX == x && fromY == y) {
\r
3639 /* Downclick on same square again */
\r
3640 ClearHighlights();
\r
3641 DrawPosition(FALSE, NULL);
\r
3642 sameAgain = TRUE;
\r
3643 } else if (fromX != -1) {
\r
3644 /* Downclick on different square */
\r
3645 ChessSquare pdown, pup;
\r
3646 pdown = boards[currentMove][fromY][fromX];
\r
3647 pup = boards[currentMove][y][x];
\r
3648 if (gameMode == EditPosition ||
\r
3649 !((WhitePawn <= pdown && pdown <= WhiteKing &&
\r
3650 WhitePawn <= pup && pup <= WhiteKing) ||
\r
3651 (BlackPawn <= pdown && pdown <= BlackKing &&
\r
3652 BlackPawn <= pup && pup <= BlackKing))) {
\r
3653 /* EditPosition, empty square, or different color piece;
\r
3654 click-click move is possible */
\r
3657 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
3658 if (appData.alwaysPromoteToQueen) {
\r
3659 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3660 if (!appData.highlightLastMove) {
\r
3661 ClearHighlights();
\r
3662 DrawPosition(FALSE, NULL);
\r
3665 SetHighlights(fromX, fromY, toX, toY);
\r
3666 DrawPosition(FALSE, NULL);
\r
3667 PromotionPopup(hwnd);
\r
3669 } else { /* not a promotion */
\r
3670 if (appData.animate || appData.highlightLastMove) {
\r
3671 SetHighlights(fromX, fromY, toX, toY);
\r
3673 ClearHighlights();
\r
3675 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3676 if (appData.animate && !appData.highlightLastMove) {
\r
3677 ClearHighlights();
\r
3678 DrawPosition(FALSE, NULL);
\r
3681 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3682 fromX = fromY = -1;
\r
3685 ClearHighlights();
\r
3686 DrawPosition(FALSE, NULL);
\r
3688 /* First downclick, or restart on a square with same color piece */
\r
3689 if (!frozen && OKToStartUserMove(x, y)) {
\r
3692 dragInfo.lastpos = pt;
\r
3693 dragInfo.from.x = fromX;
\r
3694 dragInfo.from.y = fromY;
\r
3695 dragInfo.start = dragInfo.from;
\r
3696 SetCapture(hwndMain);
\r
3698 fromX = fromY = -1;
\r
3699 dragInfo.start.x = dragInfo.start.y = -1;
\r
3700 dragInfo.from = dragInfo.start;
\r
3704 case WM_LBUTTONUP:
\r
3706 if (fromX == -1) break;
\r
3707 if (x == fromX && y == fromY) {
\r
3708 dragInfo.from.x = dragInfo.from.y = -1;
\r
3709 /* Upclick on same square */
\r
3711 /* Clicked same square twice: abort click-click move */
\r
3712 fromX = fromY = -1;
\r
3714 ClearPremoveHighlights();
\r
3716 /* First square clicked: start click-click move */
\r
3717 SetHighlights(fromX, fromY, -1, -1);
\r
3719 DrawPosition(FALSE, NULL);
\r
3720 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
3721 /* Errant click; ignore */
\r
3724 /* Finish drag move */
\r
3725 dragInfo.from.x = dragInfo.from.y = -1;
\r
3728 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
3729 appData.animate = appData.animate && !appData.animateDragging;
\r
3730 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
3731 if (appData.alwaysPromoteToQueen) {
\r
3732 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3734 DrawPosition(FALSE, NULL);
\r
3735 PromotionPopup(hwnd);
\r
3738 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3740 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3741 appData.animate = saveAnimate;
\r
3742 fromX = fromY = -1;
\r
3743 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
3744 ClearHighlights();
\r
3746 if (appData.animate || appData.animateDragging ||
\r
3747 appData.highlightDragging || gotPremove) {
\r
3748 DrawPosition(FALSE, NULL);
\r
3751 dragInfo.start.x = dragInfo.start.y = -1;
\r
3752 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
3755 case WM_MOUSEMOVE:
\r
3756 if ((appData.animateDragging || appData.highlightDragging)
\r
3757 && (wParam & MK_LBUTTON)
\r
3758 && dragInfo.from.x >= 0) {
\r
3759 if (appData.animateDragging) {
\r
3760 dragInfo.pos = pt;
\r
3762 if (appData.highlightDragging) {
\r
3763 SetHighlights(fromX, fromY, x, y);
\r
3765 DrawPosition(FALSE, NULL);
\r
3766 dragInfo.lastpos = dragInfo.pos;
\r
3770 case WM_MBUTTONDOWN:
\r
3771 case WM_RBUTTONDOWN:
\r
3774 fromX = fromY = -1;
\r
3775 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
3776 dragInfo.start.x = dragInfo.start.y = -1;
\r
3777 dragInfo.from = dragInfo.start;
\r
3778 dragInfo.lastpos = dragInfo.pos;
\r
3779 if (appData.highlightDragging) {
\r
3780 ClearHighlights();
\r
3782 DrawPosition(TRUE, NULL);
\r
3784 switch (gameMode) {
\r
3785 case EditPosition:
\r
3786 case IcsExamining:
\r
3787 if (x < 0 || y < 0) break;
\r
3790 if (message == WM_MBUTTONDOWN) {
\r
3791 buttonCount = 3; /* even if system didn't think so */
\r
3792 if (wParam & MK_SHIFT)
\r
3793 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3795 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3796 } else { /* message == WM_RBUTTONDOWN */
\r
3798 if (buttonCount == 3) {
\r
3799 if (wParam & MK_SHIFT)
\r
3800 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3802 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3804 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3807 /* Just have one menu, on the right button. Windows users don't
\r
3808 think to try the middle one, and sometimes other software steals
\r
3809 it, or it doesn't really exist. */
\r
3810 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3814 case IcsPlayingWhite:
\r
3815 case IcsPlayingBlack:
\r
3817 case MachinePlaysWhite:
\r
3818 case MachinePlaysBlack:
\r
3819 if (appData.testLegality &&
\r
3820 gameInfo.variant != VariantBughouse &&
\r
3821 gameInfo.variant != VariantCrazyhouse) break;
\r
3822 if (x < 0 || y < 0) break;
\r
3825 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
3826 SetupDropMenu(hmenu);
\r
3827 MenuPopup(hwnd, pt, hmenu, -1);
\r
3838 /* Preprocess messages for buttons in main window */
\r
3840 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3842 int id = GetWindowLong(hwnd, GWL_ID);
\r
3845 for (i=0; i<N_BUTTONS; i++) {
\r
3846 if (buttonDesc[i].id == id) break;
\r
3848 if (i == N_BUTTONS) return 0;
\r
3849 switch (message) {
\r
3854 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
3855 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
3862 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
3865 if (appData.icsActive) {
\r
3866 if (GetKeyState(VK_SHIFT) < 0) {
\r
3868 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3869 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3873 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
3874 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3881 if (appData.icsActive) {
\r
3882 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3883 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3885 SendMessage(h, WM_CHAR, wParam, lParam);
\r
3887 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
3888 PopUpMoveDialog((char)wParam);
\r
3894 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
3897 /* Process messages for Promotion dialog box */
\r
3899 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
3903 switch (message) {
\r
3904 case WM_INITDIALOG: /* message: initialize dialog box */
\r
3905 /* Center the dialog over the application window */
\r
3906 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
3907 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
3908 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
3909 gameInfo.variant == VariantGiveaway) ?
\r
3910 SW_SHOW : SW_HIDE);
\r
3913 case WM_COMMAND: /* message: received a command */
\r
3914 switch (LOWORD(wParam)) {
\r
3916 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3917 ClearHighlights();
\r
3918 DrawPosition(FALSE, NULL);
\r
3938 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3939 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
3940 if (!appData.highlightLastMove) {
\r
3941 ClearHighlights();
\r
3942 DrawPosition(FALSE, NULL);
\r
3949 /* Pop up promotion dialog */
\r
3951 PromotionPopup(HWND hwnd)
\r
3955 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
3956 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
3957 hwnd, (DLGPROC)lpProc);
\r
3958 FreeProcInstance(lpProc);
\r
3961 /* Toggle ShowThinking */
\r
3963 ToggleShowThinking()
\r
3965 ShowThinkingEvent(!appData.showThinking);
\r
3969 LoadGameDialog(HWND hwnd, char* title)
\r
3973 char fileTitle[MSG_SIZ];
\r
3974 f = OpenFileDialog(hwnd, FALSE, "",
\r
3975 appData.oldSaveStyle ? "gam" : "pgn",
\r
3977 title, &number, fileTitle, NULL);
\r
3979 cmailMsgLoaded = FALSE;
\r
3980 if (number == 0) {
\r
3981 int error = GameListBuild(f);
\r
3983 DisplayError("Cannot build game list", error);
\r
3984 } else if (!ListEmpty(&gameList) &&
\r
3985 ((ListGame *) gameList.tailPred)->number > 1) {
\r
3986 GameListPopUp(f, fileTitle);
\r
3989 GameListDestroy();
\r
3992 LoadGame(f, number, fileTitle, FALSE);
\r
3997 ChangedConsoleFont()
\r
4000 CHARRANGE tmpsel, sel;
\r
4001 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4002 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4003 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4006 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4007 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4008 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4009 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4010 * size. This was undocumented in the version of MSVC++ that I had
\r
4011 * when I wrote the code, but is apparently documented now.
\r
4013 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4014 cfmt.bCharSet = f->lf.lfCharSet;
\r
4015 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4016 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4017 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4018 /* Why are the following seemingly needed too? */
\r
4019 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4020 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4021 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4023 tmpsel.cpMax = -1; /*999999?*/
\r
4024 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4025 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4026 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4027 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4029 paraf.cbSize = sizeof(paraf);
\r
4030 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4031 paraf.dxStartIndent = 0;
\r
4032 paraf.dxOffset = WRAP_INDENT;
\r
4033 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4034 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4037 /*---------------------------------------------------------------------------*\
\r
4039 * Window Proc for main window
\r
4041 \*---------------------------------------------------------------------------*/
\r
4043 /* Process messages for main window, etc. */
\r
4045 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4048 int wmId, wmEvent;
\r
4052 char fileTitle[MSG_SIZ];
\r
4054 switch (message) {
\r
4056 case WM_PAINT: /* message: repaint portion of window */
\r
4060 case WM_ERASEBKGND:
\r
4061 if (IsIconic(hwnd)) {
\r
4062 /* Cheat; change the message */
\r
4063 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4065 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4069 case WM_LBUTTONDOWN:
\r
4070 case WM_MBUTTONDOWN:
\r
4071 case WM_RBUTTONDOWN:
\r
4072 case WM_LBUTTONUP:
\r
4073 case WM_MBUTTONUP:
\r
4074 case WM_RBUTTONUP:
\r
4075 case WM_MOUSEMOVE:
\r
4076 MouseEvent(hwnd, message, wParam, lParam);
\r
4081 if (appData.icsActive) {
\r
4082 if (wParam == '\t') {
\r
4083 if (GetKeyState(VK_SHIFT) < 0) {
\r
4085 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4086 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4090 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4091 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4095 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4096 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4098 SendMessage(h, message, wParam, lParam);
\r
4100 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4101 PopUpMoveDialog((char)wParam);
\r
4105 case WM_PALETTECHANGED:
\r
4106 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4108 HDC hdc = GetDC(hwndMain);
\r
4109 SelectPalette(hdc, hPal, TRUE);
\r
4110 nnew = RealizePalette(hdc);
\r
4112 paletteChanged = TRUE;
\r
4114 UpdateColors(hdc);
\r
4116 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
4119 ReleaseDC(hwnd, hdc);
\r
4123 case WM_QUERYNEWPALETTE:
\r
4124 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4126 HDC hdc = GetDC(hwndMain);
\r
4127 paletteChanged = FALSE;
\r
4128 SelectPalette(hdc, hPal, FALSE);
\r
4129 nnew = RealizePalette(hdc);
\r
4131 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4133 ReleaseDC(hwnd, hdc);
\r
4138 case WM_COMMAND: /* message: command from application menu */
\r
4139 wmId = LOWORD(wParam);
\r
4140 wmEvent = HIWORD(wParam);
\r
4145 AnalysisPopDown();
\r
4148 case IDM_LoadGame:
\r
4149 LoadGameDialog(hwnd, "Load Game from File");
\r
4152 case IDM_LoadNextGame:
\r
4156 case IDM_LoadPrevGame:
\r
4160 case IDM_ReloadGame:
\r
4164 case IDM_LoadPosition:
\r
4165 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4166 Reset(FALSE, TRUE);
\r
4169 f = OpenFileDialog(hwnd, FALSE, "",
\r
4170 appData.oldSaveStyle ? "pos" : "fen",
\r
4172 "Load Position from File", &number, fileTitle, NULL);
\r
4174 LoadPosition(f, number, fileTitle);
\r
4178 case IDM_LoadNextPosition:
\r
4179 ReloadPosition(1);
\r
4182 case IDM_LoadPrevPosition:
\r
4183 ReloadPosition(-1);
\r
4186 case IDM_ReloadPosition:
\r
4187 ReloadPosition(0);
\r
4190 case IDM_SaveGame:
\r
4191 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4192 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4193 appData.oldSaveStyle ? "gam" : "pgn",
\r
4195 "Save Game to File", NULL, fileTitle, NULL);
\r
4197 SaveGame(f, 0, "");
\r
4201 case IDM_SavePosition:
\r
4202 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4203 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4204 appData.oldSaveStyle ? "pos" : "fen",
\r
4206 "Save Position to File", NULL, fileTitle, NULL);
\r
4208 SavePosition(f, 0, "");
\r
4212 case IDM_CopyGame:
\r
4213 CopyGameToClipboard();
\r
4216 case IDM_PasteGame:
\r
4217 PasteGameFromClipboard();
\r
4220 /* [AS] Autodetect FEN or PGN data */
4222 PasteGameOrFENFromClipboard();
4225 /* [AS] User adjudication */
4226 case IDM_UserAdjudication_White:
4227 UserAdjudicationEvent( +1 );
4230 case IDM_UserAdjudication_Black:
4231 UserAdjudicationEvent( -1 );
4234 case IDM_UserAdjudication_Draw:
4235 UserAdjudicationEvent( 0 );
4238 case IDM_CopyPosition:
\r
4239 CopyFENToClipboard();
\r
4242 case IDM_PastePosition:
\r
4243 PasteFENFromClipboard();
\r
4246 case IDM_MailMove:
\r
4250 case IDM_ReloadCMailMsg:
\r
4251 Reset(TRUE, TRUE);
\r
4252 ReloadCmailMsgEvent(FALSE);
\r
4255 case IDM_Minimize:
\r
4256 ShowWindow(hwnd, SW_MINIMIZE);
\r
4263 case IDM_MachineWhite:
\r
4264 MachineWhiteEvent();
\r
4266 * refresh the tags dialog only if it's visible
\r
4268 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4270 tags = PGNTags(&gameInfo);
\r
4271 TagsPopUp(tags, CmailMsg());
\r
4276 case IDM_MachineBlack:
\r
4277 MachineBlackEvent();
\r
4279 * refresh the tags dialog only if it's visible
\r
4281 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
4283 tags = PGNTags(&gameInfo);
\r
4284 TagsPopUp(tags, CmailMsg());
\r
4289 case IDM_TwoMachines:
\r
4290 TwoMachinesEvent();
\r
4292 * refresh the tags dialog only if it's visible
\r
4294 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
4296 tags = PGNTags(&gameInfo);
\r
4297 TagsPopUp(tags, CmailMsg());
\r
4302 case IDM_AnalysisMode:
\r
4303 if (!first.analysisSupport) {
\r
4304 char buf[MSG_SIZ];
\r
4305 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4306 DisplayError(buf, 0);
\r
4308 if (!appData.showThinking) ToggleShowThinking();
\r
4309 AnalyzeModeEvent();
\r
4313 case IDM_AnalyzeFile:
\r
4314 if (!first.analysisSupport) {
\r
4315 char buf[MSG_SIZ];
\r
4316 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4317 DisplayError(buf, 0);
\r
4319 if (!appData.showThinking) ToggleShowThinking();
\r
4320 AnalyzeFileEvent();
\r
4321 LoadGameDialog(hwnd, "Analyze Game from File");
\r
4322 AnalysisPeriodicEvent(1);
\r
4326 case IDM_IcsClient:
\r
4330 case IDM_EditGame:
\r
4334 case IDM_EditPosition:
\r
4335 EditPositionEvent();
\r
4338 case IDM_Training:
\r
4342 case IDM_ShowGameList:
\r
4343 ShowGameListProc();
\r
4346 case IDM_EditTags:
\r
4350 case IDM_EditComment:
\r
4351 if (commentDialogUp && editComment) {
\r
4354 EditCommentEvent();
\r
4374 case IDM_CallFlag:
\r
4394 case IDM_StopObserving:
\r
4395 StopObservingEvent();
\r
4398 case IDM_StopExamining:
\r
4399 StopExaminingEvent();
\r
4402 case IDM_TypeInMove:
\r
4403 PopUpMoveDialog('\000');
\r
4406 case IDM_Backward:
\r
4408 SetFocus(hwndMain);
\r
4413 SetFocus(hwndMain);
\r
4418 SetFocus(hwndMain);
\r
4423 SetFocus(hwndMain);
\r
4430 case IDM_TruncateGame:
\r
4431 TruncateGameEvent();
\r
4438 case IDM_RetractMove:
\r
4439 RetractMoveEvent();
\r
4442 case IDM_FlipView:
\r
4443 flipView = !flipView;
\r
4444 DrawPosition(FALSE, NULL);
\r
4447 case IDM_GeneralOptions:
\r
4448 GeneralOptionsPopup(hwnd);
\r
4451 case IDM_BoardOptions:
\r
4452 BoardOptionsPopup(hwnd);
\r
4455 case IDM_IcsOptions:
\r
4456 IcsOptionsPopup(hwnd);
\r
4460 FontsOptionsPopup(hwnd);
\r
4464 SoundOptionsPopup(hwnd);
\r
4467 case IDM_CommPort:
\r
4468 CommPortOptionsPopup(hwnd);
\r
4471 case IDM_LoadOptions:
\r
4472 LoadOptionsPopup(hwnd);
\r
4475 case IDM_SaveOptions:
\r
4476 SaveOptionsPopup(hwnd);
\r
4479 case IDM_TimeControl:
\r
4480 TimeControlOptionsPopup(hwnd);
\r
4483 case IDM_SaveSettings:
\r
4484 SaveSettings(settingsFileName);
\r
4487 case IDM_SaveSettingsOnExit:
\r
4488 saveSettingsOnExit = !saveSettingsOnExit;
\r
4489 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
4490 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
4491 MF_CHECKED : MF_UNCHECKED));
\r
4502 case IDM_AboutGame:
\r
4507 appData.debugMode = !appData.debugMode;
\r
4508 if (appData.debugMode) {
\r
4509 char dir[MSG_SIZ];
\r
4510 GetCurrentDirectory(MSG_SIZ, dir);
\r
4511 SetCurrentDirectory(installDir);
\r
4512 debugFP = fopen(appData.nameOfDebugFile, "w");
4513 SetCurrentDirectory(dir);
\r
4514 setbuf(debugFP, NULL);
\r
4521 case IDM_HELPCONTENTS:
\r
4522 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
4523 MessageBox (GetFocus(),
\r
4524 "Unable to activate help",
\r
4525 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4529 case IDM_HELPSEARCH:
\r
4530 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
4531 MessageBox (GetFocus(),
\r
4532 "Unable to activate help",
\r
4533 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4537 case IDM_HELPHELP:
\r
4538 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
4539 MessageBox (GetFocus(),
\r
4540 "Unable to activate help",
\r
4541 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4546 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
4548 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
4549 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
4550 FreeProcInstance(lpProc);
\r
4553 case IDM_DirectCommand1:
\r
4554 AskQuestionEvent("Direct Command",
\r
4555 "Send to chess program:", "", "1");
\r
4557 case IDM_DirectCommand2:
\r
4558 AskQuestionEvent("Direct Command",
\r
4559 "Send to second chess program:", "", "2");
\r
4562 case EP_WhitePawn:
\r
4563 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
4564 fromX = fromY = -1;
\r
4567 case EP_WhiteKnight:
\r
4568 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
4569 fromX = fromY = -1;
\r
4572 case EP_WhiteBishop:
\r
4573 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
4574 fromX = fromY = -1;
\r
4577 case EP_WhiteRook:
\r
4578 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
4579 fromX = fromY = -1;
\r
4582 case EP_WhiteQueen:
\r
4583 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
4584 fromX = fromY = -1;
\r
4587 case EP_WhiteKing:
\r
4588 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
4589 fromX = fromY = -1;
\r
4592 case EP_BlackPawn:
\r
4593 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
4594 fromX = fromY = -1;
\r
4597 case EP_BlackKnight:
\r
4598 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
4599 fromX = fromY = -1;
\r
4602 case EP_BlackBishop:
\r
4603 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
4604 fromX = fromY = -1;
\r
4607 case EP_BlackRook:
\r
4608 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
4609 fromX = fromY = -1;
\r
4612 case EP_BlackQueen:
\r
4613 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
4614 fromX = fromY = -1;
\r
4617 case EP_BlackKing:
\r
4618 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
4619 fromX = fromY = -1;
\r
4622 case EP_EmptySquare:
\r
4623 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
4624 fromX = fromY = -1;
\r
4627 case EP_ClearBoard:
\r
4628 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
4629 fromX = fromY = -1;
\r
4633 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
4634 fromX = fromY = -1;
\r
4638 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
4639 fromX = fromY = -1;
\r
4643 DropMenuEvent(WhitePawn, fromX, fromY);
\r
4644 fromX = fromY = -1;
\r
4648 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
4649 fromX = fromY = -1;
\r
4653 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
4654 fromX = fromY = -1;
\r
4658 DropMenuEvent(WhiteRook, fromX, fromY);
\r
4659 fromX = fromY = -1;
\r
4663 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
4664 fromX = fromY = -1;
\r
4668 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4674 case CLOCK_TIMER_ID:
\r
4675 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
4676 clockTimerEvent = 0;
\r
4677 DecrementClocks(); /* call into back end */
\r
4679 case LOAD_GAME_TIMER_ID:
\r
4680 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
4681 loadGameTimerEvent = 0;
\r
4682 AutoPlayGameLoop(); /* call into back end */
\r
4684 case ANALYSIS_TIMER_ID:
\r
4685 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
4686 appData.periodicUpdates) {
\r
4687 AnalysisPeriodicEvent(0);
\r
4689 KillTimer(hwnd, analysisTimerEvent);
\r
4690 analysisTimerEvent = 0;
\r
4693 case DELAYED_TIMER_ID:
\r
4694 KillTimer(hwnd, delayedTimerEvent);
\r
4695 delayedTimerEvent = 0;
\r
4696 delayedTimerCallback();
\r
4701 case WM_USER_Input:
\r
4702 InputEvent(hwnd, message, wParam, lParam);
\r
4705 case WM_ENTERSIZEMOVE:
\r
4706 if (hwnd == hwndMain) {
\r
4707 doingSizing = TRUE;
\r
4713 if (hwnd == hwndMain) {
\r
4714 lastSizing = wParam;
\r
4718 case WM_EXITSIZEMOVE:
\r
4719 if (hwnd == hwndMain) {
\r
4721 doingSizing = FALSE;
\r
4722 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4723 GetClientRect(hwnd, &client);
\r
4724 ResizeBoard(client.right, client.bottom, lastSizing);
\r
4729 case WM_DESTROY: /* message: window being destroyed */
\r
4730 PostQuitMessage(0);
\r
4734 if (hwnd == hwndMain) {
\r
4739 default: /* Passes it on if unprocessed */
\r
4740 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4745 /*---------------------------------------------------------------------------*\
\r
4747 * Misc utility routines
\r
4749 \*---------------------------------------------------------------------------*/
\r
4752 * Decent random number generator, at least not as bad as Windows
\r
4753 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
4755 unsigned int randstate;
\r
4760 randstate = randstate * 1664525 + 1013904223;
\r
4761 return (int) randstate & 0x7fffffff;
\r
4765 mysrandom(unsigned int seed)
\r
4772 * returns TRUE if user selects a different color, FALSE otherwise
\r
4776 ChangeColor(HWND hwnd, COLORREF *which)
\r
4778 static BOOL firstTime = TRUE;
\r
4779 static DWORD customColors[16];
\r
4781 COLORREF newcolor;
\r
4786 /* Make initial colors in use available as custom colors */
\r
4787 /* Should we put the compiled-in defaults here instead? */
\r
4789 customColors[i++] = lightSquareColor & 0xffffff;
\r
4790 customColors[i++] = darkSquareColor & 0xffffff;
\r
4791 customColors[i++] = whitePieceColor & 0xffffff;
\r
4792 customColors[i++] = blackPieceColor & 0xffffff;
\r
4793 customColors[i++] = highlightSquareColor & 0xffffff;
\r
4794 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
4796 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
4797 customColors[i++] = textAttribs[ccl].color;
\r
4799 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
4800 firstTime = FALSE;
\r
4803 cc.lStructSize = sizeof(cc);
\r
4804 cc.hwndOwner = hwnd;
\r
4805 cc.hInstance = NULL;
\r
4806 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
4807 cc.lpCustColors = (LPDWORD) customColors;
\r
4808 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
4810 if (!ChooseColor(&cc)) return FALSE;
\r
4812 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
4813 if (newcolor == *which) return FALSE;
\r
4814 *which = newcolor;
\r
4818 InitDrawingColors();
\r
4819 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4824 MyLoadSound(MySound *ms)
\r
4830 if (ms->data) free(ms->data);
\r
4833 switch (ms->name[0]) {
\r
4839 /* System sound from Control Panel. Don't preload here. */
\r
4843 if (ms->name[1] == NULLCHAR) {
\r
4844 /* "!" alone = silence */
\r
4847 /* Builtin wave resource. Error if not found. */
\r
4848 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
4849 if (h == NULL) break;
\r
4850 ms->data = (void *)LoadResource(hInst, h);
\r
4851 if (h == NULL) break;
\r
4856 /* .wav file. Error if not found. */
\r
4857 f = fopen(ms->name, "rb");
\r
4858 if (f == NULL) break;
\r
4859 if (fstat(fileno(f), &st) < 0) break;
\r
4860 ms->data = malloc(st.st_size);
\r
4861 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
4867 char buf[MSG_SIZ];
\r
4868 sprintf(buf, "Error loading sound %s", ms->name);
\r
4869 DisplayError(buf, GetLastError());
\r
4875 MyPlaySound(MySound *ms)
\r
4877 BOOLEAN ok = FALSE;
\r
4878 switch (ms->name[0]) {
\r
4884 /* System sound from Control Panel (deprecated feature).
\r
4885 "$" alone or an unset sound name gets default beep (still in use). */
\r
4886 if (ms->name[1]) {
\r
4887 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
4889 if (!ok) ok = MessageBeep(MB_OK);
\r
4892 /* Builtin wave resource, or "!" alone for silence */
\r
4893 if (ms->name[1]) {
\r
4894 if (ms->data == NULL) return FALSE;
\r
4895 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4901 /* .wav file. Error if not found. */
\r
4902 if (ms->data == NULL) return FALSE;
\r
4903 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
4906 /* Don't print an error: this can happen innocently if the sound driver
\r
4907 is busy; for instance, if another instance of WinBoard is playing
\r
4908 a sound at about the same time. */
\r
4911 char buf[MSG_SIZ];
\r
4912 sprintf(buf, "Error playing sound %s", ms->name);
\r
4913 DisplayError(buf, GetLastError());
\r
4921 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4924 OPENFILENAME *ofn;
\r
4925 static UINT *number; /* gross that this is static */
\r
4927 switch (message) {
\r
4928 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4929 /* Center the dialog over the application window */
\r
4930 ofn = (OPENFILENAME *) lParam;
\r
4931 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
4932 number = (UINT *) ofn->lCustData;
\r
4933 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
4937 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
4938 return FALSE; /* Allow for further processing */
\r
4941 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
4942 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
4944 return FALSE; /* Allow for further processing */
\r
4950 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
4952 static UINT *number;
\r
4953 OPENFILENAME *ofname;
\r
4956 case WM_INITDIALOG:
\r
4957 ofname = (OPENFILENAME *)lParam;
\r
4958 number = (UINT *)(ofname->lCustData);
\r
4961 ofnot = (OFNOTIFY *)lParam;
\r
4962 if (ofnot->hdr.code == CDN_FILEOK) {
\r
4963 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
4972 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
4973 char *nameFilt, char *dlgTitle, UINT *number,
\r
4974 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
4976 OPENFILENAME openFileName;
\r
4977 char buf1[MSG_SIZ];
\r
4980 if (fileName == NULL) fileName = buf1;
\r
4981 if (defName == NULL) {
\r
4982 strcpy(fileName, "*.");
\r
4983 strcat(fileName, defExt);
\r
4985 strcpy(fileName, defName);
\r
4987 if (fileTitle) strcpy(fileTitle, "");
\r
4988 if (number) *number = 0;
\r
4990 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
4991 openFileName.hwndOwner = hwnd;
\r
4992 openFileName.hInstance = (HANDLE) hInst;
\r
4993 openFileName.lpstrFilter = nameFilt;
\r
4994 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
4995 openFileName.nMaxCustFilter = 0L;
\r
4996 openFileName.nFilterIndex = 1L;
\r
4997 openFileName.lpstrFile = fileName;
\r
4998 openFileName.nMaxFile = MSG_SIZ;
\r
4999 openFileName.lpstrFileTitle = fileTitle;
\r
5000 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5001 openFileName.lpstrInitialDir = NULL;
\r
5002 openFileName.lpstrTitle = dlgTitle;
\r
5003 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5004 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
5005 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5006 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5007 openFileName.nFileOffset = 0;
\r
5008 openFileName.nFileExtension = 0;
\r
5009 openFileName.lpstrDefExt = defExt;
\r
5010 openFileName.lCustData = (LONG) number;
\r
5011 openFileName.lpfnHook = oldDialog ?
\r
5012 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5013 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5015 if (write ? GetSaveFileName(&openFileName) :
\r
5016 GetOpenFileName(&openFileName)) {
\r
5017 /* open the file */
\r
5018 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
5020 MessageBox(hwnd, "File open failed", NULL,
\r
5021 MB_OK|MB_ICONEXCLAMATION);
\r
5025 int err = CommDlgExtendedError();
\r
5026 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
5035 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5037 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5040 * Get the first pop-up menu in the menu template. This is the
\r
5041 * menu that TrackPopupMenu displays.
\r
5043 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5045 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5048 * TrackPopup uses screen coordinates, so convert the
\r
5049 * coordinates of the mouse click to screen coordinates.
\r
5051 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5053 /* Draw and track the floating pop-up menu. */
\r
5054 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5055 pt.x, pt.y, 0, hwnd, NULL);
\r
5057 /* Destroy the menu.*/
\r
5058 DestroyMenu(hmenu);
\r
5063 int sizeX, sizeY, newSizeX, newSizeY;
\r
5065 } ResizeEditPlusButtonsClosure;
\r
5068 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5070 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5074 if (hChild == cl->hText) return TRUE;
\r
5075 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5076 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5077 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5078 ScreenToClient(cl->hDlg, &pt);
\r
5079 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5080 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5084 /* Resize a dialog that has a (rich) edit field filling most of
\r
5085 the top, with a row of buttons below */
\r
5087 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
5090 int newTextHeight, newTextWidth;
\r
5091 ResizeEditPlusButtonsClosure cl;
\r
5093 /*if (IsIconic(hDlg)) return;*/
\r
5094 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
5096 cl.hdwp = BeginDeferWindowPos(8);
\r
5098 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
5099 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5100 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5101 if (newTextHeight < 0) {
\r
5102 newSizeY += -newTextHeight;
\r
5103 newTextHeight = 0;
\r
5105 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
5106 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5112 cl.newSizeX = newSizeX;
\r
5113 cl.newSizeY = newSizeY;
\r
5114 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
5116 EndDeferWindowPos(cl.hdwp);
\r
5119 /* Center one window over another */
\r
5120 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
5122 RECT rChild, rParent;
\r
5123 int wChild, hChild, wParent, hParent;
\r
5124 int wScreen, hScreen, xNew, yNew;
\r
5127 /* Get the Height and Width of the child window */
\r
5128 GetWindowRect (hwndChild, &rChild);
\r
5129 wChild = rChild.right - rChild.left;
\r
5130 hChild = rChild.bottom - rChild.top;
\r
5132 /* Get the Height and Width of the parent window */
\r
5133 GetWindowRect (hwndParent, &rParent);
\r
5134 wParent = rParent.right - rParent.left;
\r
5135 hParent = rParent.bottom - rParent.top;
\r
5137 /* Get the display limits */
\r
5138 hdc = GetDC (hwndChild);
\r
5139 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
5140 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
5141 ReleaseDC(hwndChild, hdc);
\r
5143 /* Calculate new X position, then adjust for screen */
\r
5144 xNew = rParent.left + ((wParent - wChild) /2);
\r
5147 } else if ((xNew+wChild) > wScreen) {
\r
5148 xNew = wScreen - wChild;
\r
5151 /* Calculate new Y position, then adjust for screen */
\r
5152 yNew = rParent.top + ((hParent - hChild) /2);
\r
5155 } else if ((yNew+hChild) > hScreen) {
\r
5156 yNew = hScreen - hChild;
\r
5159 /* Set it, and return */
\r
5160 return SetWindowPos (hwndChild, NULL,
\r
5161 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
5164 /*---------------------------------------------------------------------------*\
\r
5166 * Startup Dialog functions
\r
5168 \*---------------------------------------------------------------------------*/
\r
5170 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
5172 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5174 while (*cd != NULL) {
\r
5175 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
5181 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
5183 char buf1[ARG_MAX];
\r
5186 if (str[0] == '@') {
\r
5187 FILE* f = fopen(str + 1, "r");
\r
5189 DisplayFatalError(str + 1, errno, 2);
\r
5192 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
5194 buf1[len] = NULLCHAR;
\r
5198 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5201 char buf[MSG_SIZ];
\r
5202 char *end = strchr(str, '\n');
\r
5203 if (end == NULL) return;
\r
5204 memcpy(buf, str, end - str);
\r
5205 buf[end - str] = NULLCHAR;
\r
5206 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
5212 SetStartupDialogEnables(HWND hDlg)
\r
5214 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5215 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5216 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5217 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5218 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
5219 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
5220 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5221 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
5222 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
5223 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
5224 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5225 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
5226 IsDlgButtonChecked(hDlg, OPT_View));
\r
5230 QuoteForFilename(char *filename)
\r
5232 int dquote, space;
\r
5233 dquote = strchr(filename, '"') != NULL;
\r
5234 space = strchr(filename, ' ') != NULL;
\r
5235 if (dquote || space) {
\r
5247 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
5249 char buf[MSG_SIZ];
\r
5252 InitComboStringsFromOption(hwndCombo, nthnames);
\r
5253 q = QuoteForFilename(nthcp);
\r
5254 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
5255 if (*nthdir != NULLCHAR) {
\r
5256 q = QuoteForFilename(nthdir);
\r
5257 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
5259 if (*nthcp == NULLCHAR) {
\r
5260 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5261 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5262 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5263 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5268 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5270 char buf[MSG_SIZ];
\r
5274 switch (message) {
\r
5275 case WM_INITDIALOG:
\r
5276 /* Center the dialog */
\r
5277 CenterWindow (hDlg, GetDesktopWindow());
\r
5278 /* Initialize the dialog items */
\r
5279 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5280 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
5281 firstChessProgramNames);
\r
5282 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5283 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
5284 secondChessProgramNames);
\r
5285 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
5286 InitComboStringsFromOption(hwndCombo, icsNames);
\r
5287 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
5288 if (*appData.icsHelper != NULLCHAR) {
\r
5289 char *q = QuoteForFilename(appData.icsHelper);
\r
5290 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
5292 if (*appData.icsHost == NULLCHAR) {
\r
5293 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5294 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
5295 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5296 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5297 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5300 if (appData.icsActive) {
5301 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
5303 else if (appData.noChessProgram) {
5304 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
5307 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
5310 SetStartupDialogEnables(hDlg);
\r
5314 switch (LOWORD(wParam)) {
\r
5316 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
5317 strcpy(buf, "/fcp=");
\r
5318 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5320 ParseArgs(StringGet, &p);
\r
5321 strcpy(buf, "/scp=");
\r
5322 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5324 ParseArgs(StringGet, &p);
\r
5325 appData.noChessProgram = FALSE;
\r
5326 appData.icsActive = FALSE;
\r
5327 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
5328 strcpy(buf, "/ics /icshost=");
\r
5329 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5331 ParseArgs(StringGet, &p);
\r
5332 if (appData.zippyPlay) {
\r
5333 strcpy(buf, "/fcp=");
\r
5334 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5336 ParseArgs(StringGet, &p);
\r
5338 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
5339 appData.noChessProgram = TRUE;
\r
5340 appData.icsActive = FALSE;
\r
5342 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
5343 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
5346 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
5347 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
5349 ParseArgs(StringGet, &p);
\r
5351 EndDialog(hDlg, TRUE);
\r
5358 case IDM_HELPCONTENTS:
\r
5359 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5360 MessageBox (GetFocus(),
\r
5361 "Unable to activate help",
\r
5362 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5367 SetStartupDialogEnables(hDlg);
\r
5375 /*---------------------------------------------------------------------------*\
\r
5377 * About box dialog functions
\r
5379 \*---------------------------------------------------------------------------*/
\r
5381 /* Process messages for "About" dialog box */
\r
5383 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5385 switch (message) {
\r
5386 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5387 /* Center the dialog over the application window */
\r
5388 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5389 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
5392 case WM_COMMAND: /* message: received a command */
\r
5393 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
5394 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
5395 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5403 /*---------------------------------------------------------------------------*\
\r
5405 * Comment Dialog functions
\r
5407 \*---------------------------------------------------------------------------*/
\r
5410 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5412 static HANDLE hwndText = NULL;
\r
5413 int len, newSizeX, newSizeY, flags;
\r
5414 static int sizeX, sizeY;
\r
5419 switch (message) {
\r
5420 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5421 /* Initialize the dialog items */
\r
5422 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
5423 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
5424 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
5425 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
5426 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
5427 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
5428 SetWindowText(hDlg, commentTitle);
\r
5429 if (editComment) {
\r
5430 SetFocus(hwndText);
\r
5432 SetFocus(GetDlgItem(hDlg, IDOK));
\r
5434 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
5435 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
5436 MAKELPARAM(FALSE, 0));
\r
5437 /* Size and position the dialog */
\r
5438 if (!commentDialog) {
\r
5439 commentDialog = hDlg;
\r
5440 flags = SWP_NOZORDER;
\r
5441 GetClientRect(hDlg, &rect);
\r
5442 sizeX = rect.right;
\r
5443 sizeY = rect.bottom;
\r
5444 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
5445 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
5446 WINDOWPLACEMENT wp;
\r
5447 EnsureOnScreen(&commentX, &commentY);
\r
5448 wp.length = sizeof(WINDOWPLACEMENT);
\r
5450 wp.showCmd = SW_SHOW;
\r
5451 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
5452 wp.rcNormalPosition.left = commentX;
\r
5453 wp.rcNormalPosition.right = commentX + commentW;
\r
5454 wp.rcNormalPosition.top = commentY;
\r
5455 wp.rcNormalPosition.bottom = commentY + commentH;
\r
5456 SetWindowPlacement(hDlg, &wp);
\r
5458 GetClientRect(hDlg, &rect);
\r
5459 newSizeX = rect.right;
\r
5460 newSizeY = rect.bottom;
\r
5461 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
5462 newSizeX, newSizeY);
\r
5469 case WM_COMMAND: /* message: received a command */
\r
5470 switch (LOWORD(wParam)) {
\r
5472 if (editComment) {
\r
5474 /* Read changed options from the dialog box */
\r
5475 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
5476 len = GetWindowTextLength(hwndText);
\r
5477 str = (char *) malloc(len + 1);
\r
5478 GetWindowText(hwndText, str, len + 1);
\r
5487 ReplaceComment(commentIndex, str);
\r
5494 case OPT_CancelComment:
\r
5498 case OPT_ClearComment:
\r
5499 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
5502 case OPT_EditComment:
\r
5503 EditCommentEvent();
\r
5512 newSizeX = LOWORD(lParam);
\r
5513 newSizeY = HIWORD(lParam);
\r
5514 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
5519 case WM_GETMINMAXINFO:
\r
5520 /* Prevent resizing window too small */
\r
5521 mmi = (MINMAXINFO *) lParam;
\r
5522 mmi->ptMinTrackSize.x = 100;
\r
5523 mmi->ptMinTrackSize.y = 100;
\r
5530 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
5535 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
5537 if (str == NULL) str = "";
\r
5538 p = (char *) malloc(2 * strlen(str) + 2);
\r
5541 if (*str == '\n') *q++ = '\r';
\r
5545 if (commentText != NULL) free(commentText);
\r
5547 commentIndex = index;
\r
5548 commentTitle = title;
\r
5550 editComment = edit;
\r
5552 if (commentDialog) {
\r
5553 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
5554 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
5556 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
5557 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
5558 hwndMain, (DLGPROC)lpProc);
\r
5559 FreeProcInstance(lpProc);
\r
5561 commentDialogUp = TRUE;
\r
5565 /*---------------------------------------------------------------------------*\
\r
5567 * Type-in move dialog functions
\r
5569 \*---------------------------------------------------------------------------*/
\r
5572 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5574 char move[MSG_SIZ];
\r
5576 ChessMove moveType;
\r
5577 int fromX, fromY, toX, toY;
\r
5580 switch (message) {
\r
5581 case WM_INITDIALOG:
\r
5582 move[0] = (char) lParam;
\r
5583 move[1] = NULLCHAR;
\r
5584 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5585 hInput = GetDlgItem(hDlg, OPT_Move);
\r
5586 SetWindowText(hInput, move);
\r
5588 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
5592 switch (LOWORD(wParam)) {
\r
5594 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
5595 gameMode != Training) {
\r
5596 DisplayMoveError("Displayed move is not current");
\r
5598 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
5599 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
5600 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
5601 if (gameMode != Training)
\r
5602 forwardMostMove = currentMove;
\r
5603 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5605 DisplayMoveError("Could not parse move");
\r
5608 EndDialog(hDlg, TRUE);
\r
5611 EndDialog(hDlg, FALSE);
\r
5622 PopUpMoveDialog(char firstchar)
\r
5626 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
5627 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
5628 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
5629 gameMode == EditPosition || gameMode == IcsExamining ||
\r
5630 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
5631 gameMode == Training) {
\r
5632 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
5633 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
5634 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
5635 FreeProcInstance(lpProc);
\r
5639 /*---------------------------------------------------------------------------*\
\r
5643 \*---------------------------------------------------------------------------*/
\r
5645 /* Nonmodal error box */
\r
5646 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
5647 WPARAM wParam, LPARAM lParam);
\r
5650 ErrorPopUp(char *title, char *content)
\r
5654 BOOLEAN modal = hwndMain == NULL;
\r
5672 strncpy(errorTitle, title, sizeof(errorTitle));
\r
5673 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
5676 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
5678 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
5679 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
5680 hwndMain, (DLGPROC)lpProc);
\r
5681 FreeProcInstance(lpProc);
\r
5688 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
5689 if (errorDialog == NULL) return;
\r
5690 DestroyWindow(errorDialog);
\r
5691 errorDialog = NULL;
\r
5695 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5700 switch (message) {
\r
5701 case WM_INITDIALOG:
\r
5702 GetWindowRect(hDlg, &rChild);
\r
5703 SetWindowPos(hDlg, NULL, rChild.left,
\r
5704 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
5705 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
5706 errorDialog = hDlg;
\r
5707 SetWindowText(hDlg, errorTitle);
\r
5708 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
5709 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
5713 switch (LOWORD(wParam)) {
\r
5716 if (errorDialog == hDlg) errorDialog = NULL;
\r
5717 DestroyWindow(hDlg);
\r
5728 /*---------------------------------------------------------------------------*\
\r
5730 * Ics Interaction console functions
\r
5732 \*---------------------------------------------------------------------------*/
\r
5734 #define HISTORY_SIZE 64
\r
5735 static char *history[HISTORY_SIZE];
\r
5736 int histIn = 0, histP = 0;
\r
5739 SaveInHistory(char *cmd)
\r
5741 if (history[histIn] != NULL) {
\r
5742 free(history[histIn]);
\r
5743 history[histIn] = NULL;
\r
5745 if (*cmd == NULLCHAR) return;
\r
5746 history[histIn] = StrSave(cmd);
\r
5747 histIn = (histIn + 1) % HISTORY_SIZE;
\r
5748 if (history[histIn] != NULL) {
\r
5749 free(history[histIn]);
\r
5750 history[histIn] = NULL;
\r
5756 PrevInHistory(char *cmd)
\r
5759 if (histP == histIn) {
\r
5760 if (history[histIn] != NULL) free(history[histIn]);
\r
5761 history[histIn] = StrSave(cmd);
\r
5763 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
5764 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
5766 return history[histP];
\r
5772 if (histP == histIn) return NULL;
\r
5773 histP = (histP + 1) % HISTORY_SIZE;
\r
5774 return history[histP];
\r
5781 BOOLEAN immediate;
\r
5782 } IcsTextMenuEntry;
\r
5783 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
5784 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
5787 ParseIcsTextMenu(char *icsTextMenuString)
\r
5790 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
5791 char *p = icsTextMenuString;
\r
5792 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5795 if (e->command != NULL) {
\r
5797 e->command = NULL;
\r
5801 e = icsTextMenuEntry;
\r
5802 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
5803 if (*p == ';' || *p == '\n') {
\r
5804 e->item = strdup("-");
\r
5805 e->command = NULL;
\r
5807 } else if (*p == '-') {
\r
5808 e->item = strdup("-");
\r
5809 e->command = NULL;
\r
5813 char *q, *r, *s, *t;
\r
5815 q = strchr(p, ',');
\r
5816 if (q == NULL) break;
\r
5818 r = strchr(q + 1, ',');
\r
5819 if (r == NULL) break;
\r
5821 s = strchr(r + 1, ',');
\r
5822 if (s == NULL) break;
\r
5825 t = strchr(s + 1, c);
\r
5828 t = strchr(s + 1, c);
\r
5830 if (t != NULL) *t = NULLCHAR;
\r
5831 e->item = strdup(p);
\r
5832 e->command = strdup(q + 1);
\r
5833 e->getname = *(r + 1) != '0';
\r
5834 e->immediate = *(s + 1) != '0';
\r
5838 if (t == NULL) break;
\r
5847 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
5851 hmenu = LoadMenu(hInst, "TextMenu");
\r
5852 h = GetSubMenu(hmenu, 0);
\r
5854 if (strcmp(e->item, "-") == 0) {
\r
5855 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
5857 if (e->item[0] == '|') {
\r
5858 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
5859 IDM_CommandX + i, &e->item[1]);
\r
5861 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
5870 WNDPROC consoleTextWindowProc;
\r
5873 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
5875 char buf[MSG_SIZ], name[MSG_SIZ];
\r
5876 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5880 SetWindowText(hInput, command);
\r
5882 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5884 sel.cpMin = 999999;
\r
5885 sel.cpMax = 999999;
\r
5886 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5891 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5892 if (sel.cpMin == sel.cpMax) {
\r
5893 /* Expand to surrounding word */
\r
5896 tr.chrg.cpMax = sel.cpMin;
\r
5897 tr.chrg.cpMin = --sel.cpMin;
\r
5898 if (sel.cpMin < 0) break;
\r
5899 tr.lpstrText = name;
\r
5900 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5901 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5905 tr.chrg.cpMin = sel.cpMax;
\r
5906 tr.chrg.cpMax = ++sel.cpMax;
\r
5907 tr.lpstrText = name;
\r
5908 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
5909 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
5912 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5913 MessageBeep(MB_ICONEXCLAMATION);
\r
5917 tr.lpstrText = name;
\r
5918 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
5920 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
5921 MessageBeep(MB_ICONEXCLAMATION);
\r
5924 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
5927 sprintf(buf, "%s %s", command, name);
\r
5928 SetWindowText(hInput, buf);
\r
5929 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
5931 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
5932 SetWindowText(hInput, buf);
\r
5933 sel.cpMin = 999999;
\r
5934 sel.cpMax = 999999;
\r
5935 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5941 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5946 switch (message) {
\r
5948 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
5951 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
5954 sel.cpMin = 999999;
\r
5955 sel.cpMax = 999999;
\r
5956 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5957 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
5962 if (wParam == '\t') {
\r
5963 if (GetKeyState(VK_SHIFT) < 0) {
\r
5965 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
5966 if (buttonDesc[0].hwnd) {
\r
5967 SetFocus(buttonDesc[0].hwnd);
\r
5969 SetFocus(hwndMain);
\r
5973 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
5976 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5978 SendMessage(hInput, message, wParam, lParam);
\r
5982 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5984 return SendMessage(hInput, message, wParam, lParam);
\r
5985 case WM_MBUTTONDOWN:
\r
5986 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
5987 case WM_RBUTTONDOWN:
\r
5988 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
5989 /* Move selection here if it was empty */
\r
5991 pt.x = LOWORD(lParam);
\r
5992 pt.y = HIWORD(lParam);
\r
5993 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5994 if (sel.cpMin == sel.cpMax) {
\r
5995 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
5996 sel.cpMax = sel.cpMin;
\r
5997 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5999 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6002 case WM_RBUTTONUP:
\r
6003 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6004 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6005 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6008 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6009 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6010 if (sel.cpMin == sel.cpMax) {
\r
6011 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6012 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6014 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6015 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6017 pt.x = LOWORD(lParam);
\r
6018 pt.y = HIWORD(lParam);
\r
6019 MenuPopup(hwnd, pt, hmenu, -1);
\r
6023 switch (LOWORD(wParam)) {
\r
6024 case IDM_QuickPaste:
\r
6026 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6027 if (sel.cpMin == sel.cpMax) {
\r
6028 MessageBeep(MB_ICONEXCLAMATION);
\r
6031 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6032 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6033 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6038 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6041 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6044 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6048 int i = LOWORD(wParam) - IDM_CommandX;
\r
6049 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
6050 icsTextMenuEntry[i].command != NULL) {
\r
6051 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
6052 icsTextMenuEntry[i].getname,
\r
6053 icsTextMenuEntry[i].immediate);
\r
6061 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
6064 WNDPROC consoleInputWindowProc;
\r
6067 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6069 char buf[MSG_SIZ];
\r
6071 static BOOL sendNextChar = FALSE;
\r
6072 static BOOL quoteNextChar = FALSE;
\r
6073 InputSource *is = consoleInputSource;
\r
6077 switch (message) {
\r
6079 if (!appData.localLineEditing || sendNextChar) {
\r
6080 is->buf[0] = (CHAR) wParam;
\r
6082 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6083 sendNextChar = FALSE;
\r
6086 if (quoteNextChar) {
\r
6087 buf[0] = (char) wParam;
\r
6088 buf[1] = NULLCHAR;
\r
6089 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
6090 quoteNextChar = FALSE;
\r
6094 case '\r': /* Enter key */
\r
6095 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
6096 if (consoleEcho) SaveInHistory(is->buf);
\r
6097 is->buf[is->count++] = '\n';
\r
6098 is->buf[is->count] = NULLCHAR;
\r
6099 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6100 if (consoleEcho) {
\r
6101 ConsoleOutput(is->buf, is->count, TRUE);
\r
6102 } else if (appData.localLineEditing) {
\r
6103 ConsoleOutput("\n", 1, TRUE);
\r
6106 case '\033': /* Escape key */
\r
6107 SetWindowText(hwnd, "");
\r
6108 cf.cbSize = sizeof(CHARFORMAT);
\r
6109 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6110 if (consoleEcho) {
\r
6111 cf.crTextColor = textAttribs[ColorNormal].color;
\r
6113 cf.crTextColor = COLOR_ECHOOFF;
\r
6115 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
6116 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6118 case '\t': /* Tab key */
\r
6119 if (GetKeyState(VK_SHIFT) < 0) {
\r
6121 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
6124 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6125 if (buttonDesc[0].hwnd) {
\r
6126 SetFocus(buttonDesc[0].hwnd);
\r
6128 SetFocus(hwndMain);
\r
6132 case '\023': /* Ctrl+S */
\r
6133 sendNextChar = TRUE;
\r
6135 case '\021': /* Ctrl+Q */
\r
6136 quoteNextChar = TRUE;
\r
6145 GetWindowText(hwnd, buf, MSG_SIZ);
\r
6146 p = PrevInHistory(buf);
\r
6148 SetWindowText(hwnd, p);
\r
6149 sel.cpMin = 999999;
\r
6150 sel.cpMax = 999999;
\r
6151 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6156 p = NextInHistory();
\r
6158 SetWindowText(hwnd, p);
\r
6159 sel.cpMin = 999999;
\r
6160 sel.cpMax = 999999;
\r
6161 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6167 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6171 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
6175 case WM_MBUTTONDOWN:
\r
6176 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6177 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6179 case WM_RBUTTONUP:
\r
6180 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6181 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6182 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6186 hmenu = LoadMenu(hInst, "InputMenu");
\r
6187 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6188 if (sel.cpMin == sel.cpMax) {
\r
6189 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6190 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
6192 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6193 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6195 pt.x = LOWORD(lParam);
\r
6196 pt.y = HIWORD(lParam);
\r
6197 MenuPopup(hwnd, pt, hmenu, -1);
\r
6201 switch (LOWORD(wParam)) {
\r
6203 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
6205 case IDM_SelectAll:
\r
6207 sel.cpMax = -1; /*999999?*/
\r
6208 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6211 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6214 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6217 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6222 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
6225 #define CO_MAX 100000
\r
6226 #define CO_TRIM 1000
\r
6229 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6231 static HWND hText, hInput, hFocus;
\r
6232 InputSource *is = consoleInputSource;
\r
6234 static int sizeX, sizeY;
\r
6235 int newSizeX, newSizeY;
\r
6238 switch (message) {
\r
6239 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6240 hwndConsole = hDlg;
\r
6241 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
6242 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
6244 consoleTextWindowProc = (WNDPROC)
\r
6245 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
6246 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6247 consoleInputWindowProc = (WNDPROC)
\r
6248 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
6249 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6250 Colorize(ColorNormal, TRUE);
\r
6251 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
6252 ChangedConsoleFont();
\r
6253 GetClientRect(hDlg, &rect);
\r
6254 sizeX = rect.right;
\r
6255 sizeY = rect.bottom;
\r
6256 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
6257 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
6258 WINDOWPLACEMENT wp;
\r
6259 EnsureOnScreen(&consoleX, &consoleY);
\r
6260 wp.length = sizeof(WINDOWPLACEMENT);
\r
6262 wp.showCmd = SW_SHOW;
\r
6263 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6264 wp.rcNormalPosition.left = consoleX;
\r
6265 wp.rcNormalPosition.right = consoleX + consoleW;
\r
6266 wp.rcNormalPosition.top = consoleY;
\r
6267 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
6268 SetWindowPlacement(hDlg, &wp);
\r
6282 if (IsIconic(hDlg)) break;
\r
6283 newSizeX = LOWORD(lParam);
\r
6284 newSizeY = HIWORD(lParam);
\r
6285 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
6286 RECT rectText, rectInput;
\r
6288 int newTextHeight, newTextWidth;
\r
6289 GetWindowRect(hText, &rectText);
\r
6290 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6291 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6292 if (newTextHeight < 0) {
\r
6293 newSizeY += -newTextHeight;
\r
6294 newTextHeight = 0;
\r
6296 SetWindowPos(hText, NULL, 0, 0,
\r
6297 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6298 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
6299 pt.x = rectInput.left;
\r
6300 pt.y = rectInput.top + newSizeY - sizeY;
\r
6301 ScreenToClient(hDlg, &pt);
\r
6302 SetWindowPos(hInput, NULL,
\r
6303 pt.x, pt.y, /* needs client coords */
\r
6304 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
6305 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
6311 case WM_GETMINMAXINFO:
\r
6312 /* Prevent resizing window too small */
\r
6313 mmi = (MINMAXINFO *) lParam;
\r
6314 mmi->ptMinTrackSize.x = 100;
\r
6315 mmi->ptMinTrackSize.y = 100;
\r
6318 return DefWindowProc(hDlg, message, wParam, lParam);
\r
6326 if (hwndConsole) return;
\r
6327 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
6328 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
6333 ConsoleOutput(char* data, int length, int forceVisible)
\r
6338 char buf[CO_MAX+1];
\r
6341 static int delayLF = 0;
\r
6342 CHARRANGE savesel, sel;
\r
6344 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
6352 while (length--) {
\r
6360 } else if (*p == '\007') {
\r
6361 MyPlaySound(&sounds[(int)SoundBell]);
\r
6368 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
6369 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6370 /* Save current selection */
\r
6371 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
6372 exlen = GetWindowTextLength(hText);
\r
6373 /* Find out whether current end of text is visible */
\r
6374 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
6375 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
6376 /* Trim existing text if it's too long */
\r
6377 if (exlen + (q - buf) > CO_MAX) {
\r
6378 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
6381 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6382 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
6384 savesel.cpMin -= trim;
\r
6385 savesel.cpMax -= trim;
\r
6386 if (exlen < 0) exlen = 0;
\r
6387 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
6388 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
6390 /* Append the new text */
\r
6391 sel.cpMin = exlen;
\r
6392 sel.cpMax = exlen;
\r
6393 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6394 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
6395 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
6396 if (forceVisible || exlen == 0 ||
\r
6397 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
6398 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
6399 /* Scroll to make new end of text visible if old end of text
\r
6400 was visible or new text is an echo of user typein */
\r
6401 sel.cpMin = 9999999;
\r
6402 sel.cpMax = 9999999;
\r
6403 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6404 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6405 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
6406 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6408 if (savesel.cpMax == exlen || forceVisible) {
\r
6409 /* Move insert point to new end of text if it was at the old
\r
6410 end of text or if the new text is an echo of user typein */
\r
6411 sel.cpMin = 9999999;
\r
6412 sel.cpMax = 9999999;
\r
6413 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6415 /* Restore previous selection */
\r
6416 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
6418 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6425 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
6426 RECT *rect, char *color)
\r
6430 COLORREF oldFg, oldBg;
\r
6433 if (appData.clockMode) {
\r
6435 sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));
\r
6437 sprintf(buf, "%s: %s", color, TimeString(timeRemaining));
\r
6444 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
6445 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
6447 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
6448 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
6450 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
6452 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
6453 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
6454 rect, str, strlen(str), NULL);
\r
6456 (void) SetTextColor(hdc, oldFg);
\r
6457 (void) SetBkColor(hdc, oldBg);
\r
6458 (void) SelectObject(hdc, oldFont);
\r
6463 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6468 ResetEvent(ovl->hEvent);
\r
6469 ovl->Offset = ovl->OffsetHigh = 0;
\r
6470 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
6474 err = GetLastError();
\r
6475 if (err == ERROR_IO_PENDING) {
\r
6476 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
6480 err = GetLastError();
\r
6487 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6492 ResetEvent(ovl->hEvent);
\r
6493 ovl->Offset = ovl->OffsetHigh = 0;
\r
6494 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
6498 err = GetLastError();
\r
6499 if (err == ERROR_IO_PENDING) {
\r
6500 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
6504 err = GetLastError();
\r
6510 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
6511 void CheckForInputBufferFull( InputSource * is )
6513 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
6514 /* Look for end of line */
6517 while( p < is->next && *p != '\n' ) {
6521 if( p >= is->next ) {
6522 if (appData.debugMode) {
6523 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
6526 is->error = ERROR_BROKEN_PIPE; /* [AS] Just a non-successful code! */
6527 is->count = (DWORD) -2;
6534 InputThread(LPVOID arg)
\r
6539 is = (InputSource *) arg;
\r
6540 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
6541 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
6542 while (is->hThread != NULL) {
\r
6543 is->error = DoReadFile(is->hFile, is->next,
\r
6544 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
6545 &is->count, &ovl);
\r
6546 if (is->error == NO_ERROR) {
\r
6547 is->next += is->count;
\r
6549 if (is->error == ERROR_BROKEN_PIPE) {
\r
6550 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
6553 is->count = (DWORD) -1;
\r
6557 CheckForInputBufferFull( is );
6559 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6560 if (is->count <= 0) break; /* Quit on EOF or error */
\r
6562 CloseHandle(ovl.hEvent);
\r
6563 CloseHandle(is->hFile);
\r
6568 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
6570 NonOvlInputThread(LPVOID arg)
\r
6577 is = (InputSource *) arg;
\r
6578 while (is->hThread != NULL) {
\r
6579 is->error = ReadFile(is->hFile, is->next,
\r
6580 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
6581 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
6582 if (is->error == NO_ERROR) {
\r
6583 /* Change CRLF to LF */
\r
6584 if (is->next > is->buf) {
\r
6586 i = is->count + 1;
\r
6594 if (prev == '\r' && *p == '\n') {
\r
6606 if (is->error == ERROR_BROKEN_PIPE) {
\r
6607 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
6610 is->count = (DWORD) -1;
\r
6614 CheckForInputBufferFull( is );
6616 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6617 if (is->count < 0) break; /* Quit on error */
\r
6619 CloseHandle(is->hFile);
\r
6624 SocketInputThread(LPVOID arg)
\r
6628 is = (InputSource *) arg;
\r
6629 while (is->hThread != NULL) {
\r
6630 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
6631 if ((int)is->count == SOCKET_ERROR) {
\r
6632 is->count = (DWORD) -1;
\r
6633 is->error = WSAGetLastError();
\r
6635 is->error = NO_ERROR;
\r
6636 is->next += is->count;
\r
6637 if (is->count == 0 && is->second == is) {
\r
6638 /* End of file on stderr; quit with no message */
\r
6642 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6643 if (is->count <= 0) break; /* Quit on EOF or error */
\r
6649 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6653 is = (InputSource *) lParam;
\r
6654 if (is->lineByLine) {
\r
6655 /* Feed in lines one by one */
\r
6656 char *p = is->buf;
\r
6658 while (q < is->next) {
\r
6659 if (*q++ == '\n') {
\r
6660 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
6665 /* Move any partial line to the start of the buffer */
\r
6667 while (p < is->next) {
\r
6672 if (is->error != NO_ERROR || is->count == 0) {
\r
6673 /* Notify backend of the error. Note: If there was a partial
\r
6674 line at the end, it is not flushed through. */
\r
6675 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
6678 /* Feed in the whole chunk of input at once */
\r
6679 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
6680 is->next = is->buf;
\r
6684 /*---------------------------------------------------------------------------*\
\r
6686 * Menu enables. Used when setting various modes.
\r
6688 \*---------------------------------------------------------------------------*/
\r
6696 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
6698 while (enab->item > 0) {
\r
6699 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
6704 Enables gnuEnables[] = {
\r
6705 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6706 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6707 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
6708 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
6709 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
6710 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
6711 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6712 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
6713 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
6714 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
6718 Enables icsEnables[] = {
\r
6719 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6720 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6721 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6722 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6723 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6724 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
6725 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
6726 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
6727 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6728 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
6729 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
6730 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
6735 Enables zippyEnables[] = {
\r
6736 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6737 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
6738 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
6743 Enables ncpEnables[] = {
\r
6744 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
6745 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
6746 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6747 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6748 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6749 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
6750 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
6751 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
6752 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
6753 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
6754 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6755 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6756 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
6757 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
6758 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
6762 Enables trainingOnEnables[] = {
\r
6763 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
6764 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
6765 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
6766 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
6767 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
6768 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
6769 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
6770 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
6774 Enables trainingOffEnables[] = {
\r
6775 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
6776 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
6777 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
6778 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
6779 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
6780 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
6781 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
6782 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
6786 /* These modify either ncpEnables or gnuEnables */
\r
6787 Enables cmailEnables[] = {
\r
6788 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
6789 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
6790 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
6791 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
6792 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
6793 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
6794 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
6798 Enables machineThinkingEnables[] = {
\r
6799 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6800 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
6801 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
6802 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
6803 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
6804 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6805 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6806 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6807 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
6808 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
6809 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
6810 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
6811 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
6812 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
6813 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
6817 Enables userThinkingEnables[] = {
\r
6818 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6819 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
6820 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
6821 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
6822 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
6823 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6824 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6825 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6826 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
6827 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
6828 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
6829 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
6830 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
6831 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
6832 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
6836 /*---------------------------------------------------------------------------*\
\r
6838 * Front-end interface functions exported by XBoard.
\r
6839 * Functions appear in same order as prototypes in frontend.h.
\r
6841 \*---------------------------------------------------------------------------*/
\r
6845 static UINT prevChecked = 0;
\r
6846 static int prevPausing = 0;
\r
6849 if (pausing != prevPausing) {
\r
6850 prevPausing = pausing;
\r
6851 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
6852 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
6853 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
6856 switch (gameMode) {
\r
6857 case BeginningOfGame:
\r
6858 if (appData.icsActive)
\r
6859 nowChecked = IDM_IcsClient;
\r
6860 else if (appData.noChessProgram)
\r
6861 nowChecked = IDM_EditGame;
\r
6863 nowChecked = IDM_MachineBlack;
\r
6865 case MachinePlaysBlack:
\r
6866 nowChecked = IDM_MachineBlack;
\r
6868 case MachinePlaysWhite:
\r
6869 nowChecked = IDM_MachineWhite;
\r
6871 case TwoMachinesPlay:
\r
6872 nowChecked = IDM_TwoMachines;
\r
6875 nowChecked = IDM_AnalysisMode;
\r
6878 nowChecked = IDM_AnalyzeFile;
\r
6881 nowChecked = IDM_EditGame;
\r
6883 case PlayFromGameFile:
\r
6884 nowChecked = IDM_LoadGame;
\r
6886 case EditPosition:
\r
6887 nowChecked = IDM_EditPosition;
\r
6890 nowChecked = IDM_Training;
\r
6892 case IcsPlayingWhite:
\r
6893 case IcsPlayingBlack:
\r
6894 case IcsObserving:
\r
6896 nowChecked = IDM_IcsClient;
\r
6903 if (prevChecked != 0)
\r
6904 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6905 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
6906 if (nowChecked != 0)
\r
6907 (void) CheckMenuItem(GetMenu(hwndMain),
\r
6908 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
6910 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
6911 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
6912 MF_BYCOMMAND|MF_ENABLED);
\r
6914 (void) EnableMenuItem(GetMenu(hwndMain),
\r
6915 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
6918 prevChecked = nowChecked;
\r
6924 HMENU hmenu = GetMenu(hwndMain);
\r
6925 SetMenuEnables(hmenu, icsEnables);
\r
6926 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
6927 MF_BYPOSITION|MF_ENABLED);
\r
6929 if (appData.zippyPlay) {
\r
6930 SetMenuEnables(hmenu, zippyEnables);
\r
6938 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
6944 HMENU hmenu = GetMenu(hwndMain);
\r
6945 SetMenuEnables(hmenu, ncpEnables);
\r
6946 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
6947 MF_BYPOSITION|MF_GRAYED);
\r
6948 DrawMenuBar(hwndMain);
\r
6954 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
6958 SetTrainingModeOn()
\r
6961 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
6962 for (i = 0; i < N_BUTTONS; i++) {
\r
6963 if (buttonDesc[i].hwnd != NULL)
\r
6964 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
6969 VOID SetTrainingModeOff()
\r
6972 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
6973 for (i = 0; i < N_BUTTONS; i++) {
\r
6974 if (buttonDesc[i].hwnd != NULL)
\r
6975 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
6981 SetUserThinkingEnables()
\r
6983 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
6987 SetMachineThinkingEnables()
\r
6989 HMENU hMenu = GetMenu(hwndMain);
\r
6990 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
6992 SetMenuEnables(hMenu, machineThinkingEnables);
\r
6994 if (gameMode == MachinePlaysBlack) {
\r
6995 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
6996 } else if (gameMode == MachinePlaysWhite) {
\r
6997 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
6998 } else if (gameMode == TwoMachinesPlay) {
\r
6999 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
7005 DisplayTitle(char *str)
\r
7007 char title[MSG_SIZ], *host;
\r
7008 if (str[0] != NULLCHAR) {
\r
7009 strcpy(title, str);
\r
7010 } else if (appData.icsActive) {
\r
7011 if (appData.icsCommPort[0] != NULLCHAR)
\r
7014 host = appData.icsHost;
\r
7015 sprintf(title, "%s: %s", szTitle, host);
\r
7016 } else if (appData.noChessProgram) {
\r
7017 strcpy(title, szTitle);
\r
7019 strcpy(title, szTitle);
\r
7020 strcat(title, ": ");
\r
7021 strcat(title, first.tidy);
\r
7023 SetWindowText(hwndMain, title);
\r
7028 DisplayMessage(char *str1, char *str2)
\r
7032 int remain = MESSAGE_TEXT_MAX - 1;
\r
7035 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
7036 messageText[0] = NULLCHAR;
\r
7038 len = strlen(str1);
\r
7039 if (len > remain) len = remain;
\r
7040 strncpy(messageText, str1, len);
\r
7041 messageText[len] = NULLCHAR;
\r
7044 if (*str2 && remain >= 2) {
\r
7046 strcat(messageText, " ");
\r
7049 len = strlen(str2);
\r
7050 if (len > remain) len = remain;
\r
7051 strncat(messageText, str2, len);
\r
7053 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
7055 if (IsIconic(hwndMain)) return;
\r
7056 hdc = GetDC(hwndMain);
\r
7057 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
7058 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7059 &messageRect, messageText, strlen(messageText), NULL);
\r
7060 (void) SelectObject(hdc, oldFont);
\r
7061 (void) ReleaseDC(hwndMain, hdc);
\r
7065 DisplayError(char *str, int error)
\r
7067 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
7073 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7074 NULL, error, LANG_NEUTRAL,
\r
7075 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7077 sprintf(buf, "%s:\n%s", str, buf2);
\r
7079 ErrorMap *em = errmap;
\r
7080 while (em->err != 0 && em->err != error) em++;
\r
7081 if (em->err != 0) {
\r
7082 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7084 sprintf(buf, "%s:\nError code %d", str, error);
\r
7089 ErrorPopUp("Error", buf);
\r
7094 DisplayMoveError(char *str)
\r
7096 fromX = fromY = -1;
\r
7097 ClearHighlights();
\r
7098 DrawPosition(FALSE, NULL);
\r
7099 if (appData.popupMoveErrors) {
\r
7100 ErrorPopUp("Error", str);
\r
7102 DisplayMessage(str, "");
\r
7103 moveErrorMessageUp = TRUE;
\r
7108 DisplayFatalError(char *str, int error, int exitStatus)
\r
7110 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
7112 char *label = exitStatus ? "Fatal Error" : "Exiting";
\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 if (appData.debugMode) {
\r
7132 fprintf(debugFP, "%s: %s\n", label, str);
\r
7134 if (appData.popupExitMessage) {
\r
7135 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
7136 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
7138 ExitEvent(exitStatus);
\r
7143 DisplayInformation(char *str)
\r
7145 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
7150 DisplayNote(char *str)
\r
7152 ErrorPopUp("Note", str);
\r
7157 char *title, *question, *replyPrefix;
\r
7162 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7164 static QuestionParams *qp;
\r
7165 char reply[MSG_SIZ];
\r
7168 switch (message) {
\r
7169 case WM_INITDIALOG:
\r
7170 qp = (QuestionParams *) lParam;
\r
7171 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7172 SetWindowText(hDlg, qp->title);
\r
7173 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
7174 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
7178 switch (LOWORD(wParam)) {
\r
7180 strcpy(reply, qp->replyPrefix);
\r
7181 if (*reply) strcat(reply, " ");
\r
7182 len = strlen(reply);
\r
7183 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
7184 strcat(reply, "\n");
\r
7185 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
7186 EndDialog(hDlg, TRUE);
\r
7187 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
7190 EndDialog(hDlg, FALSE);
\r
7201 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
7203 QuestionParams qp;
\r
7207 qp.question = question;
\r
7208 qp.replyPrefix = replyPrefix;
\r
7210 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
7211 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
7212 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
7213 FreeProcInstance(lpProc);
\r
7218 DisplayIcsInteractionTitle(char *str)
\r
7220 char consoleTitle[MSG_SIZ];
\r
7222 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
7223 SetWindowText(hwndConsole, consoleTitle);
\r
7227 DrawPosition(int fullRedraw, Board board)
\r
7229 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
7236 fromX = fromY = -1;
\r
7237 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
7238 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
7239 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
7240 dragInfo.lastpos = dragInfo.pos;
\r
7241 dragInfo.start.x = dragInfo.start.y = -1;
\r
7242 dragInfo.from = dragInfo.start;
\r
7244 DrawPosition(TRUE, NULL);
\r
7250 CommentPopUp(char *title, char *str)
\r
7252 HWND hwnd = GetActiveWindow();
\r
7253 EitherCommentPopUp(0, title, str, FALSE);
\r
7254 SetActiveWindow(hwnd);
\r
7258 CommentPopDown(void)
\r
7260 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
7261 if (commentDialog) {
\r
7262 ShowWindow(commentDialog, SW_HIDE);
\r
7264 commentDialogUp = FALSE;
\r
7268 EditCommentPopUp(int index, char *title, char *str)
\r
7270 EitherCommentPopUp(index, title, str, TRUE);
\r
7277 MyPlaySound(&sounds[(int)SoundMove]);
\r
7280 VOID PlayIcsWinSound()
\r
7282 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
7285 VOID PlayIcsLossSound()
\r
7287 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
7290 VOID PlayIcsDrawSound()
\r
7292 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
7295 VOID PlayIcsUnfinishedSound()
\r
7297 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
7303 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
7311 consoleEcho = TRUE;
\r
7312 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7313 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
7314 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7323 consoleEcho = FALSE;
\r
7324 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7325 /* This works OK: set text and background both to the same color */
\r
7327 cf.crTextColor = COLOR_ECHOOFF;
\r
7328 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7329 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
7332 /* No Raw()...? */
\r
7334 void Colorize(ColorClass cc, int continuation)
\r
7336 currentColorClass = cc;
\r
7337 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7338 consoleCF.crTextColor = textAttribs[cc].color;
\r
7339 consoleCF.dwEffects = textAttribs[cc].effects;
\r
7340 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
7346 static char buf[MSG_SIZ];
\r
7347 DWORD bufsiz = MSG_SIZ;
\r
7349 if (!GetUserName(buf, &bufsiz)) {
\r
7350 /*DisplayError("Error getting user name", GetLastError());*/
\r
7351 strcpy(buf, "User");
\r
7359 static char buf[MSG_SIZ];
\r
7360 DWORD bufsiz = MSG_SIZ;
\r
7362 if (!GetComputerName(buf, &bufsiz)) {
\r
7363 /*DisplayError("Error getting host name", GetLastError());*/
\r
7364 strcpy(buf, "Unknown");
\r
7371 ClockTimerRunning()
\r
7373 return clockTimerEvent != 0;
\r
7379 if (clockTimerEvent == 0) return FALSE;
\r
7380 KillTimer(hwndMain, clockTimerEvent);
\r
7381 clockTimerEvent = 0;
\r
7386 StartClockTimer(long millisec)
\r
7388 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
7389 (UINT) millisec, NULL);
\r
7393 DisplayWhiteClock(long timeRemaining, int highlight)
\r
7396 hdc = GetDC(hwndMain);
\r
7397 if (!IsIconic(hwndMain)) {
\r
7398 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");
\r
7400 if (highlight && iconCurrent == iconBlack) {
\r
7401 iconCurrent = iconWhite;
\r
7402 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
7403 if (IsIconic(hwndMain)) {
\r
7404 DrawIcon(hdc, 2, 2, iconCurrent);
\r
7407 (void) ReleaseDC(hwndMain, hdc);
\r
7409 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
7413 DisplayBlackClock(long timeRemaining, int highlight)
\r
7416 hdc = GetDC(hwndMain);
\r
7417 if (!IsIconic(hwndMain)) {
\r
7418 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");
\r
7420 if (highlight && iconCurrent == iconWhite) {
\r
7421 iconCurrent = iconBlack;
\r
7422 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
7423 if (IsIconic(hwndMain)) {
\r
7424 DrawIcon(hdc, 2, 2, iconCurrent);
\r
7427 (void) ReleaseDC(hwndMain, hdc);
\r
7429 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
7434 LoadGameTimerRunning()
\r
7436 return loadGameTimerEvent != 0;
\r
7440 StopLoadGameTimer()
\r
7442 if (loadGameTimerEvent == 0) return FALSE;
\r
7443 KillTimer(hwndMain, loadGameTimerEvent);
\r
7444 loadGameTimerEvent = 0;
\r
7449 StartLoadGameTimer(long millisec)
\r
7451 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
7452 (UINT) millisec, NULL);
\r
7460 char fileTitle[MSG_SIZ];
\r
7462 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
7463 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
7464 appData.oldSaveStyle ? "gam" : "pgn",
\r
7466 "Save Game to File", NULL, fileTitle, NULL);
\r
7468 SaveGame(f, 0, "");
\r
7475 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
7477 if (delayedTimerEvent != 0) {
\r
7478 if (appData.debugMode) {
\r
7479 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
7481 KillTimer(hwndMain, delayedTimerEvent);
\r
7482 delayedTimerEvent = 0;
\r
7483 delayedTimerCallback();
\r
7485 delayedTimerCallback = cb;
\r
7486 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
7487 (UINT) millisec, NULL);
\r
7490 DelayedEventCallback
\r
7493 if (delayedTimerEvent) {
\r
7494 return delayedTimerCallback;
\r
7501 CancelDelayedEvent()
\r
7503 if (delayedTimerEvent) {
\r
7504 KillTimer(hwndMain, delayedTimerEvent);
\r
7505 delayedTimerEvent = 0;
\r
7509 /* Start a child process running the given program.
\r
7510 The process's standard output can be read from "from", and its
\r
7511 standard input can be written to "to".
\r
7512 Exit with fatal error if anything goes wrong.
\r
7513 Returns an opaque pointer that can be used to destroy the process
\r
7517 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
7519 #define BUFSIZE 4096
\r
7521 HANDLE hChildStdinRd, hChildStdinWr,
\r
7522 hChildStdoutRd, hChildStdoutWr;
\r
7523 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
7524 SECURITY_ATTRIBUTES saAttr;
\r
7526 PROCESS_INFORMATION piProcInfo;
\r
7527 STARTUPINFO siStartInfo;
\r
7529 char buf[MSG_SIZ];
\r
7532 if (appData.debugMode) {
\r
7533 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
7538 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
7539 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
7540 saAttr.bInheritHandle = TRUE;
\r
7541 saAttr.lpSecurityDescriptor = NULL;
\r
7544 * The steps for redirecting child's STDOUT:
\r
7545 * 1. Create anonymous pipe to be STDOUT for child.
\r
7546 * 2. Create a noninheritable duplicate of read handle,
\r
7547 * and close the inheritable read handle.
\r
7550 /* Create a pipe for the child's STDOUT. */
\r
7551 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
7552 return GetLastError();
\r
7555 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
7556 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
7557 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
7558 FALSE, /* not inherited */
\r
7559 DUPLICATE_SAME_ACCESS);
\r
7561 return GetLastError();
\r
7563 CloseHandle(hChildStdoutRd);
\r
7566 * The steps for redirecting child's STDIN:
\r
7567 * 1. Create anonymous pipe to be STDIN for child.
\r
7568 * 2. Create a noninheritable duplicate of write handle,
\r
7569 * and close the inheritable write handle.
\r
7572 /* Create a pipe for the child's STDIN. */
\r
7573 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
7574 return GetLastError();
\r
7577 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
7578 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
7579 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
7580 FALSE, /* not inherited */
\r
7581 DUPLICATE_SAME_ACCESS);
\r
7583 return GetLastError();
\r
7585 CloseHandle(hChildStdinWr);
\r
7587 /* Arrange to (1) look in dir for the child .exe file, and
\r
7588 * (2) have dir be the child's working directory. Interpret
\r
7589 * dir relative to the directory WinBoard loaded from. */
\r
7590 GetCurrentDirectory(MSG_SIZ, buf);
\r
7591 SetCurrentDirectory(installDir);
\r
7592 SetCurrentDirectory(dir);
\r
7594 /* Now create the child process. */
\r
7596 siStartInfo.cb = sizeof(STARTUPINFO);
\r
7597 siStartInfo.lpReserved = NULL;
\r
7598 siStartInfo.lpDesktop = NULL;
\r
7599 siStartInfo.lpTitle = NULL;
\r
7600 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
7601 siStartInfo.cbReserved2 = 0;
\r
7602 siStartInfo.lpReserved2 = NULL;
\r
7603 siStartInfo.hStdInput = hChildStdinRd;
\r
7604 siStartInfo.hStdOutput = hChildStdoutWr;
\r
7605 siStartInfo.hStdError = hChildStdoutWr;
\r
7607 fSuccess = CreateProcess(NULL,
\r
7608 cmdLine, /* command line */
\r
7609 NULL, /* process security attributes */
\r
7610 NULL, /* primary thread security attrs */
\r
7611 TRUE, /* handles are inherited */
\r
7612 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
7613 NULL, /* use parent's environment */
\r
7615 &siStartInfo, /* STARTUPINFO pointer */
\r
7616 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
7618 err = GetLastError();
\r
7619 SetCurrentDirectory(buf); /* return to prev directory */
\r
7624 /* Close the handles we don't need in the parent */
\r
7625 CloseHandle(piProcInfo.hThread);
\r
7626 CloseHandle(hChildStdinRd);
\r
7627 CloseHandle(hChildStdoutWr);
\r
7629 /* Prepare return value */
\r
7630 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7631 cp->kind = CPReal;
\r
7632 cp->hProcess = piProcInfo.hProcess;
\r
7633 cp->pid = piProcInfo.dwProcessId;
\r
7634 cp->hFrom = hChildStdoutRdDup;
\r
7635 cp->hTo = hChildStdinWrDup;
\r
7637 *pr = (void *) cp;
\r
7639 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
7640 2000 where engines sometimes don't see the initial command(s)
\r
7641 from WinBoard and hang. I don't understand how that can happen,
\r
7642 but the Sleep is harmless, so I've put it in. Others have also
\r
7643 reported what may be the same problem, so hopefully this will fix
\r
7644 it for them too. */
\r
7652 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
7656 cp = (ChildProc *) pr;
\r
7657 if (cp == NULL) return;
\r
7659 switch (cp->kind) {
\r
7661 /* TerminateProcess is considered harmful, so... */
\r
7662 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
7663 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
7664 /* The following doesn't work because the chess program
\r
7665 doesn't "have the same console" as WinBoard. Maybe
\r
7666 we could arrange for this even though neither WinBoard
\r
7667 nor the chess program uses a console for stdio? */
\r
7668 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
7670 /* [AS] Special termination modes for misbehaving programs... */
7672 if ( appData.debugMode) {
7673 fprintf( debugFP, "Terminating process %u\n", cp->pid );
7676 TerminateProcess( cp->hProcess, 0 );
7678 else if( signal == 10 ) {
7679 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
7681 if( dw != WAIT_OBJECT_0 ) {
7682 if ( appData.debugMode) {
7683 fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
7686 TerminateProcess( cp->hProcess, 0 );
7690 CloseHandle(cp->hProcess);
\r
7694 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
7698 closesocket(cp->sock);
\r
7703 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
7704 closesocket(cp->sock);
\r
7705 closesocket(cp->sock2);
\r
7713 InterruptChildProcess(ProcRef pr)
\r
7717 cp = (ChildProc *) pr;
\r
7718 if (cp == NULL) return;
\r
7719 switch (cp->kind) {
\r
7721 /* The following doesn't work because the chess program
\r
7722 doesn't "have the same console" as WinBoard. Maybe
\r
7723 we could arrange for this even though neither WinBoard
\r
7724 nor the chess program uses a console for stdio */
\r
7725 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
7730 /* Can't interrupt */
\r
7734 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
7741 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
7743 char cmdLine[MSG_SIZ];
\r
7745 if (port[0] == NULLCHAR) {
\r
7746 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
7748 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
7750 return StartChildProcess(cmdLine, "", pr);
\r
7754 /* Code to open TCP sockets */
\r
7757 OpenTCP(char *host, char *port, ProcRef *pr)
\r
7762 struct sockaddr_in sa, mysa;
\r
7763 struct hostent FAR *hp;
\r
7764 unsigned short uport;
\r
7765 WORD wVersionRequested;
\r
7768 /* Initialize socket DLL */
\r
7769 wVersionRequested = MAKEWORD(1, 1);
\r
7770 err = WSAStartup(wVersionRequested, &wsaData);
\r
7771 if (err != 0) return err;
\r
7774 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7775 err = WSAGetLastError();
\r
7780 /* Bind local address using (mostly) don't-care values.
\r
7782 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7783 mysa.sin_family = AF_INET;
\r
7784 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7785 uport = (unsigned short) 0;
\r
7786 mysa.sin_port = htons(uport);
\r
7787 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7788 == SOCKET_ERROR) {
\r
7789 err = WSAGetLastError();
\r
7794 /* Resolve remote host name */
\r
7795 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7796 if (!(hp = gethostbyname(host))) {
\r
7797 unsigned int b0, b1, b2, b3;
\r
7799 err = WSAGetLastError();
\r
7801 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7802 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7803 hp->h_addrtype = AF_INET;
\r
7805 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7806 hp->h_addr_list[0] = (char *) malloc(4);
\r
7807 hp->h_addr_list[0][0] = (char) b0;
\r
7808 hp->h_addr_list[0][1] = (char) b1;
\r
7809 hp->h_addr_list[0][2] = (char) b2;
\r
7810 hp->h_addr_list[0][3] = (char) b3;
\r
7816 sa.sin_family = hp->h_addrtype;
\r
7817 uport = (unsigned short) atoi(port);
\r
7818 sa.sin_port = htons(uport);
\r
7819 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7821 /* Make connection */
\r
7822 if (connect(s, (struct sockaddr *) &sa,
\r
7823 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7824 err = WSAGetLastError();
\r
7829 /* Prepare return value */
\r
7830 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7831 cp->kind = CPSock;
\r
7833 *pr = (ProcRef *) cp;
\r
7839 OpenCommPort(char *name, ProcRef *pr)
\r
7844 char fullname[MSG_SIZ];
\r
7846 if (*name != '\\')
\r
7847 sprintf(fullname, "\\\\.\\%s", name);
\r
7849 strcpy(fullname, name);
\r
7851 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
7852 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
7853 if (h == (HANDLE) -1) {
\r
7854 return GetLastError();
\r
7858 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
7860 /* Accumulate characters until a 100ms pause, then parse */
\r
7861 ct.ReadIntervalTimeout = 100;
\r
7862 ct.ReadTotalTimeoutMultiplier = 0;
\r
7863 ct.ReadTotalTimeoutConstant = 0;
\r
7864 ct.WriteTotalTimeoutMultiplier = 0;
\r
7865 ct.WriteTotalTimeoutConstant = 0;
\r
7866 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
7868 /* Prepare return value */
\r
7869 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
7870 cp->kind = CPComm;
\r
7873 *pr = (ProcRef *) cp;
\r
7879 OpenLoopback(ProcRef *pr)
\r
7881 DisplayFatalError("Not implemented", 0, 1);
\r
7887 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
7892 struct sockaddr_in sa, mysa;
\r
7893 struct hostent FAR *hp;
\r
7894 unsigned short uport;
\r
7895 WORD wVersionRequested;
\r
7898 char stderrPortStr[MSG_SIZ];
\r
7900 /* Initialize socket DLL */
\r
7901 wVersionRequested = MAKEWORD(1, 1);
\r
7902 err = WSAStartup(wVersionRequested, &wsaData);
\r
7903 if (err != 0) return err;
\r
7905 /* Resolve remote host name */
\r
7906 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
7907 if (!(hp = gethostbyname(host))) {
\r
7908 unsigned int b0, b1, b2, b3;
\r
7910 err = WSAGetLastError();
\r
7912 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
7913 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
7914 hp->h_addrtype = AF_INET;
\r
7916 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
7917 hp->h_addr_list[0] = (char *) malloc(4);
\r
7918 hp->h_addr_list[0][0] = (char) b0;
\r
7919 hp->h_addr_list[0][1] = (char) b1;
\r
7920 hp->h_addr_list[0][2] = (char) b2;
\r
7921 hp->h_addr_list[0][3] = (char) b3;
\r
7927 sa.sin_family = hp->h_addrtype;
\r
7928 uport = (unsigned short) 514;
\r
7929 sa.sin_port = htons(uport);
\r
7930 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
7932 /* Bind local socket to unused "privileged" port address
\r
7934 s = INVALID_SOCKET;
\r
7935 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7936 mysa.sin_family = AF_INET;
\r
7937 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7938 for (fromPort = 1023;; fromPort--) {
\r
7939 if (fromPort < 0) {
\r
7941 return WSAEADDRINUSE;
\r
7943 if (s == INVALID_SOCKET) {
\r
7944 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7945 err = WSAGetLastError();
\r
7950 uport = (unsigned short) fromPort;
\r
7951 mysa.sin_port = htons(uport);
\r
7952 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7953 == SOCKET_ERROR) {
\r
7954 err = WSAGetLastError();
\r
7955 if (err == WSAEADDRINUSE) continue;
\r
7959 if (connect(s, (struct sockaddr *) &sa,
\r
7960 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
7961 err = WSAGetLastError();
\r
7962 if (err == WSAEADDRINUSE) {
\r
7973 /* Bind stderr local socket to unused "privileged" port address
\r
7975 s2 = INVALID_SOCKET;
\r
7976 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
7977 mysa.sin_family = AF_INET;
\r
7978 mysa.sin_addr.s_addr = INADDR_ANY;
\r
7979 for (fromPort = 1023;; fromPort--) {
\r
7980 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
7981 if (fromPort < 0) {
\r
7982 (void) closesocket(s);
\r
7984 return WSAEADDRINUSE;
\r
7986 if (s2 == INVALID_SOCKET) {
\r
7987 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
7988 err = WSAGetLastError();
\r
7994 uport = (unsigned short) fromPort;
\r
7995 mysa.sin_port = htons(uport);
\r
7996 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
7997 == SOCKET_ERROR) {
\r
7998 err = WSAGetLastError();
\r
7999 if (err == WSAEADDRINUSE) continue;
\r
8000 (void) closesocket(s);
\r
8004 if (listen(s2, 1) == SOCKET_ERROR) {
\r
8005 err = WSAGetLastError();
\r
8006 if (err == WSAEADDRINUSE) {
\r
8008 s2 = INVALID_SOCKET;
\r
8011 (void) closesocket(s);
\r
8012 (void) closesocket(s2);
\r
8018 prevStderrPort = fromPort; // remember port used
\r
8019 sprintf(stderrPortStr, "%d", fromPort);
\r
8021 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
8022 err = WSAGetLastError();
\r
8023 (void) closesocket(s);
\r
8024 (void) closesocket(s2);
\r
8029 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
8030 err = WSAGetLastError();
\r
8031 (void) closesocket(s);
\r
8032 (void) closesocket(s2);
\r
8036 if (*user == NULLCHAR) user = UserName();
\r
8037 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
8038 err = WSAGetLastError();
\r
8039 (void) closesocket(s);
\r
8040 (void) closesocket(s2);
\r
8044 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
8045 err = WSAGetLastError();
\r
8046 (void) closesocket(s);
\r
8047 (void) closesocket(s2);
\r
8052 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
8053 err = WSAGetLastError();
\r
8054 (void) closesocket(s);
\r
8055 (void) closesocket(s2);
\r
8059 (void) closesocket(s2); /* Stop listening */
\r
8061 /* Prepare return value */
\r
8062 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8063 cp->kind = CPRcmd;
\r
8066 *pr = (ProcRef *) cp;
\r
8073 AddInputSource(ProcRef pr, int lineByLine,
\r
8074 InputCallback func, VOIDSTAR closure)
\r
8076 InputSource *is, *is2 = NULL;
8077 ChildProc *cp = (ChildProc *) pr;
\r
8079 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
8080 is->lineByLine = lineByLine;
\r
8082 is->closure = closure;
\r
8083 is->second = NULL;
\r
8084 is->next = is->buf;
\r
8085 if (pr == NoProc) {
\r
8086 is->kind = CPReal;
\r
8087 consoleInputSource = is;
\r
8089 is->kind = cp->kind;
\r
8091 [AS] Try to avoid a race condition if the thread is given control too early:
8092 we create all threads suspended to that the is->hThread variable can be
8093 safely assigned, then let the threads start with ResumeThread.
8095 switch (cp->kind) {
\r
8097 is->hFile = cp->hFrom;
\r
8098 cp->hFrom = NULL; /* now owned by InputThread */
\r
8100 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
8101 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8105 is->hFile = cp->hFrom;
\r
8106 cp->hFrom = NULL; /* now owned by InputThread */
\r
8108 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
8109 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8113 is->sock = cp->sock;
\r
8115 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8116 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8120 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
8122 is->sock = cp->sock;
\r
8124 is2->sock = cp->sock2;
\r
8125 is2->second = is2;
\r
8127 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8128 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8130 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8131 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
8135 if( is->hThread != NULL ) {
8136 ResumeThread( is->hThread );
8139 if( is2 != NULL && is2->hThread != NULL ) {
8140 ResumeThread( is2->hThread );
8144 return (InputSourceRef) is;
\r
8148 RemoveInputSource(InputSourceRef isr)
\r
8152 is = (InputSource *) isr;
\r
8153 is->hThread = NULL; /* tell thread to stop */
\r
8154 CloseHandle(is->hThread);
\r
8155 if (is->second != NULL) {
\r
8156 is->second->hThread = NULL;
\r
8157 CloseHandle(is->second->hThread);
\r
8163 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
8166 int outCount = SOCKET_ERROR;
\r
8167 ChildProc *cp = (ChildProc *) pr;
\r
8168 static OVERLAPPED ovl;
\r
8170 if (pr == NoProc) {
\r
8171 ConsoleOutput(message, count, FALSE);
\r
8175 if (ovl.hEvent == NULL) {
\r
8176 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8178 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8180 switch (cp->kind) {
\r
8183 outCount = send(cp->sock, message, count, 0);
\r
8184 if (outCount == SOCKET_ERROR) {
\r
8185 *outError = WSAGetLastError();
\r
8187 *outError = NO_ERROR;
\r
8192 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
8193 &dOutCount, NULL)) {
\r
8194 *outError = NO_ERROR;
\r
8195 outCount = (int) dOutCount;
\r
8197 *outError = GetLastError();
\r
8202 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
8203 &dOutCount, &ovl);
\r
8204 if (*outError == NO_ERROR) {
\r
8205 outCount = (int) dOutCount;
\r
8213 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
8216 /* Ignore delay, not implemented for WinBoard */
\r
8217 return OutputToProcess(pr, message, count, outError);
\r
8222 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
8223 char *buf, int count, int error)
\r
8225 DisplayFatalError("Not implemented", 0, 1);
\r
8228 /* see wgamelist.c for Game List functions */
\r
8229 /* see wedittags.c for Edit Tags functions */
\r
8236 char buf[MSG_SIZ];
\r
8239 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
8240 f = fopen(buf, "r");
\r
8242 ProcessICSInitScript(f);
\r
8250 StartAnalysisClock()
\r
8252 if (analysisTimerEvent) return;
\r
8253 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
8254 (UINT) 2000, NULL);
\r
8258 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8260 static HANDLE hwndText;
\r
8262 static int sizeX, sizeY;
\r
8263 int newSizeX, newSizeY, flags;
\r
8266 switch (message) {
\r
8267 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8268 /* Initialize the dialog items */
\r
8269 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
8270 SetWindowText(hDlg, analysisTitle);
\r
8271 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
8272 /* Size and position the dialog */
\r
8273 if (!analysisDialog) {
\r
8274 analysisDialog = hDlg;
\r
8275 flags = SWP_NOZORDER;
\r
8276 GetClientRect(hDlg, &rect);
\r
8277 sizeX = rect.right;
\r
8278 sizeY = rect.bottom;
\r
8279 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
8280 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
8281 WINDOWPLACEMENT wp;
\r
8282 EnsureOnScreen(&analysisX, &analysisY);
\r
8283 wp.length = sizeof(WINDOWPLACEMENT);
\r
8285 wp.showCmd = SW_SHOW;
\r
8286 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8287 wp.rcNormalPosition.left = analysisX;
\r
8288 wp.rcNormalPosition.right = analysisX + analysisW;
\r
8289 wp.rcNormalPosition.top = analysisY;
\r
8290 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
8291 SetWindowPlacement(hDlg, &wp);
\r
8293 GetClientRect(hDlg, &rect);
\r
8294 newSizeX = rect.right;
\r
8295 newSizeY = rect.bottom;
\r
8296 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
8297 newSizeX, newSizeY);
\r
8304 case WM_COMMAND: /* message: received a command */
\r
8305 switch (LOWORD(wParam)) {
\r
8315 newSizeX = LOWORD(lParam);
\r
8316 newSizeY = HIWORD(lParam);
\r
8317 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
8322 case WM_GETMINMAXINFO:
\r
8323 /* Prevent resizing window too small */
\r
8324 mmi = (MINMAXINFO *) lParam;
\r
8325 mmi->ptMinTrackSize.x = 100;
\r
8326 mmi->ptMinTrackSize.y = 100;
\r
8333 AnalysisPopUp(char* title, char* str)
\r
8338 if (str == NULL) str = "";
\r
8339 p = (char *) malloc(2 * strlen(str) + 2);
\r
8342 if (*str == '\n') *q++ = '\r';
\r
8346 if (analysisText != NULL) free(analysisText);
\r
8349 if (analysisDialog) {
\r
8350 SetWindowText(analysisDialog, title);
\r
8351 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
8352 ShowWindow(analysisDialog, SW_SHOW);
\r
8354 analysisTitle = title;
\r
8355 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
8356 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
8357 hwndMain, (DLGPROC)lpProc);
\r
8358 FreeProcInstance(lpProc);
\r
8360 analysisDialogUp = TRUE;
\r
8366 if (analysisDialog) {
\r
8367 ShowWindow(analysisDialog, SW_HIDE);
\r
8369 analysisDialogUp = FALSE;
\r
8374 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
8376 highlightInfo.sq[0].x = fromX;
\r
8377 highlightInfo.sq[0].y = fromY;
\r
8378 highlightInfo.sq[1].x = toX;
\r
8379 highlightInfo.sq[1].y = toY;
\r
8385 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
8386 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
8390 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
8392 premoveHighlightInfo.sq[0].x = fromX;
\r
8393 premoveHighlightInfo.sq[0].y = fromY;
\r
8394 premoveHighlightInfo.sq[1].x = toX;
\r
8395 premoveHighlightInfo.sq[1].y = toY;
\r
8399 ClearPremoveHighlights()
\r
8401 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
8402 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
8406 ShutDownFrontEnd()
\r
8408 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
8409 DeleteClipboardTempFiles();
\r
8415 if (IsIconic(hwndMain))
\r
8416 ShowWindow(hwndMain, SW_RESTORE);
\r
8418 SetActiveWindow(hwndMain);
\r
8422 * Prototypes for animation support routines
\r
8424 static void ScreenSquare(int column, int row, POINT * pt);
\r
8425 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
8426 POINT frames[], int * nFrames);
\r
8432 AnimateMove(board, fromX, fromY, toX, toY)
\r
8439 ChessSquare piece;
\r
8440 POINT start, finish, mid;
\r
8441 POINT frames[kFactor * 2 + 1];
\r
8444 if (!appData.animate) return;
\r
8445 if (doingSizing) return;
\r
8446 if (fromY < 0 || fromX < 0) return;
\r
8447 piece = board[fromY][fromX];
\r
8448 if (piece >= EmptySquare) return;
\r
8450 ScreenSquare(fromX, fromY, &start);
\r
8451 ScreenSquare(toX, toY, &finish);
\r
8453 /* All pieces except knights move in straight line */
\r
8454 if (piece != WhiteKnight && piece != BlackKnight) {
\r
8455 mid.x = start.x + (finish.x - start.x) / 2;
\r
8456 mid.y = start.y + (finish.y - start.y) / 2;
\r
8458 /* Knight: make diagonal movement then straight */
\r
8459 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
8460 mid.x = start.x + (finish.x - start.x) / 2;
\r
8464 mid.y = start.y + (finish.y - start.y) / 2;
\r
8468 /* Don't use as many frames for very short moves */
\r
8469 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
8470 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
8472 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
8474 animInfo.from.x = fromX;
\r
8475 animInfo.from.y = fromY;
\r
8476 animInfo.to.x = toX;
\r
8477 animInfo.to.y = toY;
\r
8478 animInfo.lastpos = start;
\r
8479 animInfo.piece = piece;
\r
8480 for (n = 0; n < nFrames; n++) {
\r
8481 animInfo.pos = frames[n];
\r
8482 DrawPosition(FALSE, NULL);
\r
8483 animInfo.lastpos = animInfo.pos;
\r
8484 Sleep(appData.animSpeed);
\r
8486 animInfo.pos = finish;
\r
8487 DrawPosition(FALSE, NULL);
\r
8488 animInfo.piece = EmptySquare;
\r
8491 /* Convert board position to corner of screen rect and color */
\r
8494 ScreenSquare(column, row, pt)
\r
8495 int column; int row; POINT * pt;
\r
8498 pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
8499 pt->y = lineGap + row * (squareSize + lineGap);
\r
8501 pt->x = lineGap + column * (squareSize + lineGap);
\r
8502 pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
8506 /* Generate a series of frame coords from start->mid->finish.
\r
8507 The movement rate doubles until the half way point is
\r
8508 reached, then halves back down to the final destination,
\r
8509 which gives a nice slow in/out effect. The algorithmn
\r
8510 may seem to generate too many intermediates for short
\r
8511 moves, but remember that the purpose is to attract the
\r
8512 viewers attention to the piece about to be moved and
\r
8513 then to where it ends up. Too few frames would be less
\r
8517 Tween(start, mid, finish, factor, frames, nFrames)
\r
8518 POINT * start; POINT * mid;
\r
8519 POINT * finish; int factor;
\r
8520 POINT frames[]; int * nFrames;
\r
8522 int n, fraction = 1, count = 0;
\r
8524 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
8525 for (n = 0; n < factor; n++)
\r
8527 for (n = 0; n < factor; n++) {
\r
8528 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
8529 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
8531 fraction = fraction / 2;
\r
8535 frames[count] = *mid;
\r
8538 /* Slow out, stepping 1/2, then 1/4, ... */
\r
8540 for (n = 0; n < factor; n++) {
\r
8541 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
8542 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
8544 fraction = fraction * 2;
\r
8550 HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current)
\r
8552 /* Currently not implemented in WinBoard */
\r