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
90 void mysrandom(unsigned int seed);
94 POINT pos; /* window coordinates of current pos */
\r
95 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
96 POINT from; /* board coordinates of the piece's orig pos */
\r
97 POINT to; /* board coordinates of the piece's new pos */
\r
100 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
103 POINT start; /* window coordinates of start pos */
\r
104 POINT pos; /* window coordinates of current pos */
\r
105 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
106 POINT from; /* board coordinates of the piece's orig pos */
\r
109 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
112 POINT sq[2]; /* board coordinates of from, to squares */
\r
115 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
116 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
118 /* Window class names */
\r
119 char szAppName[] = "WinBoard";
\r
120 char szConsoleName[] = "WBConsole";
\r
122 /* Title bar text */
\r
123 char szTitle[] = "WinBoard";
\r
124 char szConsoleTitle[] = "ICS Interaction";
\r
127 char *settingsFileName;
\r
128 BOOLEAN saveSettingsOnExit;
\r
129 char installDir[MSG_SIZ];
\r
131 BoardSize boardSize;
\r
132 BOOLEAN chessProgram;
\r
133 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
134 static int squareSize, lineGap;
\r
135 static int winWidth, winHeight;
\r
136 static RECT messageRect, whiteRect, blackRect;
\r
137 static char messageText[MESSAGE_TEXT_MAX];
\r
138 static int clockTimerEvent = 0;
\r
139 static int loadGameTimerEvent = 0;
\r
140 static int analysisTimerEvent = 0;
\r
141 static DelayedEventCallback delayedTimerCallback;
\r
142 static int delayedTimerEvent = 0;
\r
143 static int buttonCount = 2;
\r
144 char *icsTextMenuString;
\r
146 char *firstChessProgramNames;
\r
147 char *secondChessProgramNames;
\r
149 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
151 #define PALETTESIZE 256
\r
153 HINSTANCE hInst; /* current instance */
\r
154 HWND hwndMain = NULL; /* root window*/
\r
155 HWND hwndConsole = NULL;
\r
156 BOOLEAN alwaysOnTop = FALSE;
\r
158 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
159 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
161 ColorClass currentColorClass;
\r
163 HWND hCommPort = NULL; /* currently open comm port */
\r
164 static HWND hwndPause; /* pause button */
\r
165 static HBITMAP pieceBitmap[3][(int) WhiteKing + 1];
\r
166 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
167 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
168 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
169 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
170 static HPEN gridPen = NULL;
\r
171 static HPEN highlightPen = NULL;
\r
172 static HPEN premovePen = NULL;
\r
173 static NPLOGPALETTE pLogPal;
\r
174 static BOOL paletteChanged = FALSE;
\r
175 static HICON iconWhite, iconBlack, iconCurrent;
\r
176 static int doingSizing = FALSE;
\r
177 static int lastSizing = 0;
\r
178 static int prevStderrPort;
\r
180 /* [AS] Support for background textures */
181 #define BACK_TEXTURE_MODE_DISABLED 0
182 #define BACK_TEXTURE_MODE_PLAIN 1
183 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
185 static HBITMAP liteBackTexture = NULL;
186 static HBITMAP darkBackTexture = NULL;
187 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
188 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
189 static int backTextureSquareSize = 0;
190 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
192 #if __GNUC__ && !defined(_winmajor)
\r
193 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
195 #define oldDialog (_winmajor < 4)
\r
198 char *defaultTextAttribs[] =
\r
200 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
201 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
211 int cliWidth, cliHeight;
\r
214 SizeInfo sizeInfo[] =
\r
216 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
217 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
218 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
219 { "petite", 33, 1, 1, 1, 0, 0 },
\r
220 { "slim", 37, 2, 1, 0, 0, 0 },
\r
221 { "small", 40, 2, 1, 0, 0, 0 },
\r
222 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
223 { "middling", 49, 2, 0, 0, 0, 0 },
\r
224 { "average", 54, 2, 0, 0, 0, 0 },
\r
225 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
226 { "medium", 64, 3, 0, 0, 0, 0 },
\r
227 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
228 { "large", 80, 3, 0, 0, 0, 0 },
\r
229 { "big", 87, 3, 0, 0, 0, 0 },
\r
230 { "huge", 95, 3, 0, 0, 0, 0 },
\r
231 { "giant", 108, 3, 0, 0, 0, 0 },
\r
232 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
233 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
234 { NULL, 0, 0, 0, 0, 0, 0 }
\r
237 #define MF(x) {x, {0, }, {0, }, 0}
\r
238 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
240 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY),
\r
241 MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY),
\r
242 MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY) },
\r
243 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY),
\r
244 MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY),
\r
245 MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY) },
\r
246 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY),
\r
247 MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY),
\r
248 MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY) },
\r
249 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE),
\r
250 MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE),
\r
251 MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE) },
\r
252 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM),
\r
253 MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM),
\r
254 MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM) },
\r
255 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL),
\r
256 MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL),
\r
257 MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL) },
\r
258 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE),
\r
259 MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE),
\r
260 MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE) },
\r
261 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING),
\r
262 MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING),
\r
263 MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING) },
\r
264 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE),
\r
265 MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE),
\r
266 MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE) },
\r
267 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE),
\r
268 MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE),
\r
269 MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE) },
\r
270 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM),
\r
271 MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM),
\r
272 MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM) },
\r
273 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY),
\r
274 MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY),
\r
275 MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY) },
\r
276 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE),
\r
277 MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE),
\r
278 MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE) },
\r
279 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG),
\r
280 MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG),
\r
281 MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG) },
\r
282 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE),
\r
283 MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE),
\r
284 MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE) },
\r
285 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT),
\r
286 MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT),
\r
287 MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT) },
\r
288 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL),
\r
289 MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL),
\r
290 MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL) },
\r
291 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC),
\r
292 MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC),
\r
293 MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC) },
\r
296 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
305 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
306 #define N_BUTTONS 5
\r
308 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
310 {"<<", IDM_ToStart, NULL, NULL},
\r
311 {"<", IDM_Backward, NULL, NULL},
\r
312 {"P", IDM_Pause, NULL, NULL},
\r
313 {">", IDM_Forward, NULL, NULL},
\r
314 {">>", IDM_ToEnd, NULL, NULL},
\r
317 int tinyLayout = 0, smallLayout = 0;
\r
318 #define MENU_BAR_ITEMS 6
\r
319 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
320 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
321 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
325 MySound sounds[(int)NSoundClasses];
\r
326 MyTextAttribs textAttribs[(int)NColorClasses];
\r
328 MyColorizeAttribs colorizeAttribs[] = {
\r
329 { (COLORREF)0, 0, "Shout Text" },
\r
330 { (COLORREF)0, 0, "SShout/CShout" },
\r
331 { (COLORREF)0, 0, "Channel 1 Text" },
\r
332 { (COLORREF)0, 0, "Channel Text" },
\r
333 { (COLORREF)0, 0, "Kibitz Text" },
\r
334 { (COLORREF)0, 0, "Tell Text" },
\r
335 { (COLORREF)0, 0, "Challenge Text" },
\r
336 { (COLORREF)0, 0, "Request Text" },
\r
337 { (COLORREF)0, 0, "Seek Text" },
\r
338 { (COLORREF)0, 0, "Normal Text" },
\r
339 { (COLORREF)0, 0, "None" }
\r
344 static char *commentTitle;
\r
345 static char *commentText;
\r
346 static int commentIndex;
\r
347 static Boolean editComment = FALSE;
\r
348 HWND commentDialog = NULL;
\r
349 BOOLEAN commentDialogUp = FALSE;
\r
350 static int commentX, commentY, commentH, commentW;
\r
352 static char *analysisTitle;
\r
353 static char *analysisText;
\r
354 HWND analysisDialog = NULL;
\r
355 BOOLEAN analysisDialogUp = FALSE;
\r
356 static int analysisX, analysisY, analysisH, analysisW;
\r
358 char errorTitle[MSG_SIZ];
\r
359 char errorMessage[2*MSG_SIZ];
\r
360 HWND errorDialog = NULL;
\r
361 BOOLEAN moveErrorMessageUp = FALSE;
\r
362 BOOLEAN consoleEcho = TRUE;
\r
363 CHARFORMAT consoleCF;
\r
364 COLORREF consoleBackgroundColor;
\r
366 char *programVersion;
\r
372 typedef int CPKind;
\r
381 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
384 #define INPUT_SOURCE_BUF_SIZE 4096
\r
386 typedef struct _InputSource {
\r
393 char buf[INPUT_SOURCE_BUF_SIZE];
\r
397 InputCallback func;
\r
398 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
402 InputSource *consoleInputSource;
\r
407 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
408 VOID ConsoleCreate();
\r
410 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
411 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
412 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
413 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
415 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
416 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
417 void ParseIcsTextMenu(char *icsTextMenuString);
\r
418 VOID PopUpMoveDialog(char firstchar);
\r
419 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
423 int GameListOptions();
425 HWND moveHistoryDialog = NULL;
426 BOOLEAN moveHistoryDialogUp = FALSE;
428 WindowPlacement wpMoveHistory;
430 HWND evalGraphDialog = NULL;
431 BOOLEAN evalGraphDialogUp = FALSE;
433 WindowPlacement wpEvalGraph;
435 HWND engineOutputDialog = NULL;
436 BOOLEAN engineOutputDialogUp = FALSE;
438 WindowPlacement wpEngineOutput;
440 VOID MoveHistoryPopUp();
441 VOID MoveHistoryPopDown();
442 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
443 BOOL MoveHistoryIsUp();
445 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
446 VOID EvalGraphPopUp();
447 VOID EvalGraphPopDown();
448 BOOL EvalGraphIsUp();
450 VOID EngineOutputPopUp();
451 VOID EngineOutputPopDown();
452 BOOL EngineOutputIsUp();
453 VOID EngineOutputUpdate( int which, int depth, unsigned long nodes, int score, int time, char * pv );
456 * Setting "frozen" should disable all user input other than deleting
\r
457 * the window. We do this while engines are initializing themselves.
\r
459 static int frozen = 0;
\r
460 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
466 if (frozen) return;
\r
468 hmenu = GetMenu(hwndMain);
\r
469 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
470 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
472 DrawMenuBar(hwndMain);
\r
475 /* Undo a FreezeUI */
\r
481 if (!frozen) return;
\r
483 hmenu = GetMenu(hwndMain);
\r
484 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
485 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
487 DrawMenuBar(hwndMain);
\r
490 /*---------------------------------------------------------------------------*\
\r
494 \*---------------------------------------------------------------------------*/
\r
497 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
498 LPSTR lpCmdLine, int nCmdShow)
\r
501 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
505 LoadLibrary("RICHED32.DLL");
\r
506 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
508 if (!InitApplication(hInstance)) {
\r
511 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
515 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
516 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
517 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
519 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
521 while (GetMessage(&msg, /* message structure */
\r
522 NULL, /* handle of window receiving the message */
\r
523 0, /* lowest message to examine */
\r
524 0)) /* highest message to examine */
\r
526 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
527 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
528 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
529 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
530 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
531 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
532 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
533 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
534 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
535 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
536 TranslateMessage(&msg); /* Translates virtual key codes */
\r
537 DispatchMessage(&msg); /* Dispatches message to window */
\r
542 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
545 /*---------------------------------------------------------------------------*\
\r
547 * Initialization functions
\r
549 \*---------------------------------------------------------------------------*/
\r
552 InitApplication(HINSTANCE hInstance)
\r
556 /* Fill in window class structure with parameters that describe the */
\r
559 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
560 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
561 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
562 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
563 wc.hInstance = hInstance; /* Owner of this class */
\r
564 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
565 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
566 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
567 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
568 wc.lpszClassName = szAppName; /* Name to register as */
\r
570 /* Register the window class and return success/failure code. */
\r
571 if (!RegisterClass(&wc)) return FALSE;
\r
573 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
574 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
576 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
577 wc.hInstance = hInstance;
\r
578 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
579 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
580 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
581 wc.lpszMenuName = NULL;
\r
582 wc.lpszClassName = szConsoleName;
\r
584 if (!RegisterClass(&wc)) return FALSE;
\r
589 /* Set by InitInstance, used by EnsureOnScreen */
\r
590 int screenHeight, screenWidth;
\r
593 EnsureOnScreen(int *x, int *y)
\r
595 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
596 if (*x > screenWidth - 32) *x = 0;
\r
597 if (*y > screenHeight - 32) *y = 0;
\r
601 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
603 HWND hwnd; /* Main window handle. */
\r
605 WINDOWPLACEMENT wp;
\r
608 hInst = hInstance; /* Store instance handle in our global variable */
\r
610 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
611 *filepart = NULLCHAR;
\r
613 GetCurrentDirectory(MSG_SIZ, installDir);
\r
615 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
616 if (appData.debugMode) {
\r
617 debugFP = fopen(appData.nameOfDebugFile, "w");
618 setbuf(debugFP, NULL);
\r
623 /* Create a main window for this application instance. */
\r
624 hwnd = CreateWindow(szAppName, szTitle,
\r
625 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
626 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
627 NULL, NULL, hInstance, NULL);
\r
630 /* If window could not be created, return "failure" */
\r
635 iconWhite = LoadIcon(hInstance, "icon_white");
\r
636 iconBlack = LoadIcon(hInstance, "icon_black");
\r
637 iconCurrent = iconWhite;
\r
638 InitDrawingColors();
\r
639 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
640 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
641 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
642 /* Compute window size for each board size, and use the largest
\r
643 size that fits on this screen as the default. */
\r
644 InitDrawingSizes((BoardSize)ibs, 0);
\r
645 if (boardSize == (BoardSize)-1 &&
\r
646 winHeight <= screenHeight && winWidth <= screenWidth) {
\r
647 boardSize = (BoardSize)ibs;
\r
650 InitDrawingSizes(boardSize, 0);
\r
652 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
654 /* [AS] Load textures if specified */
655 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
657 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
658 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
659 liteBackTextureMode = appData.liteBackTextureMode;
661 if (liteBackTexture == NULL && appData.debugMode) {
662 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
666 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
667 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
668 darkBackTextureMode = appData.darkBackTextureMode;
670 if (darkBackTexture == NULL && appData.debugMode) {
671 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
675 mysrandom( (unsigned) time(NULL) );
677 /* Make a console window if needed */
\r
678 if (appData.icsActive) {
\r
682 /* [AS] Restore layout */
683 if( wpMoveHistory.visible ) {
687 if( wpEvalGraph.visible ) {
691 if( wpEngineOutput.visible ) {
697 /* Make the window visible; update its client area; and return "success" */
\r
698 EnsureOnScreen(&boardX, &boardY);
\r
699 wp.length = sizeof(WINDOWPLACEMENT);
\r
701 wp.showCmd = nCmdShow;
\r
702 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
703 wp.rcNormalPosition.left = boardX;
\r
704 wp.rcNormalPosition.right = boardX + winWidth;
\r
705 wp.rcNormalPosition.top = boardY;
\r
706 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
707 SetWindowPlacement(hwndMain, &wp);
\r
709 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
710 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
712 /* [AS] Disable the FRC stuff if not playing the proper variant */
713 if( gameInfo.variant != VariantFischeRandom ) {
714 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
719 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
720 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
722 ShowWindow(hwndConsole, nCmdShow);
\r
724 UpdateWindow(hwnd);
\r
732 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
733 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
734 ArgSettingsFilename
\r
742 String *pString; // ArgString
\r
743 int *pInt; // ArgInt
\r
744 float *pFloat; // ArgFloat
\r
745 Boolean *pBoolean; // ArgBoolean
\r
746 COLORREF *pColor; // ArgColor
\r
747 ColorClass cc; // ArgAttribs
\r
748 String *pFilename; // ArgFilename
\r
749 BoardSize *pBoardSize; // ArgBoardSize
\r
750 int whichFont; // ArgFont
\r
751 DCB *pDCB; // ArgCommSettings
\r
752 String *pFilename; // ArgSettingsFilename
\r
760 ArgDescriptor argDescriptors[] = {
\r
761 /* positional arguments */
\r
762 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
763 { "", ArgNone, NULL },
\r
764 /* keyword arguments */
\r
765 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
766 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
767 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
768 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
769 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
770 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
771 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
772 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
773 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
774 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
775 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
776 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
777 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
778 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
779 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
780 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
781 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
782 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
784 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
786 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
788 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
789 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
791 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
792 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
793 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
794 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
795 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
796 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
797 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
798 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
799 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
800 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
801 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
802 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
803 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
804 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
805 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
806 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
807 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
808 /*!!bitmapDirectory?*/
\r
809 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
810 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
811 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
812 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
813 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
814 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
815 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
816 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
817 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
818 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
819 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
820 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
821 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
822 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
823 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
824 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
825 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
826 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
827 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
828 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
829 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
830 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
831 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
832 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
833 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
834 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
835 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
836 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
837 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
838 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
839 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
840 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
841 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
842 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
843 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
844 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
845 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
846 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
847 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
848 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
849 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
850 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
851 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
852 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
853 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
854 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
855 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
856 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
857 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
858 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
859 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
860 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
861 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
862 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
863 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
864 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
865 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
866 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
867 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
868 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
869 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
870 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
871 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
872 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
873 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
874 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
875 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
876 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
877 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
878 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
879 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
880 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
881 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
882 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
883 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
884 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
885 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
886 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
887 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
888 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
889 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
890 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
891 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
892 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
893 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
894 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
895 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
896 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
897 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
898 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
899 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
900 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
901 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
902 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
903 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
904 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
905 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
906 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
907 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
908 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
909 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
910 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
911 TRUE }, /* must come after all fonts */
\r
912 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
913 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
914 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
915 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
916 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
917 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
918 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
919 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
920 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
921 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
922 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
923 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
924 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
925 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
926 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
927 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
928 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
929 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
930 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
931 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
932 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
933 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
934 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
935 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
936 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
937 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
938 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
939 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
940 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
941 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
942 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
944 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
945 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
947 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
948 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
949 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
950 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
951 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
952 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
953 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
954 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
955 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
956 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
957 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
958 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
959 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
960 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
961 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
962 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
963 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
964 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
965 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
966 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
967 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
968 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
969 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
970 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
971 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
972 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
973 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
974 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
975 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
976 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
977 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
978 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
979 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
980 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
981 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
982 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
983 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
984 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
985 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
986 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
987 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
988 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
989 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
990 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
991 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
992 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
993 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
994 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
995 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
996 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
997 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
998 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
999 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1000 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1001 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1002 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1003 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1004 { "highlightLastMove", ArgBoolean,
\r
1005 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1006 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1007 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1008 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1009 { "highlightDragging", ArgBoolean,
\r
1010 (LPVOID) &appData.highlightDragging, TRUE },
\r
1011 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1012 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1013 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1014 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1015 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1016 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1017 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1018 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1019 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1020 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1021 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1022 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1023 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1024 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1025 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1026 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1027 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1028 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1029 { "soundShout", ArgFilename,
\r
1030 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1031 { "soundSShout", ArgFilename,
\r
1032 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1033 { "soundChannel1", ArgFilename,
\r
1034 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1035 { "soundChannel", ArgFilename,
\r
1036 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1037 { "soundKibitz", ArgFilename,
\r
1038 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1039 { "soundTell", ArgFilename,
\r
1040 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1041 { "soundChallenge", ArgFilename,
\r
1042 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1043 { "soundRequest", ArgFilename,
\r
1044 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1045 { "soundSeek", ArgFilename,
\r
1046 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1047 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1048 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1049 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1050 { "soundIcsLoss", ArgFilename,
\r
1051 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1052 { "soundIcsDraw", ArgFilename,
\r
1053 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1054 { "soundIcsUnfinished", ArgFilename,
\r
1055 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1056 { "soundIcsAlarm", ArgFilename,
\r
1057 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1058 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1059 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1060 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1061 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1062 { "reuseChessPrograms", ArgBoolean,
\r
1063 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1064 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1065 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1066 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1067 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1068 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1069 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1070 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1071 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1072 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1073 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1074 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1075 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1076 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1077 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1078 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1079 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1080 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1081 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1082 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1083 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1084 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1085 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1086 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1087 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1088 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1089 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1090 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1091 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1092 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1093 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1094 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1095 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1096 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1097 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1098 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1099 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1100 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1102 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1104 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1105 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1106 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1107 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
1108 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
1109 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1110 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1111 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1112 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1113 /* [AS] New features */
1114 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
1115 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
1116 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
1117 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
1118 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
1119 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
1120 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
1121 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
1122 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
1123 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
1124 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
1125 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
1126 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
1127 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
1128 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
1129 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
1130 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
1131 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
1132 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
1133 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
1134 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
1135 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
1136 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
1137 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
1138 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
1139 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
1140 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
1141 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
1142 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
1143 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
1144 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
1145 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
1146 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
1147 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
1149 /* [AS] Layout stuff */
1150 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
1151 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
1152 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
1153 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
1154 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
1156 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
1157 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
1158 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
1159 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
1160 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
1162 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
1163 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
1164 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
1165 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
1166 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
1169 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1170 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1171 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1172 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1173 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1174 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1175 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1176 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1177 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1178 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1179 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1180 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1181 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1183 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1184 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1185 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1186 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1187 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1188 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1189 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1191 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1192 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1193 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1194 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1195 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1196 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1197 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1198 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1199 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1200 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1201 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1202 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1203 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1204 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1205 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1206 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1207 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1208 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1210 { NULL, ArgNone, NULL, FALSE }
\r
1214 /* Kludge for indirection files on command line */
\r
1215 char* lastIndirectionFilename;
\r
1216 ArgDescriptor argDescriptorIndirection =
\r
1217 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1221 ExitArgError(char *msg, char *badArg)
\r
1223 char buf[MSG_SIZ];
\r
1225 sprintf(buf, "%s %s", msg, badArg);
\r
1226 DisplayFatalError(buf, 0, 2);
\r
1230 /* Command line font name parser. NULL name means do nothing.
\r
1231 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1232 For backward compatibility, syntax without the colon is also
\r
1233 accepted, but font names with digits in them won't work in that case.
\r
1236 ParseFontName(char *name, MyFontParams *mfp)
\r
1239 if (name == NULL) return;
\r
1241 q = strchr(p, ':');
\r
1243 if (q - p >= sizeof(mfp->faceName))
\r
1244 ExitArgError("Font name too long:", name);
\r
1245 memcpy(mfp->faceName, p, q - p);
\r
1246 mfp->faceName[q - p] = NULLCHAR;
\r
1249 q = mfp->faceName;
\r
1250 while (*p && !isdigit(*p)) {
\r
1252 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1253 ExitArgError("Font name too long:", name);
\r
1255 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1258 if (!*p) ExitArgError("Font point size missing:", name);
\r
1259 mfp->pointSize = (float) atof(p);
\r
1260 mfp->bold = (strchr(p, 'b') != NULL);
\r
1261 mfp->italic = (strchr(p, 'i') != NULL);
\r
1262 mfp->underline = (strchr(p, 'u') != NULL);
\r
1263 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1266 /* Color name parser.
\r
1267 X version accepts X color names, but this one
\r
1268 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1270 ParseColorName(char *name)
\r
1272 int red, green, blue, count;
\r
1273 char buf[MSG_SIZ];
\r
1275 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1277 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1278 &red, &green, &blue);
\r
1281 sprintf(buf, "Can't parse color name %s", name);
\r
1282 DisplayError(buf, 0);
\r
1283 return RGB(0, 0, 0);
\r
1285 return PALETTERGB(red, green, blue);
\r
1289 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1291 char *e = argValue;
\r
1295 if (*e == 'b') eff |= CFE_BOLD;
\r
1296 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1297 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1298 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1299 else if (*e == '#' || isdigit(*e)) break;
\r
1303 *color = ParseColorName(e);
\r
1308 ParseBoardSize(char *name)
\r
1310 BoardSize bs = SizeTiny;
\r
1311 while (sizeInfo[bs].name != NULL) {
\r
1312 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1315 ExitArgError("Unrecognized board size value", name);
\r
1316 return bs; /* not reached */
\r
1321 StringGet(void *getClosure)
\r
1323 char **p = (char **) getClosure;
\r
1328 FileGet(void *getClosure)
\r
1331 FILE* f = (FILE*) getClosure;
\r
1340 /* Parse settings file named "name". If file found, return the
\r
1341 full name in fullname and return TRUE; else return FALSE */
\r
1343 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1348 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1349 f = fopen(fullname, "r");
\r
1351 ParseArgs(FileGet, f);
\r
1360 ParseArgs(GetFunc get, void *cl)
\r
1362 char argName[ARG_MAX];
\r
1363 char argValue[ARG_MAX];
\r
1364 ArgDescriptor *ad;
\r
1373 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1374 if (ch == NULLCHAR) break;
\r
1376 /* Comment to end of line */
\r
1378 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1380 } else if (ch == '/' || ch == '-') {
\r
1383 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1384 ch != '\n' && ch != '\t') {
\r
1390 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1391 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1393 if (ad->argName == NULL)
\r
1394 ExitArgError("Unrecognized argument", argName);
\r
1396 } else if (ch == '@') {
\r
1397 /* Indirection file */
\r
1398 ad = &argDescriptorIndirection;
\r
1401 /* Positional argument */
\r
1402 ad = &argDescriptors[posarg++];
\r
1403 strcpy(argName, ad->argName);
\r
1406 if (ad->argType == ArgTrue) {
\r
1407 *(Boolean *) ad->argLoc = TRUE;
\r
1410 if (ad->argType == ArgFalse) {
\r
1411 *(Boolean *) ad->argLoc = FALSE;
\r
1415 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1416 if (ch == NULLCHAR || ch == '\n') {
\r
1417 ExitArgError("No value provided for argument", argName);
\r
1421 // Quoting with { }. No characters have to (or can) be escaped.
\r
1422 // Thus the string cannot contain a '}' character.
\r
1442 } else if (ch == '\'' || ch == '"') {
\r
1443 // Quoting with ' ' or " ", with \ as escape character.
\r
1444 // Inconvenient for long strings that may contain Windows filenames.
\r
1461 if (ch == start) {
\r
1470 if (ad->argType == ArgFilename
\r
1471 || ad->argType == ArgSettingsFilename) {
\r
1477 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1501 for (i = 0; i < 3; i++) {
\r
1502 if (ch >= '0' && ch <= '7') {
\r
1503 octval = octval*8 + (ch - '0');
\r
1510 *q++ = (char) octval;
\r
1521 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1528 switch (ad->argType) {
\r
1530 *(int *) ad->argLoc = atoi(argValue);
\r
1534 *(float *) ad->argLoc = (float) atof(argValue);
\r
1539 *(char **) ad->argLoc = strdup(argValue);
\r
1542 case ArgSettingsFilename:
\r
1544 char fullname[MSG_SIZ];
\r
1545 if (ParseSettingsFile(argValue, fullname)) {
\r
1546 if (ad->argLoc != NULL) {
\r
1547 *(char **) ad->argLoc = strdup(fullname);
\r
1550 if (ad->argLoc != NULL) {
\r
1552 ExitArgError("Failed to open indirection file", argValue);
\r
1559 switch (argValue[0]) {
\r
1562 *(Boolean *) ad->argLoc = TRUE;
\r
1566 *(Boolean *) ad->argLoc = FALSE;
\r
1569 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1575 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1578 case ArgAttribs: {
\r
1579 ColorClass cc = (ColorClass)ad->argLoc;
\r
1580 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1584 case ArgBoardSize:
\r
1585 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1589 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1592 case ArgCommSettings:
\r
1593 ParseCommSettings(argValue, &dcb);
\r
1597 ExitArgError("Unrecognized argument", argValue);
\r
1604 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1606 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1607 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1610 lf->lfEscapement = 0;
\r
1611 lf->lfOrientation = 0;
\r
1612 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1613 lf->lfItalic = mfp->italic;
\r
1614 lf->lfUnderline = mfp->underline;
\r
1615 lf->lfStrikeOut = mfp->strikeout;
\r
1616 lf->lfCharSet = DEFAULT_CHARSET;
\r
1617 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1618 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1619 lf->lfQuality = DEFAULT_QUALITY;
\r
1620 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1621 strcpy(lf->lfFaceName, mfp->faceName);
\r
1625 CreateFontInMF(MyFont *mf)
\r
1627 LFfromMFP(&mf->lf, &mf->mfp);
\r
1628 if (mf->hf) DeleteObject(mf->hf);
\r
1629 mf->hf = CreateFontIndirect(&mf->lf);
\r
1633 SetDefaultTextAttribs()
\r
1636 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1637 ParseAttribs(&textAttribs[cc].color,
\r
1638 &textAttribs[cc].effects,
\r
1639 defaultTextAttribs[cc]);
\r
1644 SetDefaultSounds()
\r
1648 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1649 textAttribs[cc].sound.name = strdup("");
\r
1650 textAttribs[cc].sound.data = NULL;
\r
1652 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1653 sounds[sc].name = strdup("");
\r
1654 sounds[sc].data = NULL;
\r
1656 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1664 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1665 MyLoadSound(&textAttribs[cc].sound);
\r
1667 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1668 MyLoadSound(&sounds[sc]);
\r
1673 InitAppData(LPSTR lpCmdLine)
\r
1676 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1679 programName = szAppName;
\r
1681 /* Initialize to defaults */
\r
1682 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1683 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1684 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1685 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1686 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1687 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1688 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1689 SetDefaultTextAttribs();
\r
1690 SetDefaultSounds();
\r
1691 appData.movesPerSession = MOVES_PER_SESSION;
\r
1692 appData.initString = INIT_STRING;
\r
1693 appData.secondInitString = INIT_STRING;
\r
1694 appData.firstComputerString = COMPUTER_STRING;
\r
1695 appData.secondComputerString = COMPUTER_STRING;
\r
1696 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1697 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1698 appData.firstPlaysBlack = FALSE;
\r
1699 appData.noChessProgram = FALSE;
\r
1700 chessProgram = FALSE;
\r
1701 appData.firstHost = FIRST_HOST;
\r
1702 appData.secondHost = SECOND_HOST;
\r
1703 appData.firstDirectory = FIRST_DIRECTORY;
\r
1704 appData.secondDirectory = SECOND_DIRECTORY;
\r
1705 appData.bitmapDirectory = "";
\r
1706 appData.remoteShell = REMOTE_SHELL;
\r
1707 appData.remoteUser = "";
\r
1708 appData.timeDelay = TIME_DELAY;
\r
1709 appData.timeControl = TIME_CONTROL;
\r
1710 appData.timeIncrement = TIME_INCREMENT;
\r
1711 appData.icsActive = FALSE;
\r
1712 appData.icsHost = "";
\r
1713 appData.icsPort = ICS_PORT;
\r
1714 appData.icsCommPort = ICS_COMM_PORT;
\r
1715 appData.icsLogon = ICS_LOGON;
\r
1716 appData.icsHelper = "";
\r
1717 appData.useTelnet = FALSE;
\r
1718 appData.telnetProgram = TELNET_PROGRAM;
\r
1719 appData.gateway = "";
\r
1720 appData.loadGameFile = "";
\r
1721 appData.loadGameIndex = 0;
\r
1722 appData.saveGameFile = "";
\r
1723 appData.autoSaveGames = FALSE;
\r
1724 appData.loadPositionFile = "";
\r
1725 appData.loadPositionIndex = 1;
\r
1726 appData.savePositionFile = "";
\r
1727 appData.matchMode = FALSE;
\r
1728 appData.matchGames = 0;
\r
1729 appData.monoMode = FALSE;
\r
1730 appData.debugMode = FALSE;
\r
1731 appData.clockMode = TRUE;
\r
1732 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1733 appData.Iconic = FALSE; /*unused*/
\r
1734 appData.searchTime = "";
\r
1735 appData.searchDepth = 0;
\r
1736 appData.showCoords = FALSE;
\r
1737 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1738 appData.autoCallFlag = FALSE;
\r
1739 appData.flipView = FALSE;
\r
1740 appData.autoFlipView = TRUE;
\r
1741 appData.cmailGameName = "";
\r
1742 appData.alwaysPromoteToQueen = FALSE;
\r
1743 appData.oldSaveStyle = FALSE;
\r
1744 appData.quietPlay = FALSE;
\r
1745 appData.showThinking = FALSE;
\r
1746 appData.ponderNextMove = TRUE;
\r
1747 appData.periodicUpdates = TRUE;
\r
1748 appData.popupExitMessage = TRUE;
\r
1749 appData.popupMoveErrors = FALSE;
\r
1750 appData.autoObserve = FALSE;
\r
1751 appData.autoComment = FALSE;
\r
1752 appData.animate = TRUE;
\r
1753 appData.animSpeed = 10;
\r
1754 appData.animateDragging = TRUE;
\r
1755 appData.highlightLastMove = TRUE;
\r
1756 appData.getMoveList = TRUE;
\r
1757 appData.testLegality = TRUE;
\r
1758 appData.premove = TRUE;
\r
1759 appData.premoveWhite = FALSE;
\r
1760 appData.premoveWhiteText = "";
\r
1761 appData.premoveBlack = FALSE;
\r
1762 appData.premoveBlackText = "";
\r
1763 appData.icsAlarm = TRUE;
\r
1764 appData.icsAlarmTime = 5000;
\r
1765 appData.autoRaiseBoard = TRUE;
\r
1766 appData.localLineEditing = TRUE;
\r
1767 appData.colorize = TRUE;
\r
1768 appData.reuseFirst = TRUE;
\r
1769 appData.reuseSecond = TRUE;
\r
1770 appData.blindfold = FALSE;
\r
1771 dcb.DCBlength = sizeof(DCB);
\r
1772 dcb.BaudRate = 9600;
\r
1773 dcb.fBinary = TRUE;
\r
1774 dcb.fParity = FALSE;
\r
1775 dcb.fOutxCtsFlow = FALSE;
\r
1776 dcb.fOutxDsrFlow = FALSE;
\r
1777 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1778 dcb.fDsrSensitivity = FALSE;
\r
1779 dcb.fTXContinueOnXoff = TRUE;
\r
1780 dcb.fOutX = FALSE;
\r
1782 dcb.fNull = FALSE;
\r
1783 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1784 dcb.fAbortOnError = FALSE;
\r
1785 dcb.wReserved = 0;
\r
1787 dcb.Parity = SPACEPARITY;
\r
1788 dcb.StopBits = ONESTOPBIT;
\r
1789 settingsFileName = SETTINGS_FILE;
\r
1790 saveSettingsOnExit = TRUE;
\r
1791 boardX = CW_USEDEFAULT;
\r
1792 boardY = CW_USEDEFAULT;
\r
1793 consoleX = CW_USEDEFAULT;
\r
1794 consoleY = CW_USEDEFAULT;
\r
1795 consoleW = CW_USEDEFAULT;
\r
1796 consoleH = CW_USEDEFAULT;
\r
1797 analysisX = CW_USEDEFAULT;
\r
1798 analysisY = CW_USEDEFAULT;
\r
1799 analysisW = CW_USEDEFAULT;
\r
1800 analysisH = CW_USEDEFAULT;
\r
1801 commentX = CW_USEDEFAULT;
\r
1802 commentY = CW_USEDEFAULT;
\r
1803 commentW = CW_USEDEFAULT;
\r
1804 commentH = CW_USEDEFAULT;
\r
1805 editTagsX = CW_USEDEFAULT;
\r
1806 editTagsY = CW_USEDEFAULT;
\r
1807 editTagsW = CW_USEDEFAULT;
\r
1808 editTagsH = CW_USEDEFAULT;
\r
1809 gameListX = CW_USEDEFAULT;
\r
1810 gameListY = CW_USEDEFAULT;
\r
1811 gameListW = CW_USEDEFAULT;
\r
1812 gameListH = CW_USEDEFAULT;
\r
1813 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1814 icsNames = ICS_NAMES;
\r
1815 firstChessProgramNames = FCP_NAMES;
\r
1816 secondChessProgramNames = SCP_NAMES;
\r
1817 appData.initialMode = "";
\r
1818 appData.variant = "normal";
\r
1819 appData.firstProtocolVersion = PROTOVER;
\r
1820 appData.secondProtocolVersion = PROTOVER;
\r
1821 appData.showButtonBar = TRUE;
\r
1823 /* [AS] New properties (see comments in header file) */
1824 appData.firstScoreIsAbsolute = FALSE;
1825 appData.secondScoreIsAbsolute = FALSE;
1826 appData.saveExtendedInfoInPGN = FALSE;
1827 appData.hideThinkingFromHuman = FALSE;
1828 appData.liteBackTextureFile = "";
1829 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
1830 appData.darkBackTextureFile = "";
1831 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
1832 appData.renderPiecesWithFont = "";
1833 appData.fontToPieceTable = "";
1834 appData.fontBackColorWhite = 0;
1835 appData.fontForeColorWhite = 0;
1836 appData.fontBackColorBlack = 0;
1837 appData.fontForeColorBlack = 0;
1838 appData.fontPieceSize = 80;
1839 appData.overrideLineGap = 1;
1840 appData.adjudicateLossThreshold = 0;
1841 appData.delayBeforeQuit = 0;
1842 appData.delayAfterQuit = 0;
1843 appData.nameOfDebugFile = "winboard.debug";
1844 appData.pgnEventHeader = "Computer Chess Game";
1845 appData.defaultFrcPosition = -1;
1846 appData.gameListTags = GLT_DEFAULT_TAGS;
1847 appData.saveOutOfBookInfo = TRUE;
1848 appData.showEvalInMoveHistory = TRUE;
1849 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
1850 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
1851 appData.highlightMoveWithArrow = FALSE;
1852 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
1853 appData.useStickyWindows = TRUE;
1854 appData.adjudicateDrawMoves = 0;
1855 appData.autoDisplayComment = TRUE;
1856 appData.autoDisplayTags = TRUE;
1858 InitWindowPlacement( &wpMoveHistory );
1859 InitWindowPlacement( &wpEvalGraph );
1860 InitWindowPlacement( &wpEngineOutput );
1863 appData.zippyTalk = ZIPPY_TALK;
\r
1864 appData.zippyPlay = ZIPPY_PLAY;
\r
1865 appData.zippyLines = ZIPPY_LINES;
\r
1866 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1867 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1868 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1869 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1870 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1871 appData.zippyUseI = ZIPPY_USE_I;
\r
1872 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1873 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1874 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1875 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1876 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1877 appData.zippyAbort = ZIPPY_ABORT;
\r
1878 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1879 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1880 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1883 /* Point font array elements to structures and
\r
1884 parse default font names */
\r
1885 for (i=0; i<NUM_FONTS; i++) {
\r
1886 for (j=0; j<NUM_SIZES; j++) {
\r
1887 font[j][i] = &fontRec[j][i];
\r
1888 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1892 /* Parse default settings file if any */
\r
1893 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1894 settingsFileName = strdup(buf);
\r
1897 /* Parse command line */
\r
1898 ParseArgs(StringGet, &lpCmdLine);
\r
1900 /* Propagate options that affect others */
\r
1901 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1902 if (appData.icsActive || appData.noChessProgram) {
\r
1903 chessProgram = FALSE; /* not local chess program mode */
\r
1906 /* Open startup dialog if needed */
\r
1907 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1908 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1909 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1910 *appData.secondChessProgram == NULLCHAR))) {
\r
1913 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1914 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1915 FreeProcInstance(lpProc);
\r
1918 /* Make sure save files land in the right (?) directory */
\r
1919 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1920 appData.saveGameFile = strdup(buf);
\r
1922 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1923 appData.savePositionFile = strdup(buf);
\r
1926 /* Finish initialization for fonts and sounds */
\r
1927 for (i=0; i<NUM_FONTS; i++) {
\r
1928 for (j=0; j<NUM_SIZES; j++) {
\r
1929 CreateFontInMF(font[j][i]);
\r
1932 /* xboard, and older WinBoards, controlled the move sound with the
\r
1933 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1934 always turn the option on (so that the backend will call us),
\r
1935 then let the user turn the sound off by setting it to silence if
\r
1936 desired. To accommodate old winboard.ini files saved by old
\r
1937 versions of WinBoard, we also turn off the sound if the option
\r
1938 was initially set to false. */
\r
1939 if (!appData.ringBellAfterMoves) {
\r
1940 sounds[(int)SoundMove].name = strdup("");
\r
1941 appData.ringBellAfterMoves = TRUE;
\r
1943 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1944 SetCurrentDirectory(installDir);
\r
1946 SetCurrentDirectory(currDir);
\r
1948 p = icsTextMenuString;
\r
1949 if (p[0] == '@') {
\r
1950 FILE* f = fopen(p + 1, "r");
\r
1952 DisplayFatalError(p + 1, errno, 2);
\r
1955 i = fread(buf, 1, sizeof(buf)-1, f);
\r
1957 buf[i] = NULLCHAR;
\r
1960 ParseIcsTextMenu(strdup(p));
\r
1967 HMENU hmenu = GetMenu(hwndMain);
\r
1969 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1970 MF_BYCOMMAND|((appData.icsActive &&
\r
1971 *appData.icsCommPort != NULLCHAR) ?
\r
1972 MF_ENABLED : MF_GRAYED));
\r
1973 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1974 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1975 MF_CHECKED : MF_UNCHECKED));
\r
1980 SaveSettings(char* name)
\r
1983 ArgDescriptor *ad;
\r
1984 WINDOWPLACEMENT wp;
\r
1985 char dir[MSG_SIZ];
\r
1987 if (!hwndMain) return;
\r
1989 GetCurrentDirectory(MSG_SIZ, dir);
\r
1990 SetCurrentDirectory(installDir);
\r
1991 f = fopen(name, "w");
\r
1992 SetCurrentDirectory(dir);
\r
1994 DisplayError(name, errno);
\r
1997 fprintf(f, ";\n");
\r
1998 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
1999 fprintf(f, ";\n");
\r
2000 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2001 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2002 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2003 fprintf(f, ";\n");
\r
2005 wp.length = sizeof(WINDOWPLACEMENT);
\r
2006 GetWindowPlacement(hwndMain, &wp);
\r
2007 boardX = wp.rcNormalPosition.left;
\r
2008 boardY = wp.rcNormalPosition.top;
\r
2010 if (hwndConsole) {
\r
2011 GetWindowPlacement(hwndConsole, &wp);
\r
2012 consoleX = wp.rcNormalPosition.left;
\r
2013 consoleY = wp.rcNormalPosition.top;
\r
2014 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2015 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2018 if (analysisDialog) {
\r
2019 GetWindowPlacement(analysisDialog, &wp);
\r
2020 analysisX = wp.rcNormalPosition.left;
\r
2021 analysisY = wp.rcNormalPosition.top;
\r
2022 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2023 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2026 if (commentDialog) {
\r
2027 GetWindowPlacement(commentDialog, &wp);
\r
2028 commentX = wp.rcNormalPosition.left;
\r
2029 commentY = wp.rcNormalPosition.top;
\r
2030 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2031 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2034 if (editTagsDialog) {
\r
2035 GetWindowPlacement(editTagsDialog, &wp);
\r
2036 editTagsX = wp.rcNormalPosition.left;
\r
2037 editTagsY = wp.rcNormalPosition.top;
\r
2038 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2039 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2042 if (gameListDialog) {
\r
2043 GetWindowPlacement(gameListDialog, &wp);
\r
2044 gameListX = wp.rcNormalPosition.left;
\r
2045 gameListY = wp.rcNormalPosition.top;
\r
2046 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2047 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2050 /* [AS] Move history */
2051 wpMoveHistory.visible = MoveHistoryIsUp();
2053 if( moveHistoryDialog ) {
2054 GetWindowPlacement(moveHistoryDialog, &wp);
2055 wpMoveHistory.x = wp.rcNormalPosition.left;
2056 wpMoveHistory.y = wp.rcNormalPosition.top;
2057 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
2058 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
2061 /* [AS] Eval graph */
2062 wpEvalGraph.visible = EvalGraphIsUp();
2064 if( evalGraphDialog ) {
2065 GetWindowPlacement(evalGraphDialog, &wp);
2066 wpEvalGraph.x = wp.rcNormalPosition.left;
2067 wpEvalGraph.y = wp.rcNormalPosition.top;
2068 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
2069 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
2072 /* [AS] Engine output */
2073 wpEngineOutput.visible = EngineOutputIsUp();
2075 if( engineOutputDialog ) {
2076 GetWindowPlacement(engineOutputDialog, &wp);
2077 wpEngineOutput.x = wp.rcNormalPosition.left;
2078 wpEngineOutput.y = wp.rcNormalPosition.top;
2079 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
2080 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
2083 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2084 if (!ad->save) continue;
\r
2085 switch (ad->argType) {
\r
2088 char *p = *(char **)ad->argLoc;
\r
2089 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2090 /* Quote multiline values or \-containing values
\r
2091 with { } if possible */
\r
2092 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2094 /* Else quote with " " */
\r
2095 fprintf(f, "/%s=\"", ad->argName);
\r
2097 if (*p == '\n') fprintf(f, "\n");
\r
2098 else if (*p == '\r') fprintf(f, "\\r");
\r
2099 else if (*p == '\t') fprintf(f, "\\t");
\r
2100 else if (*p == '\b') fprintf(f, "\\b");
\r
2101 else if (*p == '\f') fprintf(f, "\\f");
\r
2102 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2103 else if (*p == '\"') fprintf(f, "\\\"");
\r
2104 else if (*p == '\\') fprintf(f, "\\\\");
\r
2108 fprintf(f, "\"\n");
\r
2113 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2116 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2119 fprintf(f, "/%s=%s\n", ad->argName,
\r
2120 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2123 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2126 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2130 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2131 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2132 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2137 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2138 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2139 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2140 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2141 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2142 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2143 (ta->effects) ? " " : "",
\r
2144 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2148 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2149 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2151 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2154 case ArgBoardSize:
\r
2155 fprintf(f, "/%s=%s\n", ad->argName,
\r
2156 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2161 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2162 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2163 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2164 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2165 ad->argName, mfp->faceName, mfp->pointSize,
\r
2166 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2167 mfp->bold ? "b" : "",
\r
2168 mfp->italic ? "i" : "",
\r
2169 mfp->underline ? "u" : "",
\r
2170 mfp->strikeout ? "s" : "");
\r
2174 case ArgCommSettings:
\r
2175 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2183 /*---------------------------------------------------------------------------*\
\r
2185 * GDI board drawing routines
\r
2187 \*---------------------------------------------------------------------------*/
\r
2189 /* [AS] Draw square using background texture */
2190 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
2195 return; /* Should never happen! */
2198 SetGraphicsMode( dst, GM_ADVANCED );
2210 x.eDx = (FLOAT) dw + dx - 1;
2213 SetWorldTransform( dst, &x );
2222 x.eDy = (FLOAT) dh + dy - 1;
2224 SetWorldTransform( dst, &x );
2236 SetWorldTransform( dst, &x );
2240 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
2248 SetWorldTransform( dst, &x );
2250 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
2269 static HFONT hPieceFont = NULL;
2270 static HBITMAP hPieceMask[12];
2271 static HBITMAP hPieceFace[12];
2272 static int fontBitmapSquareSize = 0;
2273 static char pieceToFontChar[12] = { 'p', 'n', 'b', 'r', 'q', 'k', 'o', 'm', 'v', 't', 'w', 'l' };
2275 static BOOL SetPieceToFontCharTable( const char * map )
2277 BOOL result = FALSE;
2279 if( map != NULL && strlen(map) == 12 ) {
2282 for( i=0; i<12; i++ ) {
2283 pieceToFontChar[i] = map[i];
2292 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
2295 BYTE r1 = GetRValue( color );
2296 BYTE g1 = GetGValue( color );
2297 BYTE b1 = GetBValue( color );
2303 /* Create a uniform background first */
2304 hbrush = CreateSolidBrush( color );
2305 SetRect( &rc, 0, 0, squareSize, squareSize );
2306 FillRect( hdc, &rc, hbrush );
2307 DeleteObject( hbrush );
2310 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
2311 int steps = squareSize / 2;
2314 for( i=0; i<steps; i++ ) {
2315 BYTE r = r1 - (r1-r2) * i / steps;
2316 BYTE g = g1 - (g1-g2) * i / steps;
2317 BYTE b = b1 - (b1-b2) * i / steps;
2319 hbrush = CreateSolidBrush( RGB(r,g,b) );
2320 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
2321 FillRect( hdc, &rc, hbrush );
2322 DeleteObject(hbrush);
2325 else if( mode == 2 ) {
2326 /* Diagonal gradient, good more or less for every piece */
2328 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
2330 int steps = squareSize;
2333 triangle[0].x = squareSize - steps;
2334 triangle[0].y = squareSize;
2335 triangle[1].x = squareSize;
2336 triangle[1].y = squareSize;
2337 triangle[2].x = squareSize;
2338 triangle[2].y = squareSize - steps;
2340 for( i=0; i<steps; i++ ) {
2341 BYTE r = r1 - (r1-r2) * i / steps;
2342 BYTE g = g1 - (g1-g2) * i / steps;
2343 BYTE b = b1 - (b1-b2) * i / steps;
2345 hbrush = CreateSolidBrush( RGB(r,g,b) );
2346 hbrush_old = SelectObject( hdc, hbrush );
2347 Polygon( hdc, triangle, 3 );
2348 SelectObject( hdc, hbrush_old );
2349 DeleteObject(hbrush);
2354 SelectObject( hdc, hpen );
2359 [AS] The method I use to create the bitmaps it a bit tricky, but it
2360 seems to work ok. The main problem here is to find the "inside" of a chess
2361 piece: follow the steps as explained below.
2363 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
2367 COLORREF chroma = RGB(0xFF,0x00,0xFF);
2371 int backColor = whitePieceColor;
2372 int foreColor = blackPieceColor;
2373 int shapeIndex = index < 6 ? index+6 : index;
2375 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
2376 backColor = appData.fontBackColorWhite;
2377 foreColor = appData.fontForeColorWhite;
2379 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
2380 backColor = appData.fontBackColorBlack;
2381 foreColor = appData.fontForeColorBlack;
2385 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2387 hbm_old = SelectObject( hdc, hbm );
2391 rc.right = squareSize;
2392 rc.bottom = squareSize;
2394 /* Step 1: background is now black */
2395 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
2397 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
2399 pt.x = (squareSize - sz.cx) / 2;
2400 pt.y = (squareSize - sz.cy) / 2;
2402 SetBkMode( hdc, TRANSPARENT );
2403 SetTextColor( hdc, chroma );
2404 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
2405 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2407 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
2408 /* Step 3: the area outside the piece is filled with white */
2409 FloodFill( hdc, 0, 0, chroma );
2410 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
2412 Step 4: this is the tricky part, the area inside the piece is filled with black,
2413 but if the start point is not inside the piece we're lost!
2414 There should be a better way to do this... if we could create a region or path
2415 from the fill operation we would be fine for example.
2417 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
2419 SetTextColor( hdc, 0 );
2421 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
2422 draw the piece again in black for safety.
2424 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2426 SelectObject( hdc, hbm_old );
2428 if( hPieceMask[index] != NULL ) {
2429 DeleteObject( hPieceMask[index] );
2432 hPieceMask[index] = hbm;
2435 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2437 SelectObject( hdc, hbm );
2440 HDC dc1 = CreateCompatibleDC( hdc_window );
2441 HDC dc2 = CreateCompatibleDC( hdc_window );
2442 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2444 SelectObject( dc1, hPieceMask[index] );
2445 SelectObject( dc2, bm2 );
2446 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
2447 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
2450 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
2451 the piece background and deletes (makes transparent) the rest.
2452 Thanks to that mask, we are free to paint the background with the greates
2453 freedom, as we'll be able to mask off the unwanted parts when finished.
2454 We use this, to make gradients and give the pieces a "roundish" look.
2456 SetPieceBackground( hdc, backColor, 2 );
2457 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
2461 DeleteObject( bm2 );
2464 SetTextColor( hdc, foreColor );
2465 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2467 SelectObject( hdc, hbm_old );
2469 if( hPieceFace[index] != NULL ) {
2470 DeleteObject( hPieceFace[index] );
2473 hPieceFace[index] = hbm;
2476 static int TranslatePieceToFontPiece( int piece )
2508 void CreatePiecesFromFont()
2511 HDC hdc_window = NULL;
2517 if( fontBitmapSquareSize < 0 ) {
2518 /* Something went seriously wrong in the past: do not try to recreate fonts! */
2522 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
2523 fontBitmapSquareSize = -1;
2527 if( fontBitmapSquareSize != squareSize ) {
2528 hdc_window = GetDC( hwndMain );
2529 hdc = CreateCompatibleDC( hdc_window );
2531 if( hPieceFont != NULL ) {
2532 DeleteObject( hPieceFont );
2535 for( i=0; i<12; i++ ) {
2536 hPieceMask[i] = NULL;
2537 hPieceFace[i] = NULL;
2543 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
2544 fontHeight = appData.fontPieceSize;
2547 fontHeight = (fontHeight * squareSize) / 100;
2549 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
2551 lf.lfEscapement = 0;
2552 lf.lfOrientation = 0;
2553 lf.lfWeight = FW_NORMAL;
2557 lf.lfCharSet = DEFAULT_CHARSET;
2558 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
2559 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2560 lf.lfQuality = PROOF_QUALITY;
2561 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
2562 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
2563 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
2565 hPieceFont = CreateFontIndirect( &lf );
2567 if( hPieceFont == NULL ) {
2568 fontBitmapSquareSize = -2;
2571 /* Setup font-to-piece character table */
2572 if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) {
2573 /* No (or wrong) global settings, try to detect the font */
2574 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
2576 SetPieceToFontCharTable("phbrqkojntwl");
2578 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
2579 /* DiagramTT* family */
2580 SetPieceToFontCharTable("PNLRQKpnlrqk");
2583 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
2584 SetPieceToFontCharTable("pnbrqkomvtwl");
2588 /* Create bitmaps */
2589 hfont_old = SelectObject( hdc, hPieceFont );
2591 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
2592 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
2593 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
2594 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
2595 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
2596 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
2597 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
2598 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
2599 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
2600 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
2601 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
2602 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
2604 SelectObject( hdc, hfont_old );
2606 fontBitmapSquareSize = squareSize;
2614 if( hdc_window != NULL ) {
2615 ReleaseDC( hwndMain, hdc_window );
2620 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2624 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2625 if (gameInfo.event &&
\r
2626 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2627 strcmp(name, "k80s") == 0) {
\r
2628 strcpy(name, "tim");
\r
2630 return LoadBitmap(hinst, name);
\r
2634 /* Insert a color into the program's logical palette
\r
2635 structure. This code assumes the given color is
\r
2636 the result of the RGB or PALETTERGB macro, and it
\r
2637 knows how those macros work (which is documented).
\r
2640 InsertInPalette(COLORREF color)
\r
2642 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2644 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2645 DisplayFatalError("Too many colors", 0, 1);
\r
2646 pLogPal->palNumEntries--;
\r
2650 pe->peFlags = (char) 0;
\r
2651 pe->peRed = (char) (0xFF & color);
\r
2652 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2653 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2659 InitDrawingColors()
\r
2661 if (pLogPal == NULL) {
\r
2662 /* Allocate enough memory for a logical palette with
\r
2663 * PALETTESIZE entries and set the size and version fields
\r
2664 * of the logical palette structure.
\r
2666 pLogPal = (NPLOGPALETTE)
\r
2667 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2668 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2669 pLogPal->palVersion = 0x300;
\r
2671 pLogPal->palNumEntries = 0;
\r
2673 InsertInPalette(lightSquareColor);
\r
2674 InsertInPalette(darkSquareColor);
\r
2675 InsertInPalette(whitePieceColor);
\r
2676 InsertInPalette(blackPieceColor);
\r
2677 InsertInPalette(highlightSquareColor);
\r
2678 InsertInPalette(premoveHighlightColor);
\r
2680 /* create a logical color palette according the information
\r
2681 * in the LOGPALETTE structure.
\r
2683 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2685 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2686 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2687 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2688 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2689 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2691 /* [AS] Force rendering of the font-based pieces */
2692 if( fontBitmapSquareSize > 0 ) {
2693 fontBitmapSquareSize = 0;
2699 BoardWidth(int boardSize)
\r
2701 int lineGap = sizeInfo[boardSize].lineGap;
2703 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
2704 lineGap = appData.overrideLineGap;
2707 return (BOARD_SIZE + 1) * lineGap +
2708 BOARD_SIZE * sizeInfo[boardSize].squareSize;
\r
2711 /* Respond to board resize by dragging edge */
\r
2713 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2715 BoardSize newSize = NUM_SIZES - 1;
\r
2716 static int recurse = 0;
\r
2717 if (IsIconic(hwndMain)) return;
\r
2718 if (recurse > 0) return;
\r
2720 while (newSize > 0 &&
\r
2721 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2722 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2725 boardSize = newSize;
\r
2726 InitDrawingSizes(boardSize, flags);
\r
2733 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2735 int i, boardWidth;
\r
2736 ChessSquare piece;
\r
2737 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2739 SIZE clockSize, messageSize;
\r
2741 char buf[MSG_SIZ];
\r
2743 HMENU hmenu = GetMenu(hwndMain);
\r
2744 RECT crect, wrect;
\r
2746 LOGBRUSH logbrush;
\r
2748 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2749 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2750 squareSize = sizeInfo[boardSize].squareSize;
\r
2751 lineGap = sizeInfo[boardSize].lineGap;
\r
2753 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
2754 lineGap = appData.overrideLineGap;
2757 if (tinyLayout != oldTinyLayout) {
\r
2758 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2760 style &= ~WS_SYSMENU;
\r
2761 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2762 "&Minimize\tCtrl+F4");
\r
2764 style |= WS_SYSMENU;
\r
2765 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2767 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2769 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2770 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2771 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2773 DrawMenuBar(hwndMain);
\r
2776 boardWidth = BoardWidth(boardSize);
\r
2778 /* Get text area sizes */
\r
2779 hdc = GetDC(hwndMain);
\r
2780 if (appData.clockMode) {
\r
2781 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2783 sprintf(buf, "White");
\r
2785 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2786 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2787 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2788 str = "We only care about the height here";
\r
2789 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2790 SelectObject(hdc, oldFont);
\r
2791 ReleaseDC(hwndMain, hdc);
\r
2793 /* Compute where everything goes */
\r
2794 whiteRect.left = OUTER_MARGIN;
\r
2795 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2796 whiteRect.top = OUTER_MARGIN;
\r
2797 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2799 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2800 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2801 blackRect.top = whiteRect.top;
\r
2802 blackRect.bottom = whiteRect.bottom;
\r
2804 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2805 if (appData.showButtonBar) {
\r
2806 messageRect.right = blackRect.right
\r
2807 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2809 messageRect.right = blackRect.right;
\r
2811 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2812 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2814 boardRect.left = whiteRect.left;
\r
2815 boardRect.right = boardRect.left + boardWidth;
\r
2816 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2817 boardRect.bottom = boardRect.top + boardWidth;
\r
2819 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2820 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2821 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2822 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2823 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2824 GetWindowRect(hwndMain, &wrect);
\r
2825 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2826 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2827 /* compensate if menu bar wrapped */
\r
2828 GetClientRect(hwndMain, &crect);
\r
2829 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2830 winHeight += offby;
\r
2832 case WMSZ_TOPLEFT:
\r
2833 SetWindowPos(hwndMain, NULL,
\r
2834 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2835 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2838 case WMSZ_TOPRIGHT:
\r
2840 SetWindowPos(hwndMain, NULL,
\r
2841 wrect.left, wrect.bottom - winHeight,
\r
2842 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2845 case WMSZ_BOTTOMLEFT:
\r
2847 SetWindowPos(hwndMain, NULL,
\r
2848 wrect.right - winWidth, wrect.top,
\r
2849 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2852 case WMSZ_BOTTOMRIGHT:
\r
2856 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2857 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2862 for (i = 0; i < N_BUTTONS; i++) {
\r
2863 if (buttonDesc[i].hwnd != NULL) {
\r
2864 DestroyWindow(buttonDesc[i].hwnd);
\r
2865 buttonDesc[i].hwnd = NULL;
\r
2867 if (appData.showButtonBar) {
\r
2868 buttonDesc[i].hwnd =
\r
2869 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2870 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2871 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2872 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2873 (HMENU) buttonDesc[i].id,
\r
2874 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2876 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2877 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2878 MAKELPARAM(FALSE, 0));
\r
2880 if (buttonDesc[i].id == IDM_Pause)
\r
2881 hwndPause = buttonDesc[i].hwnd;
\r
2882 buttonDesc[i].wndproc = (WNDPROC)
\r
2883 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2886 if (gridPen != NULL) DeleteObject(gridPen);
\r
2887 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2888 if (premovePen != NULL) DeleteObject(premovePen);
\r
2889 if (lineGap != 0) {
\r
2890 logbrush.lbStyle = BS_SOLID;
\r
2891 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2893 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2894 lineGap, &logbrush, 0, NULL);
\r
2895 logbrush.lbColor = highlightSquareColor;
\r
2897 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2898 lineGap, &logbrush, 0, NULL);
\r
2900 logbrush.lbColor = premoveHighlightColor;
\r
2902 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2903 lineGap, &logbrush, 0, NULL);
\r
2905 for (i = 0; i < BOARD_SIZE + 1; i++) {
\r
2906 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2907 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2;
\r
2908 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2909 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2910 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2911 BOARD_SIZE * (squareSize + lineGap);
\r
2912 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x =
\r
2913 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left +
\r
2914 lineGap / 2 + (i * (squareSize + lineGap));
\r
2915 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y =
\r
2916 boardRect.top + BOARD_SIZE * (squareSize + lineGap);
\r
2917 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2921 if (boardSize == oldBoardSize) return;
\r
2922 oldBoardSize = boardSize;
\r
2923 oldTinyLayout = tinyLayout;
\r
2925 /* Load piece bitmaps for this board size */
\r
2926 for (i=0; i<=2; i++) {
\r
2927 for (piece = WhitePawn;
\r
2928 (int) piece <= (int) WhiteKing;
\r
2929 piece = (ChessSquare) ((int) piece + 1)) {
\r
2930 if (pieceBitmap[i][piece] != NULL)
\r
2931 DeleteObject(pieceBitmap[i][piece]);
\r
2935 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2936 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2937 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2938 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2939 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2940 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2941 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2942 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2943 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2944 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2945 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2946 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2947 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2948 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2949 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2950 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2951 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2952 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2957 PieceBitmap(ChessSquare p, int kind)
\r
2959 if ((int) p >= (int) BlackPawn)
\r
2960 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2962 return pieceBitmap[kind][(int) p];
\r
2965 /***************************************************************/
\r
2967 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2968 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2970 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2971 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2975 SquareToPos(int row, int column, int * x, int * y)
\r
2978 *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
2979 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2981 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2982 *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
2987 DrawCoordsOnDC(HDC hdc)
\r
2989 static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'};
\r
2990 static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'};
\r
2991 char str[2] = { NULLCHAR, NULLCHAR };
\r
2992 int oldMode, oldAlign, x, y, start, i;
\r
2996 if (!appData.showCoords)
\r
2999 start = flipView ? 0 : 8;
\r
3001 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3002 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3003 oldAlign = GetTextAlign(hdc);
\r
3004 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3006 y = boardRect.top + lineGap;
\r
3007 x = boardRect.left + lineGap;
\r
3009 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3010 for (i = 0; i < 8; i++) {
\r
3011 str[0] = files[start + i];
\r
3012 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3013 y += squareSize + lineGap;
\r
3016 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3017 for (i = 0; i < 8; i++) {
\r
3018 str[0] = ranks[start + i];
\r
3019 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3020 x += squareSize + lineGap;
\r
3023 SelectObject(hdc, oldBrush);
\r
3024 SetBkMode(hdc, oldMode);
\r
3025 SetTextAlign(hdc, oldAlign);
\r
3026 SelectObject(hdc, oldFont);
\r
3030 DrawGridOnDC(HDC hdc)
\r
3034 if (lineGap != 0) {
\r
3035 oldPen = SelectObject(hdc, gridPen);
\r
3036 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2);
\r
3037 SelectObject(hdc, oldPen);
\r
3041 #define HIGHLIGHT_PEN 0
\r
3042 #define PREMOVE_PEN 1
\r
3045 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3048 HPEN oldPen, hPen;
\r
3049 if (lineGap == 0) return;
\r
3051 x1 = boardRect.left +
\r
3052 lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap);
\r
3053 y1 = boardRect.top +
\r
3054 lineGap/2 + y * (squareSize + lineGap);
\r
3056 x1 = boardRect.left +
\r
3057 lineGap/2 + x * (squareSize + lineGap);
\r
3058 y1 = boardRect.top +
\r
3059 lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap);
\r
3061 hPen = pen ? premovePen : highlightPen;
\r
3062 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3063 MoveToEx(hdc, x1, y1, NULL);
\r
3064 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3065 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3066 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3067 LineTo(hdc, x1, y1);
\r
3068 SelectObject(hdc, oldPen);
\r
3072 DrawHighlightsOnDC(HDC hdc)
\r
3075 for (i=0; i<2; i++) {
\r
3076 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3077 DrawHighlightOnDC(hdc, TRUE,
\r
3078 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3081 for (i=0; i<2; i++) {
\r
3082 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3083 premoveHighlightInfo.sq[i].y >= 0) {
\r
3084 DrawHighlightOnDC(hdc, TRUE,
\r
3085 premoveHighlightInfo.sq[i].x,
\r
3086 premoveHighlightInfo.sq[i].y,
\r
3092 /* Note: sqcolor is used only in monoMode */
\r
3093 /* Note that this code is largely duplicated in woptions.c,
\r
3094 function DrawSampleSquare, so that needs to be updated too */
\r
3096 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3098 HBITMAP oldBitmap;
\r
3101 if (appData.blindfold) return;
\r
3103 /* [AS] Use font-based pieces if needed */
3104 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
3105 /* Create piece bitmaps, or do nothing if piece set is up to date */
3106 CreatePiecesFromFont();
3108 if( fontBitmapSquareSize == squareSize ) {
3109 int index = TranslatePieceToFontPiece( piece );
3111 SelectObject( tmphdc, hPieceMask[ index ] );
3115 squareSize, squareSize,
3120 SelectObject( tmphdc, hPieceFace[ index ] );
3124 squareSize, squareSize,
3133 if (appData.monoMode) {
\r
3134 SelectObject(tmphdc, PieceBitmap(piece,
\r
3135 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3136 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3137 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3140 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3141 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3142 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3144 /* Use black piece color for outline of white pieces */
\r
3145 /* Not sure this looks really good (though xboard does it).
\r
3146 Maybe better to have another selectable color, default black */
\r
3147 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3148 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3149 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3151 /* Use black for outline of white pieces */
\r
3152 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3153 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
3157 /* Use white piece color for details of black pieces */
\r
3158 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3159 WHITE_PIECE ones aren't always the right shape. */
\r
3160 /* Not sure this looks really good (though xboard does it).
\r
3161 Maybe better to have another selectable color, default medium gray? */
\r
3162 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3163 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3164 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3165 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3166 SelectObject(hdc, blackPieceBrush);
\r
3167 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3169 /* Use square color for details of black pieces */
\r
3170 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3171 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3172 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3175 SelectObject(hdc, oldBrush);
\r
3176 SelectObject(tmphdc, oldBitmap);
\r
3180 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
3181 int GetBackTextureMode( int algo )
3183 int result = BACK_TEXTURE_MODE_DISABLED;
3187 case BACK_TEXTURE_MODE_PLAIN:
3188 result = 1; /* Always use identity map */
3190 case BACK_TEXTURE_MODE_FULL_RANDOM:
3191 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
3199 [AS] Compute and save texture drawing info, otherwise we may not be able
3200 to handle redraws cleanly (as random numbers would always be different).
3202 VOID RebuildTextureSquareInfo()
3212 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
3214 if( liteBackTexture != NULL ) {
3215 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
3216 lite_w = bi.bmWidth;
3217 lite_h = bi.bmHeight;
3221 if( darkBackTexture != NULL ) {
3222 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
3223 dark_w = bi.bmWidth;
3224 dark_h = bi.bmHeight;
3228 for( row=0; row<BOARD_SIZE; row++ ) {
3229 for( col=0; col<BOARD_SIZE; col++ ) {
3230 if( (col + row) & 1 ) {
3232 if( lite_w >= squareSize && lite_h >= squareSize ) {
3233 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_SIZE;
3234 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_SIZE;
3235 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
3240 if( dark_w >= squareSize && dark_h >= squareSize ) {
3241 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_SIZE;
3242 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_SIZE;
3243 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
3250 /* [AS] Arrow highlighting support */
3252 static int A_WIDTH = 5; /* Width of arrow body */
3254 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
3255 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
3257 static double Sqr( double x )
3262 static int Round( double x )
3264 return (int) (x + 0.5);
3267 /* Draw an arrow between two points using current settings */
3268 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
3271 double dx, dy, j, k, x, y;
3274 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
3276 arrow[0].x = s_x + A_WIDTH;
3279 arrow[1].x = s_x + A_WIDTH;
3280 arrow[1].y = d_y - h;
3282 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
3283 arrow[2].y = d_y - h;
3288 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
3289 arrow[4].y = d_y - h;
3291 arrow[5].x = s_x - A_WIDTH;
3292 arrow[5].y = d_y - h;
3294 arrow[6].x = s_x - A_WIDTH;
3297 else if( d_y == s_y ) {
3298 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
3301 arrow[0].y = s_y + A_WIDTH;
3303 arrow[1].x = d_x - w;
3304 arrow[1].y = s_y + A_WIDTH;
3306 arrow[2].x = d_x - w;
3307 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
3312 arrow[4].x = d_x - w;
3313 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
3315 arrow[5].x = d_x - w;
3316 arrow[5].y = s_y - A_WIDTH;
3319 arrow[6].y = s_y - A_WIDTH;
3322 /* [AS] Needed a lot of paper for this! :-) */
3323 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
3324 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
3326 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
3328 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
3333 arrow[0].x = Round(x - j);
3334 arrow[0].y = Round(y + j*dx);
3336 arrow[1].x = Round(x + j);
3337 arrow[1].y = Round(y - j*dx);
3340 x = (double) d_x - k;
3341 y = (double) d_y - k*dy;
3344 x = (double) d_x + k;
3345 y = (double) d_y + k*dy;
3348 arrow[2].x = Round(x + j);
3349 arrow[2].y = Round(y - j*dx);
3351 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
3352 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
3357 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
3358 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
3360 arrow[6].x = Round(x - j);
3361 arrow[6].y = Round(y + j*dx);
3364 Polygon( hdc, arrow, 7 );
3367 /* [AS] Draw an arrow between two squares */
3368 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
3370 int s_x, s_y, d_x, d_y;
3377 if( s_col == d_col && s_row == d_row ) {
3381 /* Get source and destination points */
3382 SquareToPos( s_row, s_col, &s_x, &s_y);
3383 SquareToPos( d_row, d_col, &d_x, &d_y);
3386 d_y += squareSize / 4;
3388 else if( d_y < s_y ) {
3389 d_y += 3 * squareSize / 4;
3392 d_y += squareSize / 2;
3396 d_x += squareSize / 4;
3398 else if( d_x < s_x ) {
3399 d_x += 3 * squareSize / 4;
3402 d_x += squareSize / 2;
3405 s_x += squareSize / 2;
3406 s_y += squareSize / 2;
3409 A_WIDTH = squareSize / 14;
3412 stLB.lbStyle = BS_SOLID;
3413 stLB.lbColor = appData.highlightArrowColor;
3416 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
3417 holdpen = SelectObject( hdc, hpen );
3418 hbrush = CreateBrushIndirect( &stLB );
3419 holdbrush = SelectObject( hdc, hbrush );
3421 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
3423 SelectObject( hdc, holdpen );
3424 SelectObject( hdc, holdbrush );
3425 DeleteObject( hpen );
3426 DeleteObject( hbrush );
3429 BOOL HasHighlightInfo()
3431 BOOL result = FALSE;
3433 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
3434 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
3442 BOOL IsDrawArrowEnabled()
3444 BOOL result = FALSE;
3446 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
3453 VOID DrawArrowHighlight( HDC hdc )
3455 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
3456 DrawArrowBetweenSquares( hdc,
3457 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
3458 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
3462 HRGN GetArrowHighlightClipRegion( HDC hdc )
3466 if( HasHighlightInfo() ) {
3470 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
3471 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
3475 dx = MAX( x1, x2 ) + squareSize;
3476 dy = MAX( y1, y2 ) + squareSize;
3478 result = CreateRectRgn( sx, sy, dx, dy );
3485 Warning: this function modifies the behavior of several other functions.
3487 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
3488 needed. Unfortunately, the decision whether or not to perform a full or partial
3489 repaint is scattered all over the place, which is not good for features such as
3490 "arrow highlighting" that require a full repaint of the board.
3492 So, I've tried to patch the code where I thought it made sense (e.g. after or during
3493 user interaction, when speed is not so important) but especially to avoid errors
3494 in the displayed graphics.
3496 In such patched places, I always try refer to this function so there is a single
3497 place to maintain knowledge.
3499 To restore the original behavior, just return FALSE unconditionally.
3501 BOOL IsFullRepaintPreferrable()
3503 BOOL result = FALSE;
3505 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
3506 /* Arrow may appear on the board */
3514 This function is called by DrawPosition to know whether a full repaint must
3517 Only DrawPosition may directly call this function, which makes use of
3518 some state information. Other function should call DrawPosition specifying
3519 the repaint flag, and can use IsFullRepaintPreferrable if needed.
3521 BOOL DrawPositionNeedsFullRepaint()
3523 BOOL result = FALSE;
3526 Probably a slightly better policy would be to trigger a full repaint
3527 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
3528 but animation is fast enough that it's difficult to notice.
3530 if( animInfo.piece == EmptySquare ) {
3531 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
3540 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3542 int row, column, x, y, square_color, piece_color;
\r
3543 ChessSquare piece;
\r
3545 HDC texture_hdc = NULL;
3547 /* [AS] Initialize background textures if needed */
3548 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
3549 if( backTextureSquareSize != squareSize ) {
3550 backTextureSquareSize = squareSize;
3551 RebuildTextureSquareInfo();
3554 texture_hdc = CreateCompatibleDC( hdc );
3557 for (row = 0; row < BOARD_SIZE; row++) {
\r
3558 for (column = 0; column < BOARD_SIZE; column++) {
\r
3560 SquareToPos(row, column, &x, &y);
\r
3562 piece = board[row][column];
\r
3564 square_color = ((column + row) % 2) == 1;
\r
3565 piece_color = (int) piece < (int) BlackPawn;
\r
3567 if (appData.monoMode) {
\r
3568 if (piece == EmptySquare) {
\r
3569 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3570 square_color ? WHITENESS : BLACKNESS);
\r
3572 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3575 else if( backTextureSquareInfo[row][column].mode > 0 ) {
3576 /* [AS] Draw the square using a texture bitmap */
3577 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
3580 squareSize, squareSize,
3583 backTextureSquareInfo[row][column].mode,
3584 backTextureSquareInfo[row][column].x,
3585 backTextureSquareInfo[row][column].y );
3587 SelectObject( texture_hdc, hbm );
3589 if (piece != EmptySquare) {
3590 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
3594 oldBrush = SelectObject(hdc, square_color ?
\r
3595 lightSquareBrush : darkSquareBrush);
\r
3596 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3597 SelectObject(hdc, oldBrush);
\r
3598 if (piece != EmptySquare)
\r
3599 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3604 if( texture_hdc != NULL ) {
3605 DeleteDC( texture_hdc );
3609 #define MAX_CLIPS 200 /* more than enough */
\r
3612 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3614 static Board lastReq, lastDrawn;
\r
3615 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3616 static int lastDrawnFlipView = 0;
\r
3617 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3618 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3621 HBITMAP bufferBitmap;
\r
3622 HBITMAP oldBitmap;
\r
3624 HRGN clips[MAX_CLIPS];
\r
3625 ChessSquare dragged_piece = EmptySquare;
\r
3627 /* I'm undecided on this - this function figures out whether a full
\r
3628 * repaint is necessary on its own, so there's no real reason to have the
\r
3629 * caller tell it that. I think this can safely be set to FALSE - but
\r
3630 * if we trust the callers not to request full repaints unnessesarily, then
\r
3631 * we could skip some clipping work. In other words, only request a full
\r
3632 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3633 * gamestart and similar) --Hawk
\r
3635 Boolean fullrepaint = repaint;
\r
3637 if( DrawPositionNeedsFullRepaint() ) {
3643 static int repaint_count = 0;
3647 sprintf( buf, "FULL repaint: %d\n", repaint_count );
3648 OutputDebugString( buf );
3652 if (board == NULL) {
\r
3653 if (!lastReqValid) {
\r
3658 CopyBoard(lastReq, board);
\r
3662 if (doingSizing) {
\r
3666 if (IsIconic(hwndMain)) {
\r
3670 if (hdc == NULL) {
\r
3671 hdc = GetDC(hwndMain);
\r
3672 if (!appData.monoMode) {
\r
3673 SelectPalette(hdc, hPal, FALSE);
\r
3674 RealizePalette(hdc);
\r
3678 releaseDC = FALSE;
\r
3682 fprintf(debugFP, "*******************************\n"
\r
3684 "dragInfo.from (%d,%d)\n"
\r
3685 "dragInfo.start (%d,%d)\n"
\r
3686 "dragInfo.pos (%d,%d)\n"
\r
3687 "dragInfo.lastpos (%d,%d)\n",
\r
3688 repaint ? "TRUE" : "FALSE",
\r
3689 dragInfo.from.x, dragInfo.from.y,
\r
3690 dragInfo.start.x, dragInfo.start.y,
\r
3691 dragInfo.pos.x, dragInfo.pos.y,
\r
3692 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
3693 fprintf(debugFP, "prev: ");
\r
3694 for (row = 0; row < 8; row++) {
\r
3695 for (column = 0; column < 8; column++) {
\r
3696 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
3699 fprintf(debugFP, "\n");
\r
3700 fprintf(debugFP, "board: ");
\r
3701 for (row = 0; row < 8; row++) {
\r
3702 for (column = 0; column < 8; column++) {
\r
3703 fprintf(debugFP, "%d ", board[row][column]);
\r
3706 fprintf(debugFP, "\n");
\r
3710 /* Create some work-DCs */
\r
3711 hdcmem = CreateCompatibleDC(hdc);
\r
3712 tmphdc = CreateCompatibleDC(hdc);
\r
3714 /* Figure out which squares need updating by comparing the
\r
3715 * newest board with the last drawn board and checking if
\r
3716 * flipping has changed.
\r
3718 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3719 for (row = 0; row < 8; row++) {
\r
3720 for (column = 0; column < 8; column++) {
\r
3721 if (lastDrawn[row][column] != board[row][column]) {
\r
3722 SquareToPos(row, column, &x, &y);
\r
3723 clips[num_clips++] =
\r
3724 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3728 for (i=0; i<2; i++) {
\r
3729 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3730 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3731 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3732 lastDrawnHighlight.sq[i].y >= 0) {
\r
3733 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3734 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3735 clips[num_clips++] =
\r
3736 CreateRectRgn(x - lineGap, y - lineGap,
\r
3737 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3739 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3740 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3741 clips[num_clips++] =
\r
3742 CreateRectRgn(x - lineGap, y - lineGap,
\r
3743 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3747 for (i=0; i<2; i++) {
\r
3748 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3749 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3750 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3751 lastDrawnPremove.sq[i].y >= 0) {
\r
3752 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3753 lastDrawnPremove.sq[i].x, &x, &y);
\r
3754 clips[num_clips++] =
\r
3755 CreateRectRgn(x - lineGap, y - lineGap,
\r
3756 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3758 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3759 premoveHighlightInfo.sq[i].y >= 0) {
\r
3760 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3761 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3762 clips[num_clips++] =
\r
3763 CreateRectRgn(x - lineGap, y - lineGap,
\r
3764 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3769 fullrepaint = TRUE;
\r
3772 /* Create a buffer bitmap - this is the actual bitmap
\r
3773 * being written to. When all the work is done, we can
\r
3774 * copy it to the real DC (the screen). This avoids
\r
3775 * the problems with flickering.
\r
3777 GetClientRect(hwndMain, &Rect);
\r
3778 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3779 Rect.bottom-Rect.top+1);
\r
3780 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3781 if (!appData.monoMode) {
\r
3782 SelectPalette(hdcmem, hPal, FALSE);
\r
3785 /* Create clips for dragging */
\r
3786 if (!fullrepaint) {
\r
3787 if (dragInfo.from.x >= 0) {
\r
3788 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3789 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3791 if (dragInfo.start.x >= 0) {
\r
3792 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3793 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3795 if (dragInfo.pos.x >= 0) {
\r
3796 x = dragInfo.pos.x - squareSize / 2;
\r
3797 y = dragInfo.pos.y - squareSize / 2;
\r
3798 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3800 if (dragInfo.lastpos.x >= 0) {
\r
3801 x = dragInfo.lastpos.x - squareSize / 2;
\r
3802 y = dragInfo.lastpos.y - squareSize / 2;
\r
3803 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3807 /* If dragging is in progress, we temporarely remove the piece */
\r
3808 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3809 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3810 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3813 /* Are we animating a move?
\r
3815 * - remove the piece from the board (temporarely)
\r
3816 * - calculate the clipping region
\r
3818 if (!fullrepaint) {
\r
3819 if (animInfo.piece != EmptySquare) {
\r
3820 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3821 x = boardRect.left + animInfo.lastpos.x;
\r
3822 y = boardRect.top + animInfo.lastpos.y;
\r
3823 x2 = boardRect.left + animInfo.pos.x;
\r
3824 y2 = boardRect.top + animInfo.pos.y;
\r
3825 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3826 /* Slight kludge. The real problem is that after AnimateMove is
\r
3827 done, the position on the screen does not match lastDrawn.
\r
3828 This currently causes trouble only on e.p. captures in
\r
3829 atomic, where the piece moves to an empty square and then
\r
3830 explodes. The old and new positions both had an empty square
\r
3831 at the destination, but animation has drawn a piece there and
\r
3832 we have to remember to erase it. */
\r
3833 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3837 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3838 if (num_clips == 0)
\r
3839 fullrepaint = TRUE;
\r
3841 /* Set clipping on the memory DC */
\r
3842 if (!fullrepaint) {
\r
3843 SelectClipRgn(hdcmem, clips[0]);
\r
3844 for (x = 1; x < num_clips; x++) {
\r
3845 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3846 abort(); // this should never ever happen!
\r
3850 /* Do all the drawing to the memory DC */
\r
3851 DrawGridOnDC(hdcmem);
\r
3852 DrawHighlightsOnDC(hdcmem);
\r
3853 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3855 if( appData.highlightMoveWithArrow ) {
3856 DrawArrowHighlight(hdcmem);
3859 DrawCoordsOnDC(hdcmem);
\r
3861 /* Put the dragged piece back into place and draw it */
\r
3862 if (dragged_piece != EmptySquare) {
\r
3863 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3864 x = dragInfo.pos.x - squareSize / 2;
\r
3865 y = dragInfo.pos.y - squareSize / 2;
\r
3866 DrawPieceOnDC(hdcmem, dragged_piece,
\r
3867 ((int) dragged_piece < (int) BlackPawn),
\r
3868 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3871 /* Put the animated piece back into place and draw it */
\r
3872 if (animInfo.piece != EmptySquare) {
\r
3873 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3874 x = boardRect.left + animInfo.pos.x;
\r
3875 y = boardRect.top + animInfo.pos.y;
\r
3876 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3877 ((int) animInfo.piece < (int) BlackPawn),
\r
3878 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3881 /* Release the bufferBitmap by selecting in the old bitmap
\r
3882 * and delete the memory DC
\r
3884 SelectObject(hdcmem, oldBitmap);
\r
3887 /* Set clipping on the target DC */
\r
3888 if (!fullrepaint) {
\r
3889 SelectClipRgn(hdc, clips[0]);
\r
3890 for (x = 1; x < num_clips; x++) {
\r
3891 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3892 abort(); // this should never ever happen!
\r
3896 /* Copy the new bitmap onto the screen in one go.
\r
3897 * This way we avoid any flickering
\r
3899 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3900 BitBlt(hdc, boardRect.left, boardRect.top,
\r
3901 boardRect.right - boardRect.left,
\r
3902 boardRect.bottom - boardRect.top,
\r
3903 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3904 SelectObject(tmphdc, oldBitmap);
\r
3906 /* Massive cleanup */
\r
3907 for (x = 0; x < num_clips; x++)
\r
3908 DeleteObject(clips[x]);
\r
3911 DeleteObject(bufferBitmap);
\r
3914 ReleaseDC(hwndMain, hdc);
\r
3916 if (lastDrawnFlipView != flipView) {
\r
3918 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
3920 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
3923 CopyBoard(lastDrawn, board);
\r
3924 lastDrawnHighlight = highlightInfo;
\r
3925 lastDrawnPremove = premoveHighlightInfo;
\r
3926 lastDrawnFlipView = flipView;
\r
3927 lastDrawnValid = 1;
\r
3931 /*---------------------------------------------------------------------------*\
\r
3932 | CLIENT PAINT PROCEDURE
\r
3933 | This is the main event-handler for the WM_PAINT message.
\r
3935 \*---------------------------------------------------------------------------*/
\r
3937 PaintProc(HWND hwnd)
\r
3943 if(hdc = BeginPaint(hwnd, &ps)) {
\r
3944 if (IsIconic(hwnd)) {
\r
3945 DrawIcon(hdc, 2, 2, iconCurrent);
\r
3947 if (!appData.monoMode) {
\r
3948 SelectPalette(hdc, hPal, FALSE);
\r
3949 RealizePalette(hdc);
\r
3951 HDCDrawPosition(hdc, 1, NULL);
\r
3953 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3954 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
3955 ETO_CLIPPED|ETO_OPAQUE,
\r
3956 &messageRect, messageText, strlen(messageText), NULL);
\r
3957 SelectObject(hdc, oldFont);
\r
3958 DisplayBothClocks();
\r
3960 EndPaint(hwnd,&ps);
\r
3968 * If the user selects on a border boundary, return -1; if off the board,
\r
3969 * return -2. Otherwise map the event coordinate to the square.
\r
3970 * The offset boardRect.left or boardRect.top must already have been
\r
3971 * subtracted from x.
\r
3974 EventToSquare(int x)
\r
3981 if ((x % (squareSize + lineGap)) >= squareSize)
\r
3983 x /= (squareSize + lineGap);
\r
3984 if (x >= BOARD_SIZE)
\r
3995 DropEnable dropEnables[] = {
\r
3996 { 'P', DP_Pawn, "Pawn" },
\r
3997 { 'N', DP_Knight, "Knight" },
\r
3998 { 'B', DP_Bishop, "Bishop" },
\r
3999 { 'R', DP_Rook, "Rook" },
\r
4000 { 'Q', DP_Queen, "Queen" },
\r
4004 SetupDropMenu(HMENU hmenu)
\r
4006 int i, count, enable;
\r
4008 extern char white_holding[], black_holding[];
\r
4009 char item[MSG_SIZ];
\r
4011 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4012 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4013 dropEnables[i].piece);
\r
4015 while (p && *p++ == dropEnables[i].piece) count++;
\r
4016 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4017 enable = count > 0 || !appData.testLegality
\r
4018 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4019 && !appData.icsActive);
\r
4020 ModifyMenu(hmenu, dropEnables[i].command,
\r
4021 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4022 dropEnables[i].command, item);
\r
4026 static int fromX = -1, fromY = -1, toX, toY;
\r
4028 /* Event handler for mouse messages */
\r
4030 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4034 static int recursive = 0;
\r
4036 BOOLEAN needsRedraw = FALSE;
4037 BOOLEAN saveAnimate;
\r
4038 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
4039 static BOOLEAN sameAgain = FALSE;
\r
4042 if (message == WM_MBUTTONUP) {
\r
4043 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4044 to the middle button: we simulate pressing the left button too!
\r
4046 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4047 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4053 pt.x = LOWORD(lParam);
\r
4054 pt.y = HIWORD(lParam);
\r
4055 x = EventToSquare(pt.x - boardRect.left);
\r
4056 y = EventToSquare(pt.y - boardRect.top);
\r
4057 if (!flipView && y >= 0) {
\r
4058 y = BOARD_SIZE - 1 - y;
\r
4060 if (flipView && x >= 0) {
\r
4061 x = BOARD_SIZE - 1 - x;
\r
4064 switch (message) {
\r
4065 case WM_LBUTTONDOWN:
\r
4067 sameAgain = FALSE;
\r
4069 /* Downclick vertically off board; check if on clock */
\r
4070 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4071 if (gameMode == EditPosition) {
\r
4072 SetWhiteToPlayEvent();
\r
4073 } else if (gameMode == IcsPlayingBlack ||
\r
4074 gameMode == MachinePlaysWhite) {
\r
4077 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4078 if (gameMode == EditPosition) {
\r
4079 SetBlackToPlayEvent();
\r
4080 } else if (gameMode == IcsPlayingWhite ||
\r
4081 gameMode == MachinePlaysBlack) {
\r
4085 if (!appData.highlightLastMove) {
\r
4086 ClearHighlights();
\r
4087 DrawPosition(forceFullRepaint || FALSE, NULL);
4089 fromX = fromY = -1;
\r
4090 dragInfo.start.x = dragInfo.start.y = -1;
\r
4091 dragInfo.from = dragInfo.start;
\r
4093 } else if (x < 0 || y < 0) {
\r
4095 } else if (fromX == x && fromY == y) {
\r
4096 /* Downclick on same square again */
\r
4097 ClearHighlights();
\r
4098 DrawPosition(forceFullRepaint || FALSE, NULL);
4099 sameAgain = TRUE;
\r
4100 } else if (fromX != -1) {
\r
4101 /* Downclick on different square */
\r
4102 ChessSquare pdown, pup;
\r
4103 pdown = boards[currentMove][fromY][fromX];
\r
4104 pup = boards[currentMove][y][x];
\r
4105 if (gameMode == EditPosition ||
\r
4106 !((WhitePawn <= pdown && pdown <= WhiteKing &&
\r
4107 WhitePawn <= pup && pup <= WhiteKing) ||
\r
4108 (BlackPawn <= pdown && pdown <= BlackKing &&
\r
4109 BlackPawn <= pup && pup <= BlackKing))) {
\r
4110 /* EditPosition, empty square, or different color piece;
\r
4111 click-click move is possible */
\r
4114 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
4115 if (appData.alwaysPromoteToQueen) {
\r
4116 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
4117 if (!appData.highlightLastMove) {
\r
4118 ClearHighlights();
\r
4119 DrawPosition(forceFullRepaint || FALSE, NULL);
4122 SetHighlights(fromX, fromY, toX, toY);
\r
4123 DrawPosition(forceFullRepaint || FALSE, NULL);
4124 PromotionPopup(hwnd);
\r
4126 } else { /* not a promotion */
\r
4127 if (appData.animate || appData.highlightLastMove) {
\r
4128 SetHighlights(fromX, fromY, toX, toY);
\r
4130 ClearHighlights();
\r
4132 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
4133 if (appData.animate && !appData.highlightLastMove) {
\r
4134 ClearHighlights();
\r
4135 DrawPosition(forceFullRepaint || FALSE, NULL);
4138 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4139 fromX = fromY = -1;
\r
4142 ClearHighlights();
\r
4143 DrawPosition(forceFullRepaint || FALSE, NULL);
4145 /* First downclick, or restart on a square with same color piece */
\r
4146 if (!frozen && OKToStartUserMove(x, y)) {
\r
4149 dragInfo.lastpos = pt;
\r
4150 dragInfo.from.x = fromX;
\r
4151 dragInfo.from.y = fromY;
\r
4152 dragInfo.start = dragInfo.from;
\r
4153 SetCapture(hwndMain);
\r
4155 fromX = fromY = -1;
\r
4156 dragInfo.start.x = dragInfo.start.y = -1;
\r
4157 dragInfo.from = dragInfo.start;
\r
4158 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
4162 case WM_LBUTTONUP:
\r
4164 if (fromX == -1) break;
\r
4165 if (x == fromX && y == fromY) {
\r
4166 dragInfo.from.x = dragInfo.from.y = -1;
\r
4167 /* Upclick on same square */
\r
4169 /* Clicked same square twice: abort click-click move */
\r
4170 fromX = fromY = -1;
\r
4172 ClearPremoveHighlights();
\r
4174 /* First square clicked: start click-click move */
\r
4175 SetHighlights(fromX, fromY, -1, -1);
\r
4177 DrawPosition(forceFullRepaint || FALSE, NULL);
4178 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4179 /* Errant click; ignore */
\r
4182 /* Finish drag move */
\r
4183 dragInfo.from.x = dragInfo.from.y = -1;
\r
4186 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4187 appData.animate = appData.animate && !appData.animateDragging;
\r
4188 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
4189 if (appData.alwaysPromoteToQueen) {
\r
4190 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
4192 DrawPosition(forceFullRepaint || FALSE, NULL);
4193 PromotionPopup(hwnd);
\r
4196 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
4198 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4199 appData.animate = saveAnimate;
\r
4200 fromX = fromY = -1;
\r
4201 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
4202 ClearHighlights();
\r
4204 if (appData.animate || appData.animateDragging ||
\r
4205 appData.highlightDragging || gotPremove) {
\r
4206 DrawPosition(forceFullRepaint || FALSE, NULL);
4209 dragInfo.start.x = dragInfo.start.y = -1;
\r
4210 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4213 case WM_MOUSEMOVE:
\r
4214 if ((appData.animateDragging || appData.highlightDragging)
\r
4215 && (wParam & MK_LBUTTON)
\r
4216 && dragInfo.from.x >= 0)
4218 BOOL full_repaint = FALSE;
4220 if (appData.animateDragging) {
\r
4221 dragInfo.pos = pt;
\r
4223 if (appData.highlightDragging) {
\r
4224 SetHighlights(fromX, fromY, x, y);
\r
4225 if( IsDrawArrowEnabled() && (x < 0 || x > 7 || y < 0 || y > y) ) {
4226 full_repaint = TRUE;
4230 DrawPosition( full_repaint, NULL);
4232 dragInfo.lastpos = dragInfo.pos;
\r
4236 case WM_MBUTTONDOWN:
\r
4237 case WM_RBUTTONDOWN:
\r
4240 fromX = fromY = -1;
\r
4241 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4242 dragInfo.start.x = dragInfo.start.y = -1;
\r
4243 dragInfo.from = dragInfo.start;
\r
4244 dragInfo.lastpos = dragInfo.pos;
\r
4245 if (appData.highlightDragging) {
\r
4246 ClearHighlights();
\r
4248 DrawPosition(TRUE, NULL);
\r
4250 switch (gameMode) {
\r
4251 case EditPosition:
\r
4252 case IcsExamining:
\r
4253 if (x < 0 || y < 0) break;
\r
4256 if (message == WM_MBUTTONDOWN) {
\r
4257 buttonCount = 3; /* even if system didn't think so */
\r
4258 if (wParam & MK_SHIFT)
\r
4259 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4261 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4262 } else { /* message == WM_RBUTTONDOWN */
\r
4264 if (buttonCount == 3) {
\r
4265 if (wParam & MK_SHIFT)
\r
4266 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4268 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4270 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4273 /* Just have one menu, on the right button. Windows users don't
\r
4274 think to try the middle one, and sometimes other software steals
\r
4275 it, or it doesn't really exist. */
\r
4276 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4280 case IcsPlayingWhite:
\r
4281 case IcsPlayingBlack:
\r
4283 case MachinePlaysWhite:
\r
4284 case MachinePlaysBlack:
\r
4285 if (appData.testLegality &&
\r
4286 gameInfo.variant != VariantBughouse &&
\r
4287 gameInfo.variant != VariantCrazyhouse) break;
\r
4288 if (x < 0 || y < 0) break;
\r
4291 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4292 SetupDropMenu(hmenu);
\r
4293 MenuPopup(hwnd, pt, hmenu, -1);
\r
4304 /* Preprocess messages for buttons in main window */
\r
4306 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4308 int id = GetWindowLong(hwnd, GWL_ID);
\r
4311 for (i=0; i<N_BUTTONS; i++) {
\r
4312 if (buttonDesc[i].id == id) break;
\r
4314 if (i == N_BUTTONS) return 0;
\r
4315 switch (message) {
\r
4320 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4321 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4328 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4331 if (appData.icsActive) {
\r
4332 if (GetKeyState(VK_SHIFT) < 0) {
\r
4334 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4335 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4339 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4340 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4347 if (appData.icsActive) {
\r
4348 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4349 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4351 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4353 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4354 PopUpMoveDialog((char)wParam);
\r
4360 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4363 /* Process messages for Promotion dialog box */
\r
4365 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4369 switch (message) {
\r
4370 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4371 /* Center the dialog over the application window */
\r
4372 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4373 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4374 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4375 gameInfo.variant == VariantGiveaway) ?
\r
4376 SW_SHOW : SW_HIDE);
\r
4379 case WM_COMMAND: /* message: received a command */
\r
4380 switch (LOWORD(wParam)) {
\r
4382 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4383 ClearHighlights();
\r
4384 DrawPosition(FALSE, NULL);
\r
4404 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4405 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4406 if (!appData.highlightLastMove) {
\r
4407 ClearHighlights();
\r
4408 DrawPosition(FALSE, NULL);
\r
4415 /* Pop up promotion dialog */
\r
4417 PromotionPopup(HWND hwnd)
\r
4421 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4422 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4423 hwnd, (DLGPROC)lpProc);
\r
4424 FreeProcInstance(lpProc);
\r
4427 /* Toggle ShowThinking */
\r
4429 ToggleShowThinking()
\r
4431 ShowThinkingEvent(!appData.showThinking);
\r
4435 LoadGameDialog(HWND hwnd, char* title)
\r
4439 char fileTitle[MSG_SIZ];
\r
4440 f = OpenFileDialog(hwnd, FALSE, "",
\r
4441 appData.oldSaveStyle ? "gam" : "pgn",
\r
4443 title, &number, fileTitle, NULL);
\r
4445 cmailMsgLoaded = FALSE;
\r
4446 if (number == 0) {
\r
4447 int error = GameListBuild(f);
\r
4449 DisplayError("Cannot build game list", error);
\r
4450 } else if (!ListEmpty(&gameList) &&
\r
4451 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4452 GameListPopUp(f, fileTitle);
\r
4455 GameListDestroy();
\r
4458 LoadGame(f, number, fileTitle, FALSE);
\r
4463 ChangedConsoleFont()
\r
4466 CHARRANGE tmpsel, sel;
\r
4467 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4468 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4469 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4472 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4473 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4474 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4475 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4476 * size. This was undocumented in the version of MSVC++ that I had
\r
4477 * when I wrote the code, but is apparently documented now.
\r
4479 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4480 cfmt.bCharSet = f->lf.lfCharSet;
\r
4481 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4482 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4483 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4484 /* Why are the following seemingly needed too? */
\r
4485 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4486 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4487 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4489 tmpsel.cpMax = -1; /*999999?*/
\r
4490 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4491 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4492 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4493 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4495 paraf.cbSize = sizeof(paraf);
\r
4496 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4497 paraf.dxStartIndent = 0;
\r
4498 paraf.dxOffset = WRAP_INDENT;
\r
4499 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4500 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4503 /*---------------------------------------------------------------------------*\
\r
4505 * Window Proc for main window
\r
4507 \*---------------------------------------------------------------------------*/
\r
4509 /* Process messages for main window, etc. */
\r
4511 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4514 int wmId, wmEvent;
\r
4518 char fileTitle[MSG_SIZ];
\r
4521 switch (message) {
\r
4523 case WM_PAINT: /* message: repaint portion of window */
\r
4527 case WM_ERASEBKGND:
\r
4528 if (IsIconic(hwnd)) {
\r
4529 /* Cheat; change the message */
\r
4530 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4532 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4536 case WM_LBUTTONDOWN:
\r
4537 case WM_MBUTTONDOWN:
\r
4538 case WM_RBUTTONDOWN:
\r
4539 case WM_LBUTTONUP:
\r
4540 case WM_MBUTTONUP:
\r
4541 case WM_RBUTTONUP:
\r
4542 case WM_MOUSEMOVE:
\r
4543 MouseEvent(hwnd, message, wParam, lParam);
\r
4548 if (appData.icsActive) {
\r
4549 if (wParam == '\t') {
\r
4550 if (GetKeyState(VK_SHIFT) < 0) {
\r
4552 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4553 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4557 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4558 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4562 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4563 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4565 SendMessage(h, message, wParam, lParam);
\r
4567 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4568 PopUpMoveDialog((char)wParam);
\r
4572 case WM_PALETTECHANGED:
\r
4573 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4575 HDC hdc = GetDC(hwndMain);
\r
4576 SelectPalette(hdc, hPal, TRUE);
\r
4577 nnew = RealizePalette(hdc);
\r
4579 paletteChanged = TRUE;
\r
4581 UpdateColors(hdc);
\r
4583 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
4586 ReleaseDC(hwnd, hdc);
\r
4590 case WM_QUERYNEWPALETTE:
\r
4591 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4593 HDC hdc = GetDC(hwndMain);
\r
4594 paletteChanged = FALSE;
\r
4595 SelectPalette(hdc, hPal, FALSE);
\r
4596 nnew = RealizePalette(hdc);
\r
4598 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4600 ReleaseDC(hwnd, hdc);
\r
4605 case WM_COMMAND: /* message: command from application menu */
\r
4606 wmId = LOWORD(wParam);
\r
4607 wmEvent = HIWORD(wParam);
\r
4612 AnalysisPopDown();
\r
4615 case IDM_NewGameFRC:
4616 if( NewGameFRC() == 0 ) {
4622 case IDM_LoadGame:
\r
4623 LoadGameDialog(hwnd, "Load Game from File");
\r
4626 case IDM_LoadNextGame:
\r
4630 case IDM_LoadPrevGame:
\r
4634 case IDM_ReloadGame:
\r
4638 case IDM_LoadPosition:
\r
4639 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4640 Reset(FALSE, TRUE);
\r
4643 f = OpenFileDialog(hwnd, FALSE, "",
\r
4644 appData.oldSaveStyle ? "pos" : "fen",
\r
4646 "Load Position from File", &number, fileTitle, NULL);
\r
4648 LoadPosition(f, number, fileTitle);
\r
4652 case IDM_LoadNextPosition:
\r
4653 ReloadPosition(1);
\r
4656 case IDM_LoadPrevPosition:
\r
4657 ReloadPosition(-1);
\r
4660 case IDM_ReloadPosition:
\r
4661 ReloadPosition(0);
\r
4664 case IDM_SaveGame:
\r
4665 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4666 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4667 appData.oldSaveStyle ? "gam" : "pgn",
\r
4669 "Save Game to File", NULL, fileTitle, NULL);
\r
4671 SaveGame(f, 0, "");
\r
4675 case IDM_SavePosition:
\r
4676 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4677 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4678 appData.oldSaveStyle ? "pos" : "fen",
\r
4680 "Save Position to File", NULL, fileTitle, NULL);
\r
4682 SavePosition(f, 0, "");
\r
4686 case IDM_CopyGame:
\r
4687 CopyGameToClipboard();
\r
4690 case IDM_PasteGame:
\r
4691 PasteGameFromClipboard();
\r
4694 case IDM_CopyGameListToClipboard:
4695 CopyGameListToClipboard();
4698 /* [AS] Autodetect FEN or PGN data */
4700 PasteGameOrFENFromClipboard();
4703 /* [AS] Move history */
4704 case IDM_ShowMoveHistory:
4705 if( MoveHistoryIsUp() ) {
4706 MoveHistoryPopDown();
4713 /* [AS] Eval graph */
4714 case IDM_ShowEvalGraph:
4715 if( EvalGraphIsUp() ) {
4723 /* [AS] Engine output */
4724 case IDM_ShowEngineOutput:
4725 if( EngineOutputIsUp() ) {
4726 EngineOutputPopDown();
4729 EngineOutputPopUp();
4733 /* [AS] User adjudication */
4734 case IDM_UserAdjudication_White:
4735 UserAdjudicationEvent( +1 );
4738 case IDM_UserAdjudication_Black:
4739 UserAdjudicationEvent( -1 );
4742 case IDM_UserAdjudication_Draw:
4743 UserAdjudicationEvent( 0 );
4746 /* [AS] Game list options dialog */
4747 case IDM_GameListOptions:
4751 case IDM_CopyPosition:
\r
4752 CopyFENToClipboard();
\r
4755 case IDM_PastePosition:
\r
4756 PasteFENFromClipboard();
\r
4759 case IDM_MailMove:
\r
4763 case IDM_ReloadCMailMsg:
\r
4764 Reset(TRUE, TRUE);
\r
4765 ReloadCmailMsgEvent(FALSE);
\r
4768 case IDM_Minimize:
\r
4769 ShowWindow(hwnd, SW_MINIMIZE);
\r
4776 case IDM_MachineWhite:
\r
4777 MachineWhiteEvent();
\r
4779 * refresh the tags dialog only if it's visible
\r
4781 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4783 tags = PGNTags(&gameInfo);
\r
4784 TagsPopUp(tags, CmailMsg());
\r
4789 case IDM_MachineBlack:
\r
4790 MachineBlackEvent();
\r
4792 * refresh the tags dialog only if it's visible
\r
4794 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
4796 tags = PGNTags(&gameInfo);
\r
4797 TagsPopUp(tags, CmailMsg());
\r
4802 case IDM_TwoMachines:
\r
4803 TwoMachinesEvent();
\r
4805 * refresh the tags dialog only if it's visible
\r
4807 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
4809 tags = PGNTags(&gameInfo);
\r
4810 TagsPopUp(tags, CmailMsg());
\r
4815 case IDM_AnalysisMode:
\r
4816 if (!first.analysisSupport) {
\r
4817 char buf[MSG_SIZ];
\r
4818 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4819 DisplayError(buf, 0);
\r
4821 if (!appData.showThinking) ToggleShowThinking();
\r
4822 AnalyzeModeEvent();
\r
4826 case IDM_AnalyzeFile:
\r
4827 if (!first.analysisSupport) {
\r
4828 char buf[MSG_SIZ];
\r
4829 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4830 DisplayError(buf, 0);
\r
4832 if (!appData.showThinking) ToggleShowThinking();
\r
4833 AnalyzeFileEvent();
\r
4834 LoadGameDialog(hwnd, "Analyze Game from File");
\r
4835 AnalysisPeriodicEvent(1);
\r
4839 case IDM_IcsClient:
\r
4843 case IDM_EditGame:
\r
4847 case IDM_EditPosition:
\r
4848 EditPositionEvent();
\r
4851 case IDM_Training:
\r
4855 case IDM_ShowGameList:
\r
4856 ShowGameListProc();
\r
4859 case IDM_EditTags:
\r
4863 case IDM_EditComment:
\r
4864 if (commentDialogUp && editComment) {
\r
4867 EditCommentEvent();
\r
4887 case IDM_CallFlag:
\r
4907 case IDM_StopObserving:
\r
4908 StopObservingEvent();
\r
4911 case IDM_StopExamining:
\r
4912 StopExaminingEvent();
\r
4915 case IDM_TypeInMove:
\r
4916 PopUpMoveDialog('\000');
\r
4919 case IDM_Backward:
\r
4921 SetFocus(hwndMain);
\r
4926 SetFocus(hwndMain);
\r
4931 SetFocus(hwndMain);
\r
4936 SetFocus(hwndMain);
\r
4943 case IDM_TruncateGame:
\r
4944 TruncateGameEvent();
\r
4951 case IDM_RetractMove:
\r
4952 RetractMoveEvent();
\r
4955 case IDM_FlipView:
\r
4956 flipView = !flipView;
\r
4957 DrawPosition(FALSE, NULL);
\r
4960 case IDM_GeneralOptions:
\r
4961 GeneralOptionsPopup(hwnd);
\r
4962 DrawPosition(TRUE, NULL);
4965 case IDM_BoardOptions:
\r
4966 BoardOptionsPopup(hwnd);
\r
4969 case IDM_EnginePlayOptions:
4970 EnginePlayOptionsPopup(hwnd);
4973 case IDM_IcsOptions:
\r
4974 IcsOptionsPopup(hwnd);
\r
4978 FontsOptionsPopup(hwnd);
\r
4982 SoundOptionsPopup(hwnd);
\r
4985 case IDM_CommPort:
\r
4986 CommPortOptionsPopup(hwnd);
\r
4989 case IDM_LoadOptions:
\r
4990 LoadOptionsPopup(hwnd);
\r
4993 case IDM_SaveOptions:
\r
4994 SaveOptionsPopup(hwnd);
\r
4997 case IDM_TimeControl:
\r
4998 TimeControlOptionsPopup(hwnd);
\r
5001 case IDM_SaveSettings:
\r
5002 SaveSettings(settingsFileName);
\r
5005 case IDM_SaveSettingsOnExit:
\r
5006 saveSettingsOnExit = !saveSettingsOnExit;
\r
5007 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5008 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5009 MF_CHECKED : MF_UNCHECKED));
\r
5020 case IDM_AboutGame:
\r
5025 appData.debugMode = !appData.debugMode;
\r
5026 if (appData.debugMode) {
\r
5027 char dir[MSG_SIZ];
\r
5028 GetCurrentDirectory(MSG_SIZ, dir);
\r
5029 SetCurrentDirectory(installDir);
\r
5030 debugFP = fopen(appData.nameOfDebugFile, "w");
5031 SetCurrentDirectory(dir);
\r
5032 setbuf(debugFP, NULL);
\r
5039 case IDM_HELPCONTENTS:
\r
5040 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5041 MessageBox (GetFocus(),
\r
5042 "Unable to activate help",
\r
5043 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5047 case IDM_HELPSEARCH:
\r
5048 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5049 MessageBox (GetFocus(),
\r
5050 "Unable to activate help",
\r
5051 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5055 case IDM_HELPHELP:
\r
5056 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5057 MessageBox (GetFocus(),
\r
5058 "Unable to activate help",
\r
5059 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5064 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5066 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5067 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5068 FreeProcInstance(lpProc);
\r
5071 case IDM_DirectCommand1:
\r
5072 AskQuestionEvent("Direct Command",
\r
5073 "Send to chess program:", "", "1");
\r
5075 case IDM_DirectCommand2:
\r
5076 AskQuestionEvent("Direct Command",
\r
5077 "Send to second chess program:", "", "2");
\r
5080 case EP_WhitePawn:
\r
5081 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5082 fromX = fromY = -1;
\r
5085 case EP_WhiteKnight:
\r
5086 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5087 fromX = fromY = -1;
\r
5090 case EP_WhiteBishop:
\r
5091 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5092 fromX = fromY = -1;
\r
5095 case EP_WhiteRook:
\r
5096 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5097 fromX = fromY = -1;
\r
5100 case EP_WhiteQueen:
\r
5101 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5102 fromX = fromY = -1;
\r
5105 case EP_WhiteKing:
\r
5106 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5107 fromX = fromY = -1;
\r
5110 case EP_BlackPawn:
\r
5111 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5112 fromX = fromY = -1;
\r
5115 case EP_BlackKnight:
\r
5116 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5117 fromX = fromY = -1;
\r
5120 case EP_BlackBishop:
\r
5121 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5122 fromX = fromY = -1;
\r
5125 case EP_BlackRook:
\r
5126 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5127 fromX = fromY = -1;
\r
5130 case EP_BlackQueen:
\r
5131 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5132 fromX = fromY = -1;
\r
5135 case EP_BlackKing:
\r
5136 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5137 fromX = fromY = -1;
\r
5140 case EP_EmptySquare:
\r
5141 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5142 fromX = fromY = -1;
\r
5145 case EP_ClearBoard:
\r
5146 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5147 fromX = fromY = -1;
\r
5151 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5152 fromX = fromY = -1;
\r
5156 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5157 fromX = fromY = -1;
\r
5161 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5162 fromX = fromY = -1;
\r
5166 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5167 fromX = fromY = -1;
\r
5171 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5172 fromX = fromY = -1;
\r
5176 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5177 fromX = fromY = -1;
\r
5181 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5182 fromX = fromY = -1;
\r
5186 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5192 case CLOCK_TIMER_ID:
\r
5193 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5194 clockTimerEvent = 0;
\r
5195 DecrementClocks(); /* call into back end */
\r
5197 case LOAD_GAME_TIMER_ID:
\r
5198 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5199 loadGameTimerEvent = 0;
\r
5200 AutoPlayGameLoop(); /* call into back end */
\r
5202 case ANALYSIS_TIMER_ID:
\r
5203 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
5204 appData.periodicUpdates) {
\r
5205 AnalysisPeriodicEvent(0);
\r
5207 KillTimer(hwnd, analysisTimerEvent);
\r
5208 analysisTimerEvent = 0;
\r
5211 case DELAYED_TIMER_ID:
\r
5212 KillTimer(hwnd, delayedTimerEvent);
\r
5213 delayedTimerEvent = 0;
\r
5214 delayedTimerCallback();
\r
5219 case WM_USER_Input:
\r
5220 InputEvent(hwnd, message, wParam, lParam);
\r
5223 /* [AS] Also move "attached" child windows */
5224 case WM_WINDOWPOSCHANGING:
5225 if( hwnd == hwndMain && appData.useStickyWindows ) {
5226 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
5228 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
5229 /* Window is moving */
5232 GetWindowRect( hwnd, &rcMain );
5234 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
5235 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
5236 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
5242 case WM_ENTERSIZEMOVE:
\r
5243 if (hwnd == hwndMain) {
\r
5244 doingSizing = TRUE;
\r
5247 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
5251 if (hwnd == hwndMain) {
\r
5252 lastSizing = wParam;
\r
5257 return OnMoving( &sd, hwnd, wParam, lParam );
5259 case WM_EXITSIZEMOVE:
\r
5260 if (hwnd == hwndMain) {
\r
5262 doingSizing = FALSE;
\r
5263 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5264 GetClientRect(hwnd, &client);
\r
5265 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5268 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
5271 case WM_DESTROY: /* message: window being destroyed */
\r
5272 PostQuitMessage(0);
\r
5276 if (hwnd == hwndMain) {
\r
5281 default: /* Passes it on if unprocessed */
\r
5282 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5287 /*---------------------------------------------------------------------------*\
\r
5289 * Misc utility routines
\r
5291 \*---------------------------------------------------------------------------*/
\r
5294 * Decent random number generator, at least not as bad as Windows
\r
5295 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5297 unsigned int randstate;
\r
5302 randstate = randstate * 1664525 + 1013904223;
\r
5303 return (int) randstate & 0x7fffffff;
\r
5307 mysrandom(unsigned int seed)
\r
5314 * returns TRUE if user selects a different color, FALSE otherwise
\r
5318 ChangeColor(HWND hwnd, COLORREF *which)
\r
5320 static BOOL firstTime = TRUE;
\r
5321 static DWORD customColors[16];
\r
5323 COLORREF newcolor;
\r
5328 /* Make initial colors in use available as custom colors */
\r
5329 /* Should we put the compiled-in defaults here instead? */
\r
5331 customColors[i++] = lightSquareColor & 0xffffff;
\r
5332 customColors[i++] = darkSquareColor & 0xffffff;
\r
5333 customColors[i++] = whitePieceColor & 0xffffff;
\r
5334 customColors[i++] = blackPieceColor & 0xffffff;
\r
5335 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5336 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5338 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5339 customColors[i++] = textAttribs[ccl].color;
\r
5341 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5342 firstTime = FALSE;
\r
5345 cc.lStructSize = sizeof(cc);
\r
5346 cc.hwndOwner = hwnd;
\r
5347 cc.hInstance = NULL;
\r
5348 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5349 cc.lpCustColors = (LPDWORD) customColors;
\r
5350 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5352 if (!ChooseColor(&cc)) return FALSE;
\r
5354 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5355 if (newcolor == *which) return FALSE;
\r
5356 *which = newcolor;
\r
5360 InitDrawingColors();
\r
5361 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5366 MyLoadSound(MySound *ms)
\r
5372 if (ms->data) free(ms->data);
\r
5375 switch (ms->name[0]) {
\r
5381 /* System sound from Control Panel. Don't preload here. */
\r
5385 if (ms->name[1] == NULLCHAR) {
\r
5386 /* "!" alone = silence */
\r
5389 /* Builtin wave resource. Error if not found. */
\r
5390 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5391 if (h == NULL) break;
\r
5392 ms->data = (void *)LoadResource(hInst, h);
\r
5393 if (h == NULL) break;
\r
5398 /* .wav file. Error if not found. */
\r
5399 f = fopen(ms->name, "rb");
\r
5400 if (f == NULL) break;
\r
5401 if (fstat(fileno(f), &st) < 0) break;
\r
5402 ms->data = malloc(st.st_size);
\r
5403 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5409 char buf[MSG_SIZ];
\r
5410 sprintf(buf, "Error loading sound %s", ms->name);
\r
5411 DisplayError(buf, GetLastError());
\r
5417 MyPlaySound(MySound *ms)
\r
5419 BOOLEAN ok = FALSE;
\r
5420 switch (ms->name[0]) {
\r
5426 /* System sound from Control Panel (deprecated feature).
\r
5427 "$" alone or an unset sound name gets default beep (still in use). */
\r
5428 if (ms->name[1]) {
\r
5429 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5431 if (!ok) ok = MessageBeep(MB_OK);
\r
5434 /* Builtin wave resource, or "!" alone for silence */
\r
5435 if (ms->name[1]) {
\r
5436 if (ms->data == NULL) return FALSE;
\r
5437 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5443 /* .wav file. Error if not found. */
\r
5444 if (ms->data == NULL) return FALSE;
\r
5445 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5448 /* Don't print an error: this can happen innocently if the sound driver
\r
5449 is busy; for instance, if another instance of WinBoard is playing
\r
5450 a sound at about the same time. */
\r
5453 char buf[MSG_SIZ];
\r
5454 sprintf(buf, "Error playing sound %s", ms->name);
\r
5455 DisplayError(buf, GetLastError());
\r
5463 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5466 OPENFILENAME *ofn;
\r
5467 static UINT *number; /* gross that this is static */
\r
5469 switch (message) {
\r
5470 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5471 /* Center the dialog over the application window */
\r
5472 ofn = (OPENFILENAME *) lParam;
\r
5473 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5474 number = (UINT *) ofn->lCustData;
\r
5475 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5479 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5480 return FALSE; /* Allow for further processing */
\r
5483 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5484 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5486 return FALSE; /* Allow for further processing */
\r
5492 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5494 static UINT *number;
\r
5495 OPENFILENAME *ofname;
\r
5498 case WM_INITDIALOG:
\r
5499 ofname = (OPENFILENAME *)lParam;
\r
5500 number = (UINT *)(ofname->lCustData);
\r
5503 ofnot = (OFNOTIFY *)lParam;
\r
5504 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5505 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5514 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
5515 char *nameFilt, char *dlgTitle, UINT *number,
\r
5516 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5518 OPENFILENAME openFileName;
\r
5519 char buf1[MSG_SIZ];
\r
5522 if (fileName == NULL) fileName = buf1;
\r
5523 if (defName == NULL) {
\r
5524 strcpy(fileName, "*.");
\r
5525 strcat(fileName, defExt);
\r
5527 strcpy(fileName, defName);
\r
5529 if (fileTitle) strcpy(fileTitle, "");
\r
5530 if (number) *number = 0;
\r
5532 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5533 openFileName.hwndOwner = hwnd;
\r
5534 openFileName.hInstance = (HANDLE) hInst;
\r
5535 openFileName.lpstrFilter = nameFilt;
\r
5536 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5537 openFileName.nMaxCustFilter = 0L;
\r
5538 openFileName.nFilterIndex = 1L;
\r
5539 openFileName.lpstrFile = fileName;
\r
5540 openFileName.nMaxFile = MSG_SIZ;
\r
5541 openFileName.lpstrFileTitle = fileTitle;
\r
5542 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5543 openFileName.lpstrInitialDir = NULL;
\r
5544 openFileName.lpstrTitle = dlgTitle;
\r
5545 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5546 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
5547 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5548 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5549 openFileName.nFileOffset = 0;
\r
5550 openFileName.nFileExtension = 0;
\r
5551 openFileName.lpstrDefExt = defExt;
\r
5552 openFileName.lCustData = (LONG) number;
\r
5553 openFileName.lpfnHook = oldDialog ?
\r
5554 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5555 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5557 if (write ? GetSaveFileName(&openFileName) :
\r
5558 GetOpenFileName(&openFileName)) {
\r
5559 /* open the file */
\r
5560 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
5562 MessageBox(hwnd, "File open failed", NULL,
\r
5563 MB_OK|MB_ICONEXCLAMATION);
\r
5567 int err = CommDlgExtendedError();
\r
5568 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
5577 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5579 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5582 * Get the first pop-up menu in the menu template. This is the
\r
5583 * menu that TrackPopupMenu displays.
\r
5585 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5587 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5590 * TrackPopup uses screen coordinates, so convert the
\r
5591 * coordinates of the mouse click to screen coordinates.
\r
5593 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5595 /* Draw and track the floating pop-up menu. */
\r
5596 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5597 pt.x, pt.y, 0, hwnd, NULL);
\r
5599 /* Destroy the menu.*/
\r
5600 DestroyMenu(hmenu);
\r
5605 int sizeX, sizeY, newSizeX, newSizeY;
\r
5607 } ResizeEditPlusButtonsClosure;
\r
5610 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5612 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5616 if (hChild == cl->hText) return TRUE;
\r
5617 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5618 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5619 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5620 ScreenToClient(cl->hDlg, &pt);
\r
5621 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5622 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5626 /* Resize a dialog that has a (rich) edit field filling most of
\r
5627 the top, with a row of buttons below */
\r
5629 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
5632 int newTextHeight, newTextWidth;
\r
5633 ResizeEditPlusButtonsClosure cl;
\r
5635 /*if (IsIconic(hDlg)) return;*/
\r
5636 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
5638 cl.hdwp = BeginDeferWindowPos(8);
\r
5640 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
5641 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5642 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5643 if (newTextHeight < 0) {
\r
5644 newSizeY += -newTextHeight;
\r
5645 newTextHeight = 0;
\r
5647 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
5648 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5654 cl.newSizeX = newSizeX;
\r
5655 cl.newSizeY = newSizeY;
\r
5656 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
5658 EndDeferWindowPos(cl.hdwp);
\r
5661 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
5663 RECT rChild, rParent;
\r
5664 int wChild, hChild, wParent, hParent;
\r
5665 int wScreen, hScreen, xNew, yNew;
\r
5668 /* Get the Height and Width of the child window */
\r
5669 GetWindowRect (hwndChild, &rChild);
\r
5670 wChild = rChild.right - rChild.left;
\r
5671 hChild = rChild.bottom - rChild.top;
\r
5673 /* Get the Height and Width of the parent window */
\r
5674 GetWindowRect (hwndParent, &rParent);
\r
5675 wParent = rParent.right - rParent.left;
\r
5676 hParent = rParent.bottom - rParent.top;
\r
5678 /* Get the display limits */
\r
5679 hdc = GetDC (hwndChild);
\r
5680 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
5681 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
5682 ReleaseDC(hwndChild, hdc);
\r
5684 /* Calculate new X position, then adjust for screen */
\r
5685 xNew = rParent.left + ((wParent - wChild) /2);
\r
5688 } else if ((xNew+wChild) > wScreen) {
\r
5689 xNew = wScreen - wChild;
\r
5692 /* Calculate new Y position, then adjust for screen */
\r
5694 yNew = rParent.top + ((hParent - hChild) /2);
\r
5697 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
5702 } else if ((yNew+hChild) > hScreen) {
\r
5703 yNew = hScreen - hChild;
\r
5706 /* Set it, and return */
\r
5707 return SetWindowPos (hwndChild, NULL,
\r
5708 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
5711 /* Center one window over another */
5712 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
5714 return CenterWindowEx( hwndChild, hwndParent, 0 );
5717 /*---------------------------------------------------------------------------*\
\r
5719 * Startup Dialog functions
\r
5721 \*---------------------------------------------------------------------------*/
\r
5723 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
5725 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5727 while (*cd != NULL) {
\r
5728 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
5734 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
5736 char buf1[ARG_MAX];
\r
5739 if (str[0] == '@') {
\r
5740 FILE* f = fopen(str + 1, "r");
\r
5742 DisplayFatalError(str + 1, errno, 2);
\r
5745 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
5747 buf1[len] = NULLCHAR;
\r
5751 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5754 char buf[MSG_SIZ];
\r
5755 char *end = strchr(str, '\n');
\r
5756 if (end == NULL) return;
\r
5757 memcpy(buf, str, end - str);
\r
5758 buf[end - str] = NULLCHAR;
\r
5759 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
5765 SetStartupDialogEnables(HWND hDlg)
\r
5767 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5768 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5769 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5770 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5771 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
5772 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
5773 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5774 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
5775 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
5776 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
5777 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5778 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
5779 IsDlgButtonChecked(hDlg, OPT_View));
\r
5783 QuoteForFilename(char *filename)
\r
5785 int dquote, space;
\r
5786 dquote = strchr(filename, '"') != NULL;
\r
5787 space = strchr(filename, ' ') != NULL;
\r
5788 if (dquote || space) {
\r
5800 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
5802 char buf[MSG_SIZ];
\r
5805 InitComboStringsFromOption(hwndCombo, nthnames);
\r
5806 q = QuoteForFilename(nthcp);
\r
5807 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
5808 if (*nthdir != NULLCHAR) {
\r
5809 q = QuoteForFilename(nthdir);
\r
5810 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
5812 if (*nthcp == NULLCHAR) {
\r
5813 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5814 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5815 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5816 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5821 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5823 char buf[MSG_SIZ];
\r
5827 switch (message) {
\r
5828 case WM_INITDIALOG:
\r
5829 /* Center the dialog */
\r
5830 CenterWindow (hDlg, GetDesktopWindow());
\r
5831 /* Initialize the dialog items */
\r
5832 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5833 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
5834 firstChessProgramNames);
\r
5835 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5836 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
5837 secondChessProgramNames);
\r
5838 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
5839 InitComboStringsFromOption(hwndCombo, icsNames);
\r
5840 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
5841 if (*appData.icsHelper != NULLCHAR) {
\r
5842 char *q = QuoteForFilename(appData.icsHelper);
\r
5843 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
5845 if (*appData.icsHost == NULLCHAR) {
\r
5846 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5847 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
5848 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5849 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5850 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5853 if (appData.icsActive) {
5854 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
5856 else if (appData.noChessProgram) {
5857 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
5860 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
5863 SetStartupDialogEnables(hDlg);
\r
5867 switch (LOWORD(wParam)) {
\r
5869 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
5870 strcpy(buf, "/fcp=");
\r
5871 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5873 ParseArgs(StringGet, &p);
\r
5874 strcpy(buf, "/scp=");
\r
5875 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5877 ParseArgs(StringGet, &p);
\r
5878 appData.noChessProgram = FALSE;
\r
5879 appData.icsActive = FALSE;
\r
5880 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
5881 strcpy(buf, "/ics /icshost=");
\r
5882 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5884 ParseArgs(StringGet, &p);
\r
5885 if (appData.zippyPlay) {
\r
5886 strcpy(buf, "/fcp=");
\r
5887 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5889 ParseArgs(StringGet, &p);
\r
5891 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
5892 appData.noChessProgram = TRUE;
\r
5893 appData.icsActive = FALSE;
\r
5895 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
5896 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
5899 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
5900 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
5902 ParseArgs(StringGet, &p);
\r
5904 EndDialog(hDlg, TRUE);
\r
5911 case IDM_HELPCONTENTS:
\r
5912 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5913 MessageBox (GetFocus(),
\r
5914 "Unable to activate help",
\r
5915 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5920 SetStartupDialogEnables(hDlg);
\r
5928 /*---------------------------------------------------------------------------*\
\r
5930 * About box dialog functions
\r
5932 \*---------------------------------------------------------------------------*/
\r
5934 /* Process messages for "About" dialog box */
\r
5936 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5938 switch (message) {
\r
5939 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5940 /* Center the dialog over the application window */
\r
5941 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5942 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
5945 case WM_COMMAND: /* message: received a command */
\r
5946 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
5947 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
5948 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5956 /*---------------------------------------------------------------------------*\
\r
5958 * Comment Dialog functions
\r
5960 \*---------------------------------------------------------------------------*/
\r
5963 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5965 static HANDLE hwndText = NULL;
\r
5966 int len, newSizeX, newSizeY, flags;
\r
5967 static int sizeX, sizeY;
\r
5972 switch (message) {
\r
5973 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5974 /* Initialize the dialog items */
\r
5975 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
5976 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
5977 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
5978 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
5979 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
5980 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
5981 SetWindowText(hDlg, commentTitle);
\r
5982 if (editComment) {
\r
5983 SetFocus(hwndText);
\r
5985 SetFocus(GetDlgItem(hDlg, IDOK));
\r
5987 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
5988 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
5989 MAKELPARAM(FALSE, 0));
\r
5990 /* Size and position the dialog */
\r
5991 if (!commentDialog) {
\r
5992 commentDialog = hDlg;
\r
5993 flags = SWP_NOZORDER;
\r
5994 GetClientRect(hDlg, &rect);
\r
5995 sizeX = rect.right;
\r
5996 sizeY = rect.bottom;
\r
5997 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
5998 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
5999 WINDOWPLACEMENT wp;
\r
6000 EnsureOnScreen(&commentX, &commentY);
\r
6001 wp.length = sizeof(WINDOWPLACEMENT);
\r
6003 wp.showCmd = SW_SHOW;
\r
6004 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6005 wp.rcNormalPosition.left = commentX;
\r
6006 wp.rcNormalPosition.right = commentX + commentW;
\r
6007 wp.rcNormalPosition.top = commentY;
\r
6008 wp.rcNormalPosition.bottom = commentY + commentH;
\r
6009 SetWindowPlacement(hDlg, &wp);
\r
6011 GetClientRect(hDlg, &rect);
\r
6012 newSizeX = rect.right;
\r
6013 newSizeY = rect.bottom;
\r
6014 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6015 newSizeX, newSizeY);
\r
6022 case WM_COMMAND: /* message: received a command */
\r
6023 switch (LOWORD(wParam)) {
\r
6025 if (editComment) {
\r
6027 /* Read changed options from the dialog box */
\r
6028 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6029 len = GetWindowTextLength(hwndText);
\r
6030 str = (char *) malloc(len + 1);
\r
6031 GetWindowText(hwndText, str, len + 1);
\r
6040 ReplaceComment(commentIndex, str);
\r
6047 case OPT_CancelComment:
\r
6051 case OPT_ClearComment:
\r
6052 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6055 case OPT_EditComment:
\r
6056 EditCommentEvent();
\r
6065 newSizeX = LOWORD(lParam);
\r
6066 newSizeY = HIWORD(lParam);
\r
6067 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6072 case WM_GETMINMAXINFO:
\r
6073 /* Prevent resizing window too small */
\r
6074 mmi = (MINMAXINFO *) lParam;
\r
6075 mmi->ptMinTrackSize.x = 100;
\r
6076 mmi->ptMinTrackSize.y = 100;
\r
6083 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6088 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6090 if (str == NULL) str = "";
\r
6091 p = (char *) malloc(2 * strlen(str) + 2);
\r
6094 if (*str == '\n') *q++ = '\r';
\r
6098 if (commentText != NULL) free(commentText);
\r
6100 commentIndex = index;
\r
6101 commentTitle = title;
\r
6103 editComment = edit;
\r
6105 if (commentDialog) {
\r
6106 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6107 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
6109 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6110 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6111 hwndMain, (DLGPROC)lpProc);
\r
6112 FreeProcInstance(lpProc);
\r
6114 commentDialogUp = TRUE;
\r
6118 /*---------------------------------------------------------------------------*\
\r
6120 * Type-in move dialog functions
\r
6122 \*---------------------------------------------------------------------------*/
\r
6125 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6127 char move[MSG_SIZ];
\r
6129 ChessMove moveType;
\r
6130 int fromX, fromY, toX, toY;
\r
6133 switch (message) {
\r
6134 case WM_INITDIALOG:
\r
6135 move[0] = (char) lParam;
\r
6136 move[1] = NULLCHAR;
\r
6137 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
6138 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6139 SetWindowText(hInput, move);
\r
6141 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6145 switch (LOWORD(wParam)) {
\r
6147 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
6148 gameMode != Training) {
\r
6149 DisplayMoveError("Displayed move is not current");
\r
6151 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6152 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6153 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
6154 if (gameMode != Training)
\r
6155 forwardMostMove = currentMove;
\r
6156 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
6158 DisplayMoveError("Could not parse move");
\r
6161 EndDialog(hDlg, TRUE);
\r
6164 EndDialog(hDlg, FALSE);
\r
6175 PopUpMoveDialog(char firstchar)
\r
6179 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
6180 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
6181 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
6182 gameMode == EditPosition || gameMode == IcsExamining ||
\r
6183 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
6184 gameMode == Training) {
\r
6185 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6186 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6187 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6188 FreeProcInstance(lpProc);
\r
6192 /*---------------------------------------------------------------------------*\
\r
6196 \*---------------------------------------------------------------------------*/
\r
6198 /* Nonmodal error box */
\r
6199 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6200 WPARAM wParam, LPARAM lParam);
\r
6203 ErrorPopUp(char *title, char *content)
\r
6207 BOOLEAN modal = hwndMain == NULL;
\r
6225 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6226 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6229 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6231 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6232 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6233 hwndMain, (DLGPROC)lpProc);
\r
6234 FreeProcInstance(lpProc);
\r
6241 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6242 if (errorDialog == NULL) return;
\r
6243 DestroyWindow(errorDialog);
\r
6244 errorDialog = NULL;
\r
6248 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6253 switch (message) {
\r
6254 case WM_INITDIALOG:
\r
6255 GetWindowRect(hDlg, &rChild);
\r
6256 SetWindowPos(hDlg, NULL, rChild.left,
\r
6257 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6258 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6259 errorDialog = hDlg;
\r
6260 SetWindowText(hDlg, errorTitle);
\r
6261 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6262 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6266 switch (LOWORD(wParam)) {
\r
6269 if (errorDialog == hDlg) errorDialog = NULL;
\r
6270 DestroyWindow(hDlg);
\r
6281 /*---------------------------------------------------------------------------*\
\r
6283 * Ics Interaction console functions
\r
6285 \*---------------------------------------------------------------------------*/
\r
6287 #define HISTORY_SIZE 64
\r
6288 static char *history[HISTORY_SIZE];
\r
6289 int histIn = 0, histP = 0;
\r
6292 SaveInHistory(char *cmd)
\r
6294 if (history[histIn] != NULL) {
\r
6295 free(history[histIn]);
\r
6296 history[histIn] = NULL;
\r
6298 if (*cmd == NULLCHAR) return;
\r
6299 history[histIn] = StrSave(cmd);
\r
6300 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6301 if (history[histIn] != NULL) {
\r
6302 free(history[histIn]);
\r
6303 history[histIn] = NULL;
\r
6309 PrevInHistory(char *cmd)
\r
6312 if (histP == histIn) {
\r
6313 if (history[histIn] != NULL) free(history[histIn]);
\r
6314 history[histIn] = StrSave(cmd);
\r
6316 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6317 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6319 return history[histP];
\r
6325 if (histP == histIn) return NULL;
\r
6326 histP = (histP + 1) % HISTORY_SIZE;
\r
6327 return history[histP];
\r
6334 BOOLEAN immediate;
\r
6335 } IcsTextMenuEntry;
\r
6336 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
6337 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
6340 ParseIcsTextMenu(char *icsTextMenuString)
\r
6343 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
6344 char *p = icsTextMenuString;
\r
6345 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6348 if (e->command != NULL) {
\r
6350 e->command = NULL;
\r
6354 e = icsTextMenuEntry;
\r
6355 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6356 if (*p == ';' || *p == '\n') {
\r
6357 e->item = strdup("-");
\r
6358 e->command = NULL;
\r
6360 } else if (*p == '-') {
\r
6361 e->item = strdup("-");
\r
6362 e->command = NULL;
\r
6366 char *q, *r, *s, *t;
\r
6368 q = strchr(p, ',');
\r
6369 if (q == NULL) break;
\r
6371 r = strchr(q + 1, ',');
\r
6372 if (r == NULL) break;
\r
6374 s = strchr(r + 1, ',');
\r
6375 if (s == NULL) break;
\r
6378 t = strchr(s + 1, c);
\r
6381 t = strchr(s + 1, c);
\r
6383 if (t != NULL) *t = NULLCHAR;
\r
6384 e->item = strdup(p);
\r
6385 e->command = strdup(q + 1);
\r
6386 e->getname = *(r + 1) != '0';
\r
6387 e->immediate = *(s + 1) != '0';
\r
6391 if (t == NULL) break;
\r
6400 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6404 hmenu = LoadMenu(hInst, "TextMenu");
\r
6405 h = GetSubMenu(hmenu, 0);
\r
6407 if (strcmp(e->item, "-") == 0) {
\r
6408 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6410 if (e->item[0] == '|') {
\r
6411 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6412 IDM_CommandX + i, &e->item[1]);
\r
6414 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
6423 WNDPROC consoleTextWindowProc;
\r
6426 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6428 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6429 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6433 SetWindowText(hInput, command);
\r
6435 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6437 sel.cpMin = 999999;
\r
6438 sel.cpMax = 999999;
\r
6439 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6444 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6445 if (sel.cpMin == sel.cpMax) {
\r
6446 /* Expand to surrounding word */
\r
6449 tr.chrg.cpMax = sel.cpMin;
\r
6450 tr.chrg.cpMin = --sel.cpMin;
\r
6451 if (sel.cpMin < 0) break;
\r
6452 tr.lpstrText = name;
\r
6453 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6454 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6458 tr.chrg.cpMin = sel.cpMax;
\r
6459 tr.chrg.cpMax = ++sel.cpMax;
\r
6460 tr.lpstrText = name;
\r
6461 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6462 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6465 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6466 MessageBeep(MB_ICONEXCLAMATION);
\r
6470 tr.lpstrText = name;
\r
6471 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6473 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6474 MessageBeep(MB_ICONEXCLAMATION);
\r
6477 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6480 sprintf(buf, "%s %s", command, name);
\r
6481 SetWindowText(hInput, buf);
\r
6482 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6484 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
6485 SetWindowText(hInput, buf);
\r
6486 sel.cpMin = 999999;
\r
6487 sel.cpMax = 999999;
\r
6488 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6494 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6499 switch (message) {
\r
6501 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6504 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6507 sel.cpMin = 999999;
\r
6508 sel.cpMax = 999999;
\r
6509 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6510 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6515 if (wParam == '\t') {
\r
6516 if (GetKeyState(VK_SHIFT) < 0) {
\r
6518 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6519 if (buttonDesc[0].hwnd) {
\r
6520 SetFocus(buttonDesc[0].hwnd);
\r
6522 SetFocus(hwndMain);
\r
6526 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
6529 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6531 SendMessage(hInput, message, wParam, lParam);
\r
6535 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6537 return SendMessage(hInput, message, wParam, lParam);
\r
6538 case WM_MBUTTONDOWN:
\r
6539 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6540 case WM_RBUTTONDOWN:
\r
6541 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6542 /* Move selection here if it was empty */
\r
6544 pt.x = LOWORD(lParam);
\r
6545 pt.y = HIWORD(lParam);
\r
6546 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6547 if (sel.cpMin == sel.cpMax) {
\r
6548 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6549 sel.cpMax = sel.cpMin;
\r
6550 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6552 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6555 case WM_RBUTTONUP:
\r
6556 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6557 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6558 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6561 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6562 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6563 if (sel.cpMin == sel.cpMax) {
\r
6564 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6565 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6567 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6568 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6570 pt.x = LOWORD(lParam);
\r
6571 pt.y = HIWORD(lParam);
\r
6572 MenuPopup(hwnd, pt, hmenu, -1);
\r
6576 switch (LOWORD(wParam)) {
\r
6577 case IDM_QuickPaste:
\r
6579 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6580 if (sel.cpMin == sel.cpMax) {
\r
6581 MessageBeep(MB_ICONEXCLAMATION);
\r
6584 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6585 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6586 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6591 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6594 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6597 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6601 int i = LOWORD(wParam) - IDM_CommandX;
\r
6602 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
6603 icsTextMenuEntry[i].command != NULL) {
\r
6604 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
6605 icsTextMenuEntry[i].getname,
\r
6606 icsTextMenuEntry[i].immediate);
\r
6614 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
6617 WNDPROC consoleInputWindowProc;
\r
6620 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6622 char buf[MSG_SIZ];
\r
6624 static BOOL sendNextChar = FALSE;
\r
6625 static BOOL quoteNextChar = FALSE;
\r
6626 InputSource *is = consoleInputSource;
\r
6630 switch (message) {
\r
6632 if (!appData.localLineEditing || sendNextChar) {
\r
6633 is->buf[0] = (CHAR) wParam;
\r
6635 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6636 sendNextChar = FALSE;
\r
6639 if (quoteNextChar) {
\r
6640 buf[0] = (char) wParam;
\r
6641 buf[1] = NULLCHAR;
\r
6642 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
6643 quoteNextChar = FALSE;
\r
6647 case '\r': /* Enter key */
\r
6648 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
6649 if (consoleEcho) SaveInHistory(is->buf);
\r
6650 is->buf[is->count++] = '\n';
\r
6651 is->buf[is->count] = NULLCHAR;
\r
6652 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6653 if (consoleEcho) {
\r
6654 ConsoleOutput(is->buf, is->count, TRUE);
\r
6655 } else if (appData.localLineEditing) {
\r
6656 ConsoleOutput("\n", 1, TRUE);
\r
6659 case '\033': /* Escape key */
\r
6660 SetWindowText(hwnd, "");
\r
6661 cf.cbSize = sizeof(CHARFORMAT);
\r
6662 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6663 if (consoleEcho) {
\r
6664 cf.crTextColor = textAttribs[ColorNormal].color;
\r
6666 cf.crTextColor = COLOR_ECHOOFF;
\r
6668 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
6669 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6671 case '\t': /* Tab key */
\r
6672 if (GetKeyState(VK_SHIFT) < 0) {
\r
6674 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
6677 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6678 if (buttonDesc[0].hwnd) {
\r
6679 SetFocus(buttonDesc[0].hwnd);
\r
6681 SetFocus(hwndMain);
\r
6685 case '\023': /* Ctrl+S */
\r
6686 sendNextChar = TRUE;
\r
6688 case '\021': /* Ctrl+Q */
\r
6689 quoteNextChar = TRUE;
\r
6698 GetWindowText(hwnd, buf, MSG_SIZ);
\r
6699 p = PrevInHistory(buf);
\r
6701 SetWindowText(hwnd, p);
\r
6702 sel.cpMin = 999999;
\r
6703 sel.cpMax = 999999;
\r
6704 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6709 p = NextInHistory();
\r
6711 SetWindowText(hwnd, p);
\r
6712 sel.cpMin = 999999;
\r
6713 sel.cpMax = 999999;
\r
6714 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6720 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6724 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
6728 case WM_MBUTTONDOWN:
\r
6729 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6730 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6732 case WM_RBUTTONUP:
\r
6733 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6734 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6735 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6739 hmenu = LoadMenu(hInst, "InputMenu");
\r
6740 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6741 if (sel.cpMin == sel.cpMax) {
\r
6742 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6743 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
6745 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6746 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6748 pt.x = LOWORD(lParam);
\r
6749 pt.y = HIWORD(lParam);
\r
6750 MenuPopup(hwnd, pt, hmenu, -1);
\r
6754 switch (LOWORD(wParam)) {
\r
6756 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
6758 case IDM_SelectAll:
\r
6760 sel.cpMax = -1; /*999999?*/
\r
6761 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6764 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6767 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6770 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6775 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
6778 #define CO_MAX 100000
\r
6779 #define CO_TRIM 1000
\r
6782 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6785 static HWND hText, hInput, hFocus;
\r
6786 InputSource *is = consoleInputSource;
\r
6788 static int sizeX, sizeY;
\r
6789 int newSizeX, newSizeY;
\r
6792 switch (message) {
\r
6793 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6794 hwndConsole = hDlg;
\r
6795 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
6796 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
6798 consoleTextWindowProc = (WNDPROC)
\r
6799 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
6800 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6801 consoleInputWindowProc = (WNDPROC)
\r
6802 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
6803 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6804 Colorize(ColorNormal, TRUE);
\r
6805 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
6806 ChangedConsoleFont();
\r
6807 GetClientRect(hDlg, &rect);
\r
6808 sizeX = rect.right;
\r
6809 sizeY = rect.bottom;
\r
6810 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
6811 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
6812 WINDOWPLACEMENT wp;
\r
6813 EnsureOnScreen(&consoleX, &consoleY);
\r
6814 wp.length = sizeof(WINDOWPLACEMENT);
\r
6816 wp.showCmd = SW_SHOW;
\r
6817 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6818 wp.rcNormalPosition.left = consoleX;
\r
6819 wp.rcNormalPosition.right = consoleX + consoleW;
\r
6820 wp.rcNormalPosition.top = consoleY;
\r
6821 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
6822 SetWindowPlacement(hDlg, &wp);
\r
6836 if (IsIconic(hDlg)) break;
\r
6837 newSizeX = LOWORD(lParam);
\r
6838 newSizeY = HIWORD(lParam);
\r
6839 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
6840 RECT rectText, rectInput;
\r
6842 int newTextHeight, newTextWidth;
\r
6843 GetWindowRect(hText, &rectText);
\r
6844 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6845 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6846 if (newTextHeight < 0) {
\r
6847 newSizeY += -newTextHeight;
\r
6848 newTextHeight = 0;
\r
6850 SetWindowPos(hText, NULL, 0, 0,
\r
6851 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6852 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
6853 pt.x = rectInput.left;
\r
6854 pt.y = rectInput.top + newSizeY - sizeY;
\r
6855 ScreenToClient(hDlg, &pt);
\r
6856 SetWindowPos(hInput, NULL,
\r
6857 pt.x, pt.y, /* needs client coords */
\r
6858 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
6859 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
6865 case WM_GETMINMAXINFO:
\r
6866 /* Prevent resizing window too small */
\r
6867 mmi = (MINMAXINFO *) lParam;
\r
6868 mmi->ptMinTrackSize.x = 100;
\r
6869 mmi->ptMinTrackSize.y = 100;
\r
6873 case WM_ENTERSIZEMOVE:
6874 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
6877 return OnSizing( &sd, hDlg, wParam, lParam );
6880 return OnMoving( &sd, hDlg, wParam, lParam );
6882 case WM_EXITSIZEMOVE:
6883 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
6886 return DefWindowProc(hDlg, message, wParam, lParam);
\r
6894 if (hwndConsole) return;
\r
6895 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
6896 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
6901 ConsoleOutput(char* data, int length, int forceVisible)
\r
6906 char buf[CO_MAX+1];
\r
6909 static int delayLF = 0;
\r
6910 CHARRANGE savesel, sel;
\r
6912 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
6920 while (length--) {
\r
6928 } else if (*p == '\007') {
\r
6929 MyPlaySound(&sounds[(int)SoundBell]);
\r
6936 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
6937 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6938 /* Save current selection */
\r
6939 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
6940 exlen = GetWindowTextLength(hText);
\r
6941 /* Find out whether current end of text is visible */
\r
6942 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
6943 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
6944 /* Trim existing text if it's too long */
\r
6945 if (exlen + (q - buf) > CO_MAX) {
\r
6946 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
6949 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6950 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
6952 savesel.cpMin -= trim;
\r
6953 savesel.cpMax -= trim;
\r
6954 if (exlen < 0) exlen = 0;
\r
6955 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
6956 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
6958 /* Append the new text */
\r
6959 sel.cpMin = exlen;
\r
6960 sel.cpMax = exlen;
\r
6961 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6962 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
6963 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
6964 if (forceVisible || exlen == 0 ||
\r
6965 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
6966 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
6967 /* Scroll to make new end of text visible if old end of text
\r
6968 was visible or new text is an echo of user typein */
\r
6969 sel.cpMin = 9999999;
\r
6970 sel.cpMax = 9999999;
\r
6971 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6972 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6973 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
6974 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6976 if (savesel.cpMax == exlen || forceVisible) {
\r
6977 /* Move insert point to new end of text if it was at the old
\r
6978 end of text or if the new text is an echo of user typein */
\r
6979 sel.cpMin = 9999999;
\r
6980 sel.cpMax = 9999999;
\r
6981 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6983 /* Restore previous selection */
\r
6984 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
6986 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6993 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
6994 RECT *rect, char *color)
\r
6998 COLORREF oldFg, oldBg;
\r
7001 if (appData.clockMode) {
\r
7003 sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));
\r
7005 sprintf(buf, "%s: %s", color, TimeString(timeRemaining));
\r
7012 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7013 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7015 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7016 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7018 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7020 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7021 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7022 rect, str, strlen(str), NULL);
\r
7024 (void) SetTextColor(hdc, oldFg);
\r
7025 (void) SetBkColor(hdc, oldBg);
\r
7026 (void) SelectObject(hdc, oldFont);
\r
7031 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7038 if (appData.debugMode) {
7039 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
7042 return ERROR_INVALID_USER_BUFFER;
7045 ResetEvent(ovl->hEvent);
\r
7046 ovl->Offset = ovl->OffsetHigh = 0;
\r
7047 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7051 err = GetLastError();
\r
7052 if (err == ERROR_IO_PENDING) {
\r
7053 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7057 err = GetLastError();
\r
7064 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7069 ResetEvent(ovl->hEvent);
\r
7070 ovl->Offset = ovl->OffsetHigh = 0;
\r
7071 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7075 err = GetLastError();
\r
7076 if (err == ERROR_IO_PENDING) {
\r
7077 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7081 err = GetLastError();
\r
7087 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
7088 void CheckForInputBufferFull( InputSource * is )
7090 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
7091 /* Look for end of line */
7094 while( p < is->next && *p != '\n' ) {
7098 if( p >= is->next ) {
7099 if (appData.debugMode) {
7100 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
7103 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
7104 is->count = (DWORD) -1;
7111 InputThread(LPVOID arg)
\r
7116 is = (InputSource *) arg;
\r
7117 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7118 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7119 while (is->hThread != NULL) {
\r
7120 is->error = DoReadFile(is->hFile, is->next,
\r
7121 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7122 &is->count, &ovl);
\r
7123 if (is->error == NO_ERROR) {
\r
7124 is->next += is->count;
\r
7126 if (is->error == ERROR_BROKEN_PIPE) {
\r
7127 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7130 is->count = (DWORD) -1;
\r
7131 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
7136 CheckForInputBufferFull( is );
7138 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7140 if( is->count == ((DWORD) -1) ) break; /* [AS] */
7142 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7145 CloseHandle(ovl.hEvent);
\r
7146 CloseHandle(is->hFile);
\r
7148 if (appData.debugMode) {
7149 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
7156 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7158 NonOvlInputThread(LPVOID arg)
\r
7165 is = (InputSource *) arg;
\r
7166 while (is->hThread != NULL) {
\r
7167 is->error = ReadFile(is->hFile, is->next,
\r
7168 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7169 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7170 if (is->error == NO_ERROR) {
\r
7171 /* Change CRLF to LF */
\r
7172 if (is->next > is->buf) {
\r
7174 i = is->count + 1;
\r
7182 if (prev == '\r' && *p == '\n') {
\r
7194 if (is->error == ERROR_BROKEN_PIPE) {
\r
7195 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7198 is->count = (DWORD) -1;
\r
7202 CheckForInputBufferFull( is );
7204 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7206 if( is->count == ((DWORD) -1) ) break; /* [AS] */
7208 if (is->count < 0) break; /* Quit on error */
\r
7210 CloseHandle(is->hFile);
\r
7215 SocketInputThread(LPVOID arg)
\r
7219 is = (InputSource *) arg;
\r
7220 while (is->hThread != NULL) {
\r
7221 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7222 if ((int)is->count == SOCKET_ERROR) {
\r
7223 is->count = (DWORD) -1;
\r
7224 is->error = WSAGetLastError();
\r
7226 is->error = NO_ERROR;
\r
7227 is->next += is->count;
\r
7228 if (is->count == 0 && is->second == is) {
\r
7229 /* End of file on stderr; quit with no message */
\r
7233 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7235 if( is->count == ((DWORD) -1) ) break; /* [AS] */
7237 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7243 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7247 is = (InputSource *) lParam;
\r
7248 if (is->lineByLine) {
\r
7249 /* Feed in lines one by one */
\r
7250 char *p = is->buf;
\r
7252 while (q < is->next) {
\r
7253 if (*q++ == '\n') {
\r
7254 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7259 /* Move any partial line to the start of the buffer */
\r
7261 while (p < is->next) {
\r
7266 if (is->error != NO_ERROR || is->count == 0) {
\r
7267 /* Notify backend of the error. Note: If there was a partial
\r
7268 line at the end, it is not flushed through. */
\r
7269 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7272 /* Feed in the whole chunk of input at once */
\r
7273 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7274 is->next = is->buf;
\r
7278 /*---------------------------------------------------------------------------*\
\r
7280 * Menu enables. Used when setting various modes.
\r
7282 \*---------------------------------------------------------------------------*/
\r
7290 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7292 while (enab->item > 0) {
\r
7293 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7298 Enables gnuEnables[] = {
\r
7299 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7300 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7301 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7302 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7303 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7304 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7305 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7306 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7307 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7308 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7312 Enables icsEnables[] = {
\r
7313 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7314 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7315 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7316 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7317 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7318 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7319 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7320 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7321 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7322 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7323 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7324 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7329 Enables zippyEnables[] = {
\r
7330 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7331 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7332 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7337 Enables ncpEnables[] = {
\r
7338 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7339 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7340 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7341 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7342 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7343 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7344 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7345 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7346 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7347 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7348 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7349 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7350 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7351 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7352 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7356 Enables trainingOnEnables[] = {
\r
7357 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7358 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7359 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7360 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7361 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7362 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7363 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7364 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7368 Enables trainingOffEnables[] = {
\r
7369 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7370 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7371 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7372 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7373 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7374 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7375 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7376 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7380 /* These modify either ncpEnables or gnuEnables */
\r
7381 Enables cmailEnables[] = {
\r
7382 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7383 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7384 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7385 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7386 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7387 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7388 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7392 Enables machineThinkingEnables[] = {
\r
7393 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7394 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7395 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7396 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7397 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7398 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7399 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7400 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7401 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7402 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7403 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7404 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7405 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7406 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7407 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7411 Enables userThinkingEnables[] = {
\r
7412 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7413 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7414 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7415 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7416 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7417 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7418 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7419 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7420 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7421 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7422 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7423 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7424 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7425 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7426 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7430 /*---------------------------------------------------------------------------*\
\r
7432 * Front-end interface functions exported by XBoard.
\r
7433 * Functions appear in same order as prototypes in frontend.h.
\r
7435 \*---------------------------------------------------------------------------*/
\r
7439 static UINT prevChecked = 0;
\r
7440 static int prevPausing = 0;
\r
7443 if (pausing != prevPausing) {
\r
7444 prevPausing = pausing;
\r
7445 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7446 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
7447 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
7450 switch (gameMode) {
\r
7451 case BeginningOfGame:
\r
7452 if (appData.icsActive)
\r
7453 nowChecked = IDM_IcsClient;
\r
7454 else if (appData.noChessProgram)
\r
7455 nowChecked = IDM_EditGame;
\r
7457 nowChecked = IDM_MachineBlack;
\r
7459 case MachinePlaysBlack:
\r
7460 nowChecked = IDM_MachineBlack;
\r
7462 case MachinePlaysWhite:
\r
7463 nowChecked = IDM_MachineWhite;
\r
7465 case TwoMachinesPlay:
\r
7466 nowChecked = IDM_TwoMachines;
\r
7469 nowChecked = IDM_AnalysisMode;
\r
7472 nowChecked = IDM_AnalyzeFile;
\r
7475 nowChecked = IDM_EditGame;
\r
7477 case PlayFromGameFile:
\r
7478 nowChecked = IDM_LoadGame;
\r
7480 case EditPosition:
\r
7481 nowChecked = IDM_EditPosition;
\r
7484 nowChecked = IDM_Training;
\r
7486 case IcsPlayingWhite:
\r
7487 case IcsPlayingBlack:
\r
7488 case IcsObserving:
\r
7490 nowChecked = IDM_IcsClient;
\r
7497 if (prevChecked != 0)
\r
7498 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7499 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
7500 if (nowChecked != 0)
\r
7501 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7502 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
7504 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
7505 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
7506 MF_BYCOMMAND|MF_ENABLED);
\r
7508 (void) EnableMenuItem(GetMenu(hwndMain),
\r
7509 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
7512 prevChecked = nowChecked;
\r
7518 HMENU hmenu = GetMenu(hwndMain);
\r
7519 SetMenuEnables(hmenu, icsEnables);
\r
7520 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
7521 MF_BYPOSITION|MF_ENABLED);
\r
7523 if (appData.zippyPlay) {
\r
7524 SetMenuEnables(hmenu, zippyEnables);
\r
7532 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
7538 HMENU hmenu = GetMenu(hwndMain);
\r
7539 SetMenuEnables(hmenu, ncpEnables);
\r
7540 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
7541 MF_BYPOSITION|MF_GRAYED);
\r
7542 DrawMenuBar(hwndMain);
\r
7548 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
7552 SetTrainingModeOn()
\r
7555 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
7556 for (i = 0; i < N_BUTTONS; i++) {
\r
7557 if (buttonDesc[i].hwnd != NULL)
\r
7558 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
7563 VOID SetTrainingModeOff()
\r
7566 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
7567 for (i = 0; i < N_BUTTONS; i++) {
\r
7568 if (buttonDesc[i].hwnd != NULL)
\r
7569 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
7575 SetUserThinkingEnables()
\r
7577 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
7581 SetMachineThinkingEnables()
\r
7583 HMENU hMenu = GetMenu(hwndMain);
\r
7584 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
7586 SetMenuEnables(hMenu, machineThinkingEnables);
\r
7588 if (gameMode == MachinePlaysBlack) {
\r
7589 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
7590 } else if (gameMode == MachinePlaysWhite) {
\r
7591 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
7592 } else if (gameMode == TwoMachinesPlay) {
\r
7593 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
7599 DisplayTitle(char *str)
\r
7601 char title[MSG_SIZ], *host;
\r
7602 if (str[0] != NULLCHAR) {
\r
7603 strcpy(title, str);
\r
7604 } else if (appData.icsActive) {
\r
7605 if (appData.icsCommPort[0] != NULLCHAR)
\r
7608 host = appData.icsHost;
\r
7609 sprintf(title, "%s: %s", szTitle, host);
\r
7610 } else if (appData.noChessProgram) {
\r
7611 strcpy(title, szTitle);
\r
7613 strcpy(title, szTitle);
\r
7614 strcat(title, ": ");
\r
7615 strcat(title, first.tidy);
\r
7617 SetWindowText(hwndMain, title);
\r
7622 DisplayMessage(char *str1, char *str2)
\r
7626 int remain = MESSAGE_TEXT_MAX - 1;
\r
7629 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
7630 messageText[0] = NULLCHAR;
\r
7632 len = strlen(str1);
\r
7633 if (len > remain) len = remain;
\r
7634 strncpy(messageText, str1, len);
\r
7635 messageText[len] = NULLCHAR;
\r
7638 if (*str2 && remain >= 2) {
\r
7640 strcat(messageText, " ");
\r
7643 len = strlen(str2);
\r
7644 if (len > remain) len = remain;
\r
7645 strncat(messageText, str2, len);
\r
7647 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
7649 if (IsIconic(hwndMain)) return;
\r
7650 hdc = GetDC(hwndMain);
\r
7651 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
7652 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7653 &messageRect, messageText, strlen(messageText), NULL);
\r
7654 (void) SelectObject(hdc, oldFont);
\r
7655 (void) ReleaseDC(hwndMain, hdc);
\r
7659 DisplayError(char *str, int error)
\r
7661 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
7667 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7668 NULL, error, LANG_NEUTRAL,
\r
7669 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7671 sprintf(buf, "%s:\n%s", str, buf2);
\r
7673 ErrorMap *em = errmap;
\r
7674 while (em->err != 0 && em->err != error) em++;
\r
7675 if (em->err != 0) {
\r
7676 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7678 sprintf(buf, "%s:\nError code %d", str, error);
\r
7683 ErrorPopUp("Error", buf);
\r
7688 DisplayMoveError(char *str)
\r
7690 fromX = fromY = -1;
\r
7691 ClearHighlights();
\r
7692 DrawPosition(FALSE, NULL);
\r
7693 if (appData.popupMoveErrors) {
\r
7694 ErrorPopUp("Error", str);
\r
7696 DisplayMessage(str, "");
\r
7697 moveErrorMessageUp = TRUE;
\r
7702 DisplayFatalError(char *str, int error, int exitStatus)
\r
7704 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
7706 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
7709 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7710 NULL, error, LANG_NEUTRAL,
\r
7711 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7713 sprintf(buf, "%s:\n%s", str, buf2);
\r
7715 ErrorMap *em = errmap;
\r
7716 while (em->err != 0 && em->err != error) em++;
\r
7717 if (em->err != 0) {
\r
7718 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7720 sprintf(buf, "%s:\nError code %d", str, error);
\r
7725 if (appData.debugMode) {
\r
7726 fprintf(debugFP, "%s: %s\n", label, str);
\r
7728 if (appData.popupExitMessage) {
\r
7729 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
7730 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
7732 ExitEvent(exitStatus);
\r
7737 DisplayInformation(char *str)
\r
7739 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
7744 DisplayNote(char *str)
\r
7746 ErrorPopUp("Note", str);
\r
7751 char *title, *question, *replyPrefix;
\r
7756 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7758 static QuestionParams *qp;
\r
7759 char reply[MSG_SIZ];
\r
7762 switch (message) {
\r
7763 case WM_INITDIALOG:
\r
7764 qp = (QuestionParams *) lParam;
\r
7765 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7766 SetWindowText(hDlg, qp->title);
\r
7767 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
7768 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
7772 switch (LOWORD(wParam)) {
\r
7774 strcpy(reply, qp->replyPrefix);
\r
7775 if (*reply) strcat(reply, " ");
\r
7776 len = strlen(reply);
\r
7777 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
7778 strcat(reply, "\n");
\r
7779 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
7780 EndDialog(hDlg, TRUE);
\r
7781 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
7784 EndDialog(hDlg, FALSE);
\r
7795 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
7797 QuestionParams qp;
\r
7801 qp.question = question;
\r
7802 qp.replyPrefix = replyPrefix;
\r
7804 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
7805 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
7806 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
7807 FreeProcInstance(lpProc);
\r
7810 /* [AS] Pick FRC position */
7811 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
7813 static int * lpIndexFRC;
7820 lpIndexFRC = (int *) lParam;
7822 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
7824 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
7825 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
7826 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
7827 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
7832 switch( LOWORD(wParam) ) {
7834 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
7835 EndDialog( hDlg, 0 );
7838 EndDialog( hDlg, 1 );
7841 if( HIWORD(wParam) == EN_CHANGE ) {
7842 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
7844 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
7847 case IDC_NFG_Random:
7848 sprintf( buf, "%d", myrandom() % 960 );
7849 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
7862 int index = appData.defaultFrcPosition;
7863 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
7865 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
7868 appData.defaultFrcPosition = index;
7874 /* [AS] Game list options */
7880 static GLT_Item GLT_ItemInfo[] = {
7881 { GLT_EVENT, "Event" },
7882 { GLT_SITE, "Site" },
7883 { GLT_DATE, "Date" },
7884 { GLT_ROUND, "Round" },
7885 { GLT_PLAYERS, "Players" },
7886 { GLT_RESULT, "Result" },
7887 { GLT_WHITE_ELO, "White Rating" },
7888 { GLT_BLACK_ELO, "Black Rating" },
7889 { GLT_TIME_CONTROL,"Time Control" },
7890 { GLT_VARIANT, "Variant" },
7891 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
7895 const char * GLT_FindItem( char id )
7897 const char * result = 0;
7899 GLT_Item * list = GLT_ItemInfo;
7901 while( list->id != 0 ) {
7902 if( list->id == id ) {
7903 result = list->name;
7913 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
7915 const char * name = GLT_FindItem( id );
7919 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
7922 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
7927 void GLT_TagsToList( HWND hDlg, char * tags )
7931 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
7934 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
7938 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
7943 if( strchr( tags, *pc ) == 0 ) {
7944 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
7949 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
7952 char GLT_ListItemToTag( HWND hDlg, int index )
7957 GLT_Item * list = GLT_ItemInfo;
7959 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
7960 while( list->id != 0 ) {
7961 if( strcmp( list->name, name ) == 0 ) {
7973 void GLT_MoveSelection( HWND hDlg, int delta )
7975 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
7976 int idx2 = idx1 + delta;
7977 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
7979 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
7982 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
7983 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
7984 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
7985 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
7989 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
7991 static char glt[64];
7992 static char * lpUserGLT;
7997 lpUserGLT = (char *) lParam;
7999 strcpy( glt, lpUserGLT );
8001 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
8003 /* Initialize list */
8004 GLT_TagsToList( hDlg, glt );
8006 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
8011 switch( LOWORD(wParam) ) {
8014 char * pc = lpUserGLT;
8016 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
8020 id = GLT_ListItemToTag( hDlg, idx );
8024 } while( id != '\0' );
8026 EndDialog( hDlg, 0 );
8029 EndDialog( hDlg, 1 );
8032 case IDC_GLT_Default:
8033 strcpy( glt, GLT_DEFAULT_TAGS );
8034 GLT_TagsToList( hDlg, glt );
8037 case IDC_GLT_Restore:
8038 strcpy( glt, lpUserGLT );
8039 GLT_TagsToList( hDlg, glt );
8043 GLT_MoveSelection( hDlg, -1 );
8047 GLT_MoveSelection( hDlg, +1 );
8057 int GameListOptions()
8061 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
8063 strcpy( glt, appData.gameListTags );
8065 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
8068 /* [AS] Memory leak here! */
8069 appData.gameListTags = strdup( glt );
8077 DisplayIcsInteractionTitle(char *str)
\r
8079 char consoleTitle[MSG_SIZ];
\r
8081 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8082 SetWindowText(hwndConsole, consoleTitle);
\r
8086 DrawPosition(int fullRedraw, Board board)
\r
8088 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8095 fromX = fromY = -1;
\r
8096 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8097 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8098 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8099 dragInfo.lastpos = dragInfo.pos;
\r
8100 dragInfo.start.x = dragInfo.start.y = -1;
\r
8101 dragInfo.from = dragInfo.start;
\r
8103 DrawPosition(TRUE, NULL);
\r
8109 CommentPopUp(char *title, char *str)
\r
8111 HWND hwnd = GetActiveWindow();
\r
8112 EitherCommentPopUp(0, title, str, FALSE);
\r
8113 SetActiveWindow(hwnd);
\r
8117 CommentPopDown(void)
\r
8119 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8120 if (commentDialog) {
\r
8121 ShowWindow(commentDialog, SW_HIDE);
\r
8123 commentDialogUp = FALSE;
\r
8127 EditCommentPopUp(int index, char *title, char *str)
\r
8129 EitherCommentPopUp(index, title, str, TRUE);
\r
8136 MyPlaySound(&sounds[(int)SoundMove]);
\r
8139 VOID PlayIcsWinSound()
\r
8141 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8144 VOID PlayIcsLossSound()
\r
8146 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8149 VOID PlayIcsDrawSound()
\r
8151 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8154 VOID PlayIcsUnfinishedSound()
\r
8156 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8162 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8170 consoleEcho = TRUE;
\r
8171 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8172 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8173 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8182 consoleEcho = FALSE;
\r
8183 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8184 /* This works OK: set text and background both to the same color */
\r
8186 cf.crTextColor = COLOR_ECHOOFF;
\r
8187 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8188 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8191 /* No Raw()...? */
\r
8193 void Colorize(ColorClass cc, int continuation)
\r
8195 currentColorClass = cc;
\r
8196 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8197 consoleCF.crTextColor = textAttribs[cc].color;
\r
8198 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8199 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8205 static char buf[MSG_SIZ];
\r
8206 DWORD bufsiz = MSG_SIZ;
\r
8208 if (!GetUserName(buf, &bufsiz)) {
\r
8209 /*DisplayError("Error getting user name", GetLastError());*/
\r
8210 strcpy(buf, "User");
\r
8218 static char buf[MSG_SIZ];
\r
8219 DWORD bufsiz = MSG_SIZ;
\r
8221 if (!GetComputerName(buf, &bufsiz)) {
\r
8222 /*DisplayError("Error getting host name", GetLastError());*/
\r
8223 strcpy(buf, "Unknown");
\r
8230 ClockTimerRunning()
\r
8232 return clockTimerEvent != 0;
\r
8238 if (clockTimerEvent == 0) return FALSE;
\r
8239 KillTimer(hwndMain, clockTimerEvent);
\r
8240 clockTimerEvent = 0;
\r
8245 StartClockTimer(long millisec)
\r
8247 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8248 (UINT) millisec, NULL);
\r
8252 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8255 hdc = GetDC(hwndMain);
\r
8256 if (!IsIconic(hwndMain)) {
\r
8257 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");
\r
8259 if (highlight && iconCurrent == iconBlack) {
\r
8260 iconCurrent = iconWhite;
\r
8261 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8262 if (IsIconic(hwndMain)) {
\r
8263 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8266 (void) ReleaseDC(hwndMain, hdc);
\r
8268 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8272 DisplayBlackClock(long timeRemaining, int highlight)
\r
8275 hdc = GetDC(hwndMain);
\r
8276 if (!IsIconic(hwndMain)) {
\r
8277 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");
\r
8279 if (highlight && iconCurrent == iconWhite) {
\r
8280 iconCurrent = iconBlack;
\r
8281 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8282 if (IsIconic(hwndMain)) {
\r
8283 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8286 (void) ReleaseDC(hwndMain, hdc);
\r
8288 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8293 LoadGameTimerRunning()
\r
8295 return loadGameTimerEvent != 0;
\r
8299 StopLoadGameTimer()
\r
8301 if (loadGameTimerEvent == 0) return FALSE;
\r
8302 KillTimer(hwndMain, loadGameTimerEvent);
\r
8303 loadGameTimerEvent = 0;
\r
8308 StartLoadGameTimer(long millisec)
\r
8310 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8311 (UINT) millisec, NULL);
\r
8319 char fileTitle[MSG_SIZ];
\r
8321 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8322 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
8323 appData.oldSaveStyle ? "gam" : "pgn",
\r
8325 "Save Game to File", NULL, fileTitle, NULL);
\r
8327 SaveGame(f, 0, "");
\r
8334 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8336 if (delayedTimerEvent != 0) {
\r
8337 if (appData.debugMode) {
\r
8338 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8340 KillTimer(hwndMain, delayedTimerEvent);
\r
8341 delayedTimerEvent = 0;
\r
8342 delayedTimerCallback();
\r
8344 delayedTimerCallback = cb;
\r
8345 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8346 (UINT) millisec, NULL);
\r
8349 DelayedEventCallback
\r
8352 if (delayedTimerEvent) {
\r
8353 return delayedTimerCallback;
\r
8360 CancelDelayedEvent()
\r
8362 if (delayedTimerEvent) {
\r
8363 KillTimer(hwndMain, delayedTimerEvent);
\r
8364 delayedTimerEvent = 0;
\r
8368 /* Start a child process running the given program.
\r
8369 The process's standard output can be read from "from", and its
\r
8370 standard input can be written to "to".
\r
8371 Exit with fatal error if anything goes wrong.
\r
8372 Returns an opaque pointer that can be used to destroy the process
\r
8376 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8378 #define BUFSIZE 4096
\r
8380 HANDLE hChildStdinRd, hChildStdinWr,
\r
8381 hChildStdoutRd, hChildStdoutWr;
\r
8382 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8383 SECURITY_ATTRIBUTES saAttr;
\r
8385 PROCESS_INFORMATION piProcInfo;
\r
8386 STARTUPINFO siStartInfo;
\r
8388 char buf[MSG_SIZ];
\r
8391 if (appData.debugMode) {
\r
8392 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8397 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8398 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8399 saAttr.bInheritHandle = TRUE;
\r
8400 saAttr.lpSecurityDescriptor = NULL;
\r
8403 * The steps for redirecting child's STDOUT:
\r
8404 * 1. Create anonymous pipe to be STDOUT for child.
\r
8405 * 2. Create a noninheritable duplicate of read handle,
\r
8406 * and close the inheritable read handle.
\r
8409 /* Create a pipe for the child's STDOUT. */
\r
8410 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8411 return GetLastError();
\r
8414 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8415 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8416 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8417 FALSE, /* not inherited */
\r
8418 DUPLICATE_SAME_ACCESS);
\r
8420 return GetLastError();
\r
8422 CloseHandle(hChildStdoutRd);
\r
8425 * The steps for redirecting child's STDIN:
\r
8426 * 1. Create anonymous pipe to be STDIN for child.
\r
8427 * 2. Create a noninheritable duplicate of write handle,
\r
8428 * and close the inheritable write handle.
\r
8431 /* Create a pipe for the child's STDIN. */
\r
8432 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8433 return GetLastError();
\r
8436 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8437 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8438 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8439 FALSE, /* not inherited */
\r
8440 DUPLICATE_SAME_ACCESS);
\r
8442 return GetLastError();
\r
8444 CloseHandle(hChildStdinWr);
\r
8446 /* Arrange to (1) look in dir for the child .exe file, and
\r
8447 * (2) have dir be the child's working directory. Interpret
\r
8448 * dir relative to the directory WinBoard loaded from. */
\r
8449 GetCurrentDirectory(MSG_SIZ, buf);
\r
8450 SetCurrentDirectory(installDir);
\r
8451 SetCurrentDirectory(dir);
\r
8453 /* Now create the child process. */
\r
8455 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8456 siStartInfo.lpReserved = NULL;
\r
8457 siStartInfo.lpDesktop = NULL;
\r
8458 siStartInfo.lpTitle = NULL;
\r
8459 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8460 siStartInfo.cbReserved2 = 0;
\r
8461 siStartInfo.lpReserved2 = NULL;
\r
8462 siStartInfo.hStdInput = hChildStdinRd;
\r
8463 siStartInfo.hStdOutput = hChildStdoutWr;
\r
8464 siStartInfo.hStdError = hChildStdoutWr;
\r
8466 fSuccess = CreateProcess(NULL,
\r
8467 cmdLine, /* command line */
\r
8468 NULL, /* process security attributes */
\r
8469 NULL, /* primary thread security attrs */
\r
8470 TRUE, /* handles are inherited */
\r
8471 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
8472 NULL, /* use parent's environment */
\r
8474 &siStartInfo, /* STARTUPINFO pointer */
\r
8475 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
8477 err = GetLastError();
\r
8478 SetCurrentDirectory(buf); /* return to prev directory */
\r
8483 /* Close the handles we don't need in the parent */
\r
8484 CloseHandle(piProcInfo.hThread);
\r
8485 CloseHandle(hChildStdinRd);
\r
8486 CloseHandle(hChildStdoutWr);
\r
8488 /* Prepare return value */
\r
8489 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8490 cp->kind = CPReal;
\r
8491 cp->hProcess = piProcInfo.hProcess;
\r
8492 cp->pid = piProcInfo.dwProcessId;
\r
8493 cp->hFrom = hChildStdoutRdDup;
\r
8494 cp->hTo = hChildStdinWrDup;
\r
8496 *pr = (void *) cp;
\r
8498 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
8499 2000 where engines sometimes don't see the initial command(s)
\r
8500 from WinBoard and hang. I don't understand how that can happen,
\r
8501 but the Sleep is harmless, so I've put it in. Others have also
\r
8502 reported what may be the same problem, so hopefully this will fix
\r
8503 it for them too. */
\r
8511 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
8515 cp = (ChildProc *) pr;
\r
8516 if (cp == NULL) return;
\r
8518 switch (cp->kind) {
\r
8520 /* TerminateProcess is considered harmful, so... */
\r
8521 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
8522 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
8523 /* The following doesn't work because the chess program
\r
8524 doesn't "have the same console" as WinBoard. Maybe
\r
8525 we could arrange for this even though neither WinBoard
\r
8526 nor the chess program uses a console for stdio? */
\r
8527 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
8529 /* [AS] Special termination modes for misbehaving programs... */
8531 if ( appData.debugMode) {
8532 fprintf( debugFP, "Terminating process %u\n", cp->pid );
8535 TerminateProcess( cp->hProcess, 0 );
8537 else if( signal == 10 ) {
8538 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
8540 if( dw != WAIT_OBJECT_0 ) {
8541 if ( appData.debugMode) {
8542 fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
8545 TerminateProcess( cp->hProcess, 0 );
8549 CloseHandle(cp->hProcess);
\r
8553 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
8557 closesocket(cp->sock);
\r
8562 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
8563 closesocket(cp->sock);
\r
8564 closesocket(cp->sock2);
\r
8572 InterruptChildProcess(ProcRef pr)
\r
8576 cp = (ChildProc *) pr;
\r
8577 if (cp == NULL) return;
\r
8578 switch (cp->kind) {
\r
8580 /* The following doesn't work because the chess program
\r
8581 doesn't "have the same console" as WinBoard. Maybe
\r
8582 we could arrange for this even though neither WinBoard
\r
8583 nor the chess program uses a console for stdio */
\r
8584 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
8589 /* Can't interrupt */
\r
8593 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
8600 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
8602 char cmdLine[MSG_SIZ];
\r
8604 if (port[0] == NULLCHAR) {
\r
8605 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
8607 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
8609 return StartChildProcess(cmdLine, "", pr);
\r
8613 /* Code to open TCP sockets */
\r
8616 OpenTCP(char *host, char *port, ProcRef *pr)
\r
8621 struct sockaddr_in sa, mysa;
\r
8622 struct hostent FAR *hp;
\r
8623 unsigned short uport;
\r
8624 WORD wVersionRequested;
\r
8627 /* Initialize socket DLL */
\r
8628 wVersionRequested = MAKEWORD(1, 1);
\r
8629 err = WSAStartup(wVersionRequested, &wsaData);
\r
8630 if (err != 0) return err;
\r
8633 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8634 err = WSAGetLastError();
\r
8639 /* Bind local address using (mostly) don't-care values.
\r
8641 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8642 mysa.sin_family = AF_INET;
\r
8643 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8644 uport = (unsigned short) 0;
\r
8645 mysa.sin_port = htons(uport);
\r
8646 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8647 == SOCKET_ERROR) {
\r
8648 err = WSAGetLastError();
\r
8653 /* Resolve remote host name */
\r
8654 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8655 if (!(hp = gethostbyname(host))) {
\r
8656 unsigned int b0, b1, b2, b3;
\r
8658 err = WSAGetLastError();
\r
8660 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8661 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8662 hp->h_addrtype = AF_INET;
\r
8664 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8665 hp->h_addr_list[0] = (char *) malloc(4);
\r
8666 hp->h_addr_list[0][0] = (char) b0;
\r
8667 hp->h_addr_list[0][1] = (char) b1;
\r
8668 hp->h_addr_list[0][2] = (char) b2;
\r
8669 hp->h_addr_list[0][3] = (char) b3;
\r
8675 sa.sin_family = hp->h_addrtype;
\r
8676 uport = (unsigned short) atoi(port);
\r
8677 sa.sin_port = htons(uport);
\r
8678 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8680 /* Make connection */
\r
8681 if (connect(s, (struct sockaddr *) &sa,
\r
8682 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8683 err = WSAGetLastError();
\r
8688 /* Prepare return value */
\r
8689 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8690 cp->kind = CPSock;
\r
8692 *pr = (ProcRef *) cp;
\r
8698 OpenCommPort(char *name, ProcRef *pr)
\r
8703 char fullname[MSG_SIZ];
\r
8705 if (*name != '\\')
\r
8706 sprintf(fullname, "\\\\.\\%s", name);
\r
8708 strcpy(fullname, name);
\r
8710 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
8711 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
8712 if (h == (HANDLE) -1) {
\r
8713 return GetLastError();
\r
8717 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
8719 /* Accumulate characters until a 100ms pause, then parse */
\r
8720 ct.ReadIntervalTimeout = 100;
\r
8721 ct.ReadTotalTimeoutMultiplier = 0;
\r
8722 ct.ReadTotalTimeoutConstant = 0;
\r
8723 ct.WriteTotalTimeoutMultiplier = 0;
\r
8724 ct.WriteTotalTimeoutConstant = 0;
\r
8725 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
8727 /* Prepare return value */
\r
8728 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8729 cp->kind = CPComm;
\r
8732 *pr = (ProcRef *) cp;
\r
8738 OpenLoopback(ProcRef *pr)
\r
8740 DisplayFatalError("Not implemented", 0, 1);
\r
8746 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
8751 struct sockaddr_in sa, mysa;
\r
8752 struct hostent FAR *hp;
\r
8753 unsigned short uport;
\r
8754 WORD wVersionRequested;
\r
8757 char stderrPortStr[MSG_SIZ];
\r
8759 /* Initialize socket DLL */
\r
8760 wVersionRequested = MAKEWORD(1, 1);
\r
8761 err = WSAStartup(wVersionRequested, &wsaData);
\r
8762 if (err != 0) return err;
\r
8764 /* Resolve remote host name */
\r
8765 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8766 if (!(hp = gethostbyname(host))) {
\r
8767 unsigned int b0, b1, b2, b3;
\r
8769 err = WSAGetLastError();
\r
8771 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8772 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8773 hp->h_addrtype = AF_INET;
\r
8775 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8776 hp->h_addr_list[0] = (char *) malloc(4);
\r
8777 hp->h_addr_list[0][0] = (char) b0;
\r
8778 hp->h_addr_list[0][1] = (char) b1;
\r
8779 hp->h_addr_list[0][2] = (char) b2;
\r
8780 hp->h_addr_list[0][3] = (char) b3;
\r
8786 sa.sin_family = hp->h_addrtype;
\r
8787 uport = (unsigned short) 514;
\r
8788 sa.sin_port = htons(uport);
\r
8789 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8791 /* Bind local socket to unused "privileged" port address
\r
8793 s = INVALID_SOCKET;
\r
8794 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8795 mysa.sin_family = AF_INET;
\r
8796 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8797 for (fromPort = 1023;; fromPort--) {
\r
8798 if (fromPort < 0) {
\r
8800 return WSAEADDRINUSE;
\r
8802 if (s == INVALID_SOCKET) {
\r
8803 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8804 err = WSAGetLastError();
\r
8809 uport = (unsigned short) fromPort;
\r
8810 mysa.sin_port = htons(uport);
\r
8811 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8812 == SOCKET_ERROR) {
\r
8813 err = WSAGetLastError();
\r
8814 if (err == WSAEADDRINUSE) continue;
\r
8818 if (connect(s, (struct sockaddr *) &sa,
\r
8819 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8820 err = WSAGetLastError();
\r
8821 if (err == WSAEADDRINUSE) {
\r
8832 /* Bind stderr local socket to unused "privileged" port address
\r
8834 s2 = INVALID_SOCKET;
\r
8835 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8836 mysa.sin_family = AF_INET;
\r
8837 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8838 for (fromPort = 1023;; fromPort--) {
\r
8839 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
8840 if (fromPort < 0) {
\r
8841 (void) closesocket(s);
\r
8843 return WSAEADDRINUSE;
\r
8845 if (s2 == INVALID_SOCKET) {
\r
8846 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8847 err = WSAGetLastError();
\r
8853 uport = (unsigned short) fromPort;
\r
8854 mysa.sin_port = htons(uport);
\r
8855 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8856 == SOCKET_ERROR) {
\r
8857 err = WSAGetLastError();
\r
8858 if (err == WSAEADDRINUSE) continue;
\r
8859 (void) closesocket(s);
\r
8863 if (listen(s2, 1) == SOCKET_ERROR) {
\r
8864 err = WSAGetLastError();
\r
8865 if (err == WSAEADDRINUSE) {
\r
8867 s2 = INVALID_SOCKET;
\r
8870 (void) closesocket(s);
\r
8871 (void) closesocket(s2);
\r
8877 prevStderrPort = fromPort; // remember port used
\r
8878 sprintf(stderrPortStr, "%d", fromPort);
\r
8880 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
8881 err = WSAGetLastError();
\r
8882 (void) closesocket(s);
\r
8883 (void) closesocket(s2);
\r
8888 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
8889 err = WSAGetLastError();
\r
8890 (void) closesocket(s);
\r
8891 (void) closesocket(s2);
\r
8895 if (*user == NULLCHAR) user = UserName();
\r
8896 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
8897 err = WSAGetLastError();
\r
8898 (void) closesocket(s);
\r
8899 (void) closesocket(s2);
\r
8903 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
8904 err = WSAGetLastError();
\r
8905 (void) closesocket(s);
\r
8906 (void) closesocket(s2);
\r
8911 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
8912 err = WSAGetLastError();
\r
8913 (void) closesocket(s);
\r
8914 (void) closesocket(s2);
\r
8918 (void) closesocket(s2); /* Stop listening */
\r
8920 /* Prepare return value */
\r
8921 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8922 cp->kind = CPRcmd;
\r
8925 *pr = (ProcRef *) cp;
\r
8932 AddInputSource(ProcRef pr, int lineByLine,
\r
8933 InputCallback func, VOIDSTAR closure)
\r
8935 InputSource *is, *is2 = NULL;
8936 ChildProc *cp = (ChildProc *) pr;
\r
8938 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
8939 is->lineByLine = lineByLine;
\r
8941 is->closure = closure;
\r
8942 is->second = NULL;
\r
8943 is->next = is->buf;
\r
8944 if (pr == NoProc) {
\r
8945 is->kind = CPReal;
\r
8946 consoleInputSource = is;
\r
8948 is->kind = cp->kind;
\r
8950 [AS] Try to avoid a race condition if the thread is given control too early:
8951 we create all threads suspended so that the is->hThread variable can be
8952 safely assigned, then let the threads start with ResumeThread.
8954 switch (cp->kind) {
\r
8956 is->hFile = cp->hFrom;
\r
8957 cp->hFrom = NULL; /* now owned by InputThread */
\r
8959 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
8960 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8964 is->hFile = cp->hFrom;
\r
8965 cp->hFrom = NULL; /* now owned by InputThread */
\r
8967 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
8968 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8972 is->sock = cp->sock;
\r
8974 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8975 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8979 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
8981 is->sock = cp->sock;
\r
8983 is2->sock = cp->sock2;
\r
8984 is2->second = is2;
\r
8986 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8987 (LPVOID) is, CREATE_SUSPENDED, &is->id);
8989 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8990 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
8994 if( is->hThread != NULL ) {
8995 ResumeThread( is->hThread );
8998 if( is2 != NULL && is2->hThread != NULL ) {
8999 ResumeThread( is2->hThread );
9003 return (InputSourceRef) is;
\r
9007 RemoveInputSource(InputSourceRef isr)
\r
9011 is = (InputSource *) isr;
\r
9012 is->hThread = NULL; /* tell thread to stop */
\r
9013 CloseHandle(is->hThread);
\r
9014 if (is->second != NULL) {
\r
9015 is->second->hThread = NULL;
\r
9016 CloseHandle(is->second->hThread);
\r
9022 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9025 int outCount = SOCKET_ERROR;
\r
9026 ChildProc *cp = (ChildProc *) pr;
\r
9027 static OVERLAPPED ovl;
\r
9029 if (pr == NoProc) {
\r
9030 ConsoleOutput(message, count, FALSE);
\r
9034 if (ovl.hEvent == NULL) {
\r
9035 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9037 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9039 switch (cp->kind) {
\r
9042 outCount = send(cp->sock, message, count, 0);
\r
9043 if (outCount == SOCKET_ERROR) {
\r
9044 *outError = WSAGetLastError();
\r
9046 *outError = NO_ERROR;
\r
9051 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9052 &dOutCount, NULL)) {
\r
9053 *outError = NO_ERROR;
\r
9054 outCount = (int) dOutCount;
\r
9056 *outError = GetLastError();
\r
9061 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9062 &dOutCount, &ovl);
\r
9063 if (*outError == NO_ERROR) {
\r
9064 outCount = (int) dOutCount;
\r
9072 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9075 /* Ignore delay, not implemented for WinBoard */
\r
9076 return OutputToProcess(pr, message, count, outError);
\r
9081 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9082 char *buf, int count, int error)
\r
9084 DisplayFatalError("Not implemented", 0, 1);
\r
9087 /* see wgamelist.c for Game List functions */
\r
9088 /* see wedittags.c for Edit Tags functions */
\r
9095 char buf[MSG_SIZ];
\r
9098 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9099 f = fopen(buf, "r");
\r
9101 ProcessICSInitScript(f);
\r
9109 StartAnalysisClock()
\r
9111 if (analysisTimerEvent) return;
\r
9112 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9113 (UINT) 2000, NULL);
\r
9117 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9119 static HANDLE hwndText;
\r
9121 static int sizeX, sizeY;
\r
9122 int newSizeX, newSizeY, flags;
\r
9125 switch (message) {
\r
9126 case WM_INITDIALOG: /* message: initialize dialog box */
\r
9127 /* Initialize the dialog items */
\r
9128 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
9129 SetWindowText(hDlg, analysisTitle);
\r
9130 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
9131 /* Size and position the dialog */
\r
9132 if (!analysisDialog) {
\r
9133 analysisDialog = hDlg;
\r
9134 flags = SWP_NOZORDER;
\r
9135 GetClientRect(hDlg, &rect);
\r
9136 sizeX = rect.right;
\r
9137 sizeY = rect.bottom;
\r
9138 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
9139 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
9140 WINDOWPLACEMENT wp;
\r
9141 EnsureOnScreen(&analysisX, &analysisY);
\r
9142 wp.length = sizeof(WINDOWPLACEMENT);
\r
9144 wp.showCmd = SW_SHOW;
\r
9145 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
9146 wp.rcNormalPosition.left = analysisX;
\r
9147 wp.rcNormalPosition.right = analysisX + analysisW;
\r
9148 wp.rcNormalPosition.top = analysisY;
\r
9149 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
9150 SetWindowPlacement(hDlg, &wp);
\r
9152 GetClientRect(hDlg, &rect);
\r
9153 newSizeX = rect.right;
\r
9154 newSizeY = rect.bottom;
\r
9155 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
9156 newSizeX, newSizeY);
\r
9163 case WM_COMMAND: /* message: received a command */
\r
9164 switch (LOWORD(wParam)) {
\r
9174 newSizeX = LOWORD(lParam);
\r
9175 newSizeY = HIWORD(lParam);
\r
9176 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
9181 case WM_GETMINMAXINFO:
\r
9182 /* Prevent resizing window too small */
\r
9183 mmi = (MINMAXINFO *) lParam;
\r
9184 mmi->ptMinTrackSize.x = 100;
\r
9185 mmi->ptMinTrackSize.y = 100;
\r
9192 AnalysisPopUp(char* title, char* str)
\r
9198 EngineOutputPopUp();
9201 if (str == NULL) str = "";
\r
9202 p = (char *) malloc(2 * strlen(str) + 2);
\r
9205 if (*str == '\n') *q++ = '\r';
\r
9209 if (analysisText != NULL) free(analysisText);
\r
9212 if (analysisDialog) {
\r
9213 SetWindowText(analysisDialog, title);
\r
9214 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
9215 ShowWindow(analysisDialog, SW_SHOW);
\r
9217 analysisTitle = title;
\r
9218 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
9219 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
9220 hwndMain, (DLGPROC)lpProc);
\r
9221 FreeProcInstance(lpProc);
\r
9223 analysisDialogUp = TRUE;
\r
9229 if (analysisDialog) {
\r
9230 ShowWindow(analysisDialog, SW_HIDE);
\r
9232 analysisDialogUp = FALSE;
\r
9237 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9239 highlightInfo.sq[0].x = fromX;
\r
9240 highlightInfo.sq[0].y = fromY;
\r
9241 highlightInfo.sq[1].x = toX;
\r
9242 highlightInfo.sq[1].y = toY;
\r
9248 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9249 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9253 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9255 premoveHighlightInfo.sq[0].x = fromX;
\r
9256 premoveHighlightInfo.sq[0].y = fromY;
\r
9257 premoveHighlightInfo.sq[1].x = toX;
\r
9258 premoveHighlightInfo.sq[1].y = toY;
\r
9262 ClearPremoveHighlights()
\r
9264 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9265 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9269 ShutDownFrontEnd()
\r
9271 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9272 DeleteClipboardTempFiles();
\r
9278 if (IsIconic(hwndMain))
\r
9279 ShowWindow(hwndMain, SW_RESTORE);
\r
9281 SetActiveWindow(hwndMain);
\r
9285 * Prototypes for animation support routines
\r
9287 static void ScreenSquare(int column, int row, POINT * pt);
\r
9288 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9289 POINT frames[], int * nFrames);
\r
9295 AnimateMove(board, fromX, fromY, toX, toY)
\r
9302 ChessSquare piece;
\r
9303 POINT start, finish, mid;
\r
9304 POINT frames[kFactor * 2 + 1];
\r
9307 if (!appData.animate) return;
\r
9308 if (doingSizing) return;
\r
9309 if (fromY < 0 || fromX < 0) return;
\r
9310 piece = board[fromY][fromX];
\r
9311 if (piece >= EmptySquare) return;
\r
9313 ScreenSquare(fromX, fromY, &start);
\r
9314 ScreenSquare(toX, toY, &finish);
\r
9316 /* All pieces except knights move in straight line */
\r
9317 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9318 mid.x = start.x + (finish.x - start.x) / 2;
\r
9319 mid.y = start.y + (finish.y - start.y) / 2;
\r
9321 /* Knight: make diagonal movement then straight */
\r
9322 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9323 mid.x = start.x + (finish.x - start.x) / 2;
\r
9327 mid.y = start.y + (finish.y - start.y) / 2;
\r
9331 /* Don't use as many frames for very short moves */
\r
9332 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9333 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9335 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9337 animInfo.from.x = fromX;
\r
9338 animInfo.from.y = fromY;
\r
9339 animInfo.to.x = toX;
\r
9340 animInfo.to.y = toY;
\r
9341 animInfo.lastpos = start;
\r
9342 animInfo.piece = piece;
\r
9343 for (n = 0; n < nFrames; n++) {
\r
9344 animInfo.pos = frames[n];
\r
9345 DrawPosition(FALSE, NULL);
\r
9346 animInfo.lastpos = animInfo.pos;
\r
9347 Sleep(appData.animSpeed);
\r
9349 animInfo.pos = finish;
\r
9350 DrawPosition(FALSE, NULL);
\r
9351 animInfo.piece = EmptySquare;
\r
9354 /* Convert board position to corner of screen rect and color */
\r
9357 ScreenSquare(column, row, pt)
\r
9358 int column; int row; POINT * pt;
\r
9361 pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
9362 pt->y = lineGap + row * (squareSize + lineGap);
\r
9364 pt->x = lineGap + column * (squareSize + lineGap);
\r
9365 pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
9369 /* Generate a series of frame coords from start->mid->finish.
\r
9370 The movement rate doubles until the half way point is
\r
9371 reached, then halves back down to the final destination,
\r
9372 which gives a nice slow in/out effect. The algorithmn
\r
9373 may seem to generate too many intermediates for short
\r
9374 moves, but remember that the purpose is to attract the
\r
9375 viewers attention to the piece about to be moved and
\r
9376 then to where it ends up. Too few frames would be less
\r
9380 Tween(start, mid, finish, factor, frames, nFrames)
\r
9381 POINT * start; POINT * mid;
\r
9382 POINT * finish; int factor;
\r
9383 POINT frames[]; int * nFrames;
\r
9385 int n, fraction = 1, count = 0;
\r
9387 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9388 for (n = 0; n < factor; n++)
\r
9390 for (n = 0; n < factor; n++) {
\r
9391 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9392 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9394 fraction = fraction / 2;
\r
9398 frames[count] = *mid;
\r
9401 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9403 for (n = 0; n < factor; n++) {
\r
9404 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9405 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9407 fraction = fraction * 2;
\r
9413 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
9418 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
9419 first, last, current, current >= 0 ? movelist[current] : "n/a" );
9421 OutputDebugString( buf );
9424 MoveHistorySet( movelist, first, last, current, pvInfoList );
9426 EvalGraphSet( first, last, current, pvInfoList );
9429 void SetProgramStats( int which, int depth, unsigned long nodes, int score, int time, char * pv )
9434 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
9435 which, depth, nodes, score / 100.0, time / 100.0, pv == 0 ? "n/a" : pv );
9437 OutputDebugString( buf );
9440 EngineOutputUpdate( which, depth, nodes, score, time, pv );