2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "frontend.h"
\r
84 #include "backend.h"
\r
85 #include "winboard.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "woptions.h"
\r
89 #include "wsockerr.h"
\r
90 #include "defaults.h"
\r
94 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
97 void mysrandom(unsigned int seed);
\r
99 extern int whiteFlag, blackFlag;
\r
100 Boolean flipClock = FALSE;
\r
101 extern HANDLE chatHandle[];
\r
102 extern int ics_type;
\r
104 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
105 VOID NewVariantPopup(HWND hwnd);
\r
106 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
107 /*char*/int promoChar));
\r
108 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
109 void DisplayMove P((int moveNumber));
\r
110 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
111 void ChatPopUp P(());
\r
113 ChessSquare piece;
\r
114 POINT pos; /* window coordinates of current pos */
\r
115 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
116 POINT from; /* board coordinates of the piece's orig pos */
\r
117 POINT to; /* board coordinates of the piece's new pos */
\r
120 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
123 POINT start; /* window coordinates of start pos */
\r
124 POINT pos; /* window coordinates of current pos */
\r
125 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
126 POINT from; /* board coordinates of the piece's orig pos */
\r
129 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
132 POINT sq[2]; /* board coordinates of from, to squares */
\r
135 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
136 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 typedef struct { // [HGM] atomic
\r
139 int fromX, fromY, toX, toY, radius;
\r
142 static ExplodeInfo explodeInfo;
\r
144 /* Window class names */
\r
145 char szAppName[] = "WinBoard";
\r
146 char szConsoleName[] = "WBConsole";
\r
148 /* Title bar text */
\r
149 char szTitle[] = "WinBoard";
\r
150 char szConsoleTitle[] = "I C S Interaction";
\r
153 char *settingsFileName;
\r
154 BOOLEAN saveSettingsOnExit;
\r
155 char installDir[MSG_SIZ];
\r
157 BoardSize boardSize;
\r
158 BOOLEAN chessProgram;
\r
159 //static int boardX, boardY;
\r
160 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
161 static int squareSize, lineGap, minorSize;
\r
162 static int winW, winH;
\r
163 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
164 static int logoHeight = 0;
\r
165 static char messageText[MESSAGE_TEXT_MAX];
\r
166 static int clockTimerEvent = 0;
\r
167 static int loadGameTimerEvent = 0;
\r
168 static int analysisTimerEvent = 0;
\r
169 static DelayedEventCallback delayedTimerCallback;
\r
170 static int delayedTimerEvent = 0;
\r
171 static int buttonCount = 2;
\r
172 char *icsTextMenuString;
\r
174 char *firstChessProgramNames;
\r
175 char *secondChessProgramNames;
\r
177 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
179 #define PALETTESIZE 256
\r
181 HINSTANCE hInst; /* current instance */
\r
182 BOOLEAN alwaysOnTop = FALSE;
\r
184 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
185 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
187 ColorClass currentColorClass;
\r
189 HWND hCommPort = NULL; /* currently open comm port */
\r
190 static HWND hwndPause; /* pause button */
\r
191 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
192 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
193 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
194 explodeBrush, /* [HGM] atomic */
\r
195 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
196 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
197 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
198 static HPEN gridPen = NULL;
\r
199 static HPEN highlightPen = NULL;
\r
200 static HPEN premovePen = NULL;
\r
201 static NPLOGPALETTE pLogPal;
\r
202 static BOOL paletteChanged = FALSE;
\r
203 static HICON iconWhite, iconBlack, iconCurrent;
\r
204 static int doingSizing = FALSE;
\r
205 static int lastSizing = 0;
\r
206 static int prevStderrPort;
\r
207 static HBITMAP userLogo;
\r
209 /* [AS] Support for background textures */
\r
210 #define BACK_TEXTURE_MODE_DISABLED 0
\r
211 #define BACK_TEXTURE_MODE_PLAIN 1
\r
212 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
214 static HBITMAP liteBackTexture = NULL;
\r
215 static HBITMAP darkBackTexture = NULL;
\r
216 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
217 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
218 static int backTextureSquareSize = 0;
\r
219 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
221 #if __GNUC__ && !defined(_winmajor)
\r
222 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
224 #if defined(_winmajor)
\r
225 #define oldDialog (_winmajor < 4)
\r
227 #define oldDialog 0
\r
231 char *defaultTextAttribs[] =
\r
233 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
234 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
244 int cliWidth, cliHeight;
\r
247 SizeInfo sizeInfo[] =
\r
249 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
250 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
251 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
252 { "petite", 33, 1, 1, 1, 0, 0 },
\r
253 { "slim", 37, 2, 1, 0, 0, 0 },
\r
254 { "small", 40, 2, 1, 0, 0, 0 },
\r
255 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
256 { "middling", 49, 2, 0, 0, 0, 0 },
\r
257 { "average", 54, 2, 0, 0, 0, 0 },
\r
258 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
259 { "medium", 64, 3, 0, 0, 0, 0 },
\r
260 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
261 { "large", 80, 3, 0, 0, 0, 0 },
\r
262 { "big", 87, 3, 0, 0, 0, 0 },
\r
263 { "huge", 95, 3, 0, 0, 0, 0 },
\r
264 { "giant", 108, 3, 0, 0, 0, 0 },
\r
265 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
266 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
267 { NULL, 0, 0, 0, 0, 0, 0 }
\r
270 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
271 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
273 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
274 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
275 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
276 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
277 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
278 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
279 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
280 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
281 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
282 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
283 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
284 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
285 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
286 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
287 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
288 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
289 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
290 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
293 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
302 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
303 #define N_BUTTONS 5
\r
305 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
307 {"<<", IDM_ToStart, NULL, NULL},
\r
308 {"<", IDM_Backward, NULL, NULL},
\r
309 {"P", IDM_Pause, NULL, NULL},
\r
310 {">", IDM_Forward, NULL, NULL},
\r
311 {">>", IDM_ToEnd, NULL, NULL},
\r
314 int tinyLayout = 0, smallLayout = 0;
\r
315 #define MENU_BAR_ITEMS 7
\r
316 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
317 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
318 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
322 MySound sounds[(int)NSoundClasses];
\r
323 MyTextAttribs textAttribs[(int)NColorClasses];
\r
325 MyColorizeAttribs colorizeAttribs[] = {
\r
326 { (COLORREF)0, 0, "Shout Text" },
\r
327 { (COLORREF)0, 0, "SShout/CShout" },
\r
328 { (COLORREF)0, 0, "Channel 1 Text" },
\r
329 { (COLORREF)0, 0, "Channel Text" },
\r
330 { (COLORREF)0, 0, "Kibitz Text" },
\r
331 { (COLORREF)0, 0, "Tell Text" },
\r
332 { (COLORREF)0, 0, "Challenge Text" },
\r
333 { (COLORREF)0, 0, "Request Text" },
\r
334 { (COLORREF)0, 0, "Seek Text" },
\r
335 { (COLORREF)0, 0, "Normal Text" },
\r
336 { (COLORREF)0, 0, "None" }
\r
341 static char *commentTitle;
\r
342 static char *commentText;
\r
343 static int commentIndex;
\r
344 static Boolean editComment = FALSE;
\r
347 char errorTitle[MSG_SIZ];
\r
348 char errorMessage[2*MSG_SIZ];
\r
349 HWND errorDialog = NULL;
\r
350 BOOLEAN moveErrorMessageUp = FALSE;
\r
351 BOOLEAN consoleEcho = TRUE;
\r
352 CHARFORMAT consoleCF;
\r
353 COLORREF consoleBackgroundColor;
\r
355 char *programVersion;
\r
361 typedef int CPKind;
\r
370 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
373 #define INPUT_SOURCE_BUF_SIZE 4096
\r
375 typedef struct _InputSource {
\r
382 char buf[INPUT_SOURCE_BUF_SIZE];
\r
386 InputCallback func;
\r
387 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
391 InputSource *consoleInputSource;
\r
396 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
397 VOID ConsoleCreate();
\r
399 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
400 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
401 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
402 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
404 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
405 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
406 void ParseIcsTextMenu(char *icsTextMenuString);
\r
407 VOID PopUpMoveDialog(char firstchar);
\r
408 VOID PopUpNameDialog(char firstchar);
\r
409 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
413 int GameListOptions();
\r
415 int dummy; // [HGM] for obsolete args
\r
417 HWND hwndMain = NULL; /* root window*/
\r
418 HWND hwndConsole = NULL;
\r
419 HWND commentDialog = NULL;
\r
420 HWND moveHistoryDialog = NULL;
\r
421 HWND evalGraphDialog = NULL;
\r
422 HWND engineOutputDialog = NULL;
\r
423 HWND gameListDialog = NULL;
\r
424 HWND editTagsDialog = NULL;
\r
426 int commentUp = FALSE;
\r
428 WindowPlacement wpMain;
\r
429 WindowPlacement wpConsole;
\r
430 WindowPlacement wpComment;
\r
431 WindowPlacement wpMoveHistory;
\r
432 WindowPlacement wpEvalGraph;
\r
433 WindowPlacement wpEngineOutput;
\r
434 WindowPlacement wpGameList;
\r
435 WindowPlacement wpTags;
\r
437 VOID EngineOptionsPopup(); // [HGM] settings
\r
439 VOID GothicPopUp(char *title, VariantClass variant);
\r
441 * Setting "frozen" should disable all user input other than deleting
\r
442 * the window. We do this while engines are initializing themselves.
\r
444 static int frozen = 0;
\r
445 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
451 if (frozen) return;
\r
453 hmenu = GetMenu(hwndMain);
\r
454 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
455 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
457 DrawMenuBar(hwndMain);
\r
460 /* Undo a FreezeUI */
\r
466 if (!frozen) return;
\r
468 hmenu = GetMenu(hwndMain);
\r
469 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
470 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
472 DrawMenuBar(hwndMain);
\r
475 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
477 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
483 #define JAWS_ALT_INTERCEPT
\r
484 #define JAWS_KB_NAVIGATION
\r
485 #define JAWS_MENU_ITEMS
\r
486 #define JAWS_SILENCE
\r
487 #define JAWS_REPLAY
\r
489 #define JAWS_COPYRIGHT
\r
490 #define JAWS_DELETE(X) X
\r
491 #define SAYMACHINEMOVE()
\r
495 /*---------------------------------------------------------------------------*\
\r
499 \*---------------------------------------------------------------------------*/
\r
502 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
503 LPSTR lpCmdLine, int nCmdShow)
\r
506 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
507 // INITCOMMONCONTROLSEX ex;
\r
511 LoadLibrary("RICHED32.DLL");
\r
512 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
514 if (!InitApplication(hInstance)) {
\r
517 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
523 // InitCommonControlsEx(&ex);
\r
524 InitCommonControls();
\r
526 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
527 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
528 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
530 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
532 while (GetMessage(&msg, /* message structure */
\r
533 NULL, /* handle of window receiving the message */
\r
534 0, /* lowest message to examine */
\r
535 0)) /* highest message to examine */
\r
538 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
539 // [HGM] navigate: switch between all windows with tab
\r
540 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
541 int i, currentElement = 0;
\r
543 // first determine what element of the chain we come from (if any)
\r
544 if(appData.icsActive) {
\r
545 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
546 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
548 if(engineOutputDialog && EngineOutputIsUp()) {
\r
549 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
550 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
552 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
553 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
555 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
556 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
557 if(msg.hwnd == e1) currentElement = 2; else
\r
558 if(msg.hwnd == e2) currentElement = 3; else
\r
559 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
560 if(msg.hwnd == mh) currentElement = 4; else
\r
561 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
562 if(msg.hwnd == hText) currentElement = 5; else
\r
563 if(msg.hwnd == hInput) currentElement = 6; else
\r
564 for (i = 0; i < N_BUTTONS; i++) {
\r
565 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
568 // determine where to go to
\r
569 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
571 currentElement = (currentElement + direction) % 7;
\r
572 switch(currentElement) {
\r
574 h = hwndMain; break; // passing this case always makes the loop exit
\r
576 h = buttonDesc[0].hwnd; break; // could be NULL
\r
578 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
581 if(!EngineOutputIsUp()) continue;
\r
584 if(!MoveHistoryIsUp()) continue;
\r
586 // case 6: // input to eval graph does not seem to get here!
\r
587 // if(!EvalGraphIsUp()) continue;
\r
588 // h = evalGraphDialog; break;
\r
590 if(!appData.icsActive) continue;
\r
594 if(!appData.icsActive) continue;
\r
600 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
601 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
604 continue; // this message now has been processed
\r
608 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
609 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
610 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
611 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
612 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
613 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
614 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
615 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
616 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
617 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
618 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
619 for(i=0; i<MAX_CHAT; i++)
\r
620 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
623 if(done) continue; // [HGM] chat: end patch
\r
624 TranslateMessage(&msg); /* Translates virtual key codes */
\r
625 DispatchMessage(&msg); /* Dispatches message to window */
\r
630 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
633 /*---------------------------------------------------------------------------*\
\r
635 * Initialization functions
\r
637 \*---------------------------------------------------------------------------*/
\r
641 { // update user logo if necessary
\r
642 static char oldUserName[MSG_SIZ], *curName;
\r
644 if(appData.autoLogo) {
\r
645 curName = UserName();
\r
646 if(strcmp(curName, oldUserName)) {
\r
647 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
648 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
649 strcpy(oldUserName, curName);
\r
655 InitApplication(HINSTANCE hInstance)
\r
659 /* Fill in window class structure with parameters that describe the */
\r
662 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
663 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
664 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
665 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
666 wc.hInstance = hInstance; /* Owner of this class */
\r
667 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
668 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
669 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
670 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
671 wc.lpszClassName = szAppName; /* Name to register as */
\r
673 /* Register the window class and return success/failure code. */
\r
674 if (!RegisterClass(&wc)) return FALSE;
\r
676 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
677 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
679 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
680 wc.hInstance = hInstance;
\r
681 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
682 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
683 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
684 wc.lpszMenuName = NULL;
\r
685 wc.lpszClassName = szConsoleName;
\r
687 if (!RegisterClass(&wc)) return FALSE;
\r
692 /* Set by InitInstance, used by EnsureOnScreen */
\r
693 int screenHeight, screenWidth;
\r
696 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
698 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
699 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
700 if (*x > screenWidth - 32) *x = 0;
\r
701 if (*y > screenHeight - 32) *y = 0;
\r
702 if (*x < minX) *x = minX;
\r
703 if (*y < minY) *y = minY;
\r
707 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
709 HWND hwnd; /* Main window handle. */
\r
711 WINDOWPLACEMENT wp;
\r
714 hInst = hInstance; /* Store instance handle in our global variable */
\r
716 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
717 *filepart = NULLCHAR;
\r
719 GetCurrentDirectory(MSG_SIZ, installDir);
\r
721 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
722 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
723 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
724 if (appData.debugMode) {
\r
725 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
726 setbuf(debugFP, NULL);
\r
731 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
732 // InitEngineUCI( installDir, &second );
\r
734 /* Create a main window for this application instance. */
\r
735 hwnd = CreateWindow(szAppName, szTitle,
\r
736 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
737 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
738 NULL, NULL, hInstance, NULL);
\r
741 /* If window could not be created, return "failure" */
\r
746 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
747 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
748 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
750 if (first.programLogo == NULL && appData.debugMode) {
\r
751 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
753 } else if(appData.autoLogo) {
\r
754 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
756 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
757 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
761 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
762 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
764 if (second.programLogo == NULL && appData.debugMode) {
\r
765 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
767 } else if(appData.autoLogo) {
\r
769 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
770 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
771 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
773 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
774 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
775 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
781 iconWhite = LoadIcon(hInstance, "icon_white");
\r
782 iconBlack = LoadIcon(hInstance, "icon_black");
\r
783 iconCurrent = iconWhite;
\r
784 InitDrawingColors();
\r
785 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
786 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
787 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
788 /* Compute window size for each board size, and use the largest
\r
789 size that fits on this screen as the default. */
\r
790 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
791 if (boardSize == (BoardSize)-1 &&
\r
792 winH <= screenHeight
\r
793 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
794 && winW <= screenWidth) {
\r
795 boardSize = (BoardSize)ibs;
\r
799 InitDrawingSizes(boardSize, 0);
\r
801 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
803 /* [AS] Load textures if specified */
\r
804 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
806 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
807 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
808 liteBackTextureMode = appData.liteBackTextureMode;
\r
810 if (liteBackTexture == NULL && appData.debugMode) {
\r
811 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
815 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
816 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
817 darkBackTextureMode = appData.darkBackTextureMode;
\r
819 if (darkBackTexture == NULL && appData.debugMode) {
\r
820 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
824 mysrandom( (unsigned) time(NULL) );
\r
826 /* [AS] Restore layout */
\r
827 if( wpMoveHistory.visible ) {
\r
828 MoveHistoryPopUp();
\r
831 if( wpEvalGraph.visible ) {
\r
835 if( wpEngineOutput.visible ) {
\r
836 EngineOutputPopUp();
\r
841 /* Make the window visible; update its client area; and return "success" */
\r
842 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
843 wp.length = sizeof(WINDOWPLACEMENT);
\r
845 wp.showCmd = nCmdShow;
\r
846 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
847 wp.rcNormalPosition.left = wpMain.x;
\r
848 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
849 wp.rcNormalPosition.top = wpMain.y;
\r
850 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
851 SetWindowPlacement(hwndMain, &wp);
\r
853 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
854 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
858 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
859 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
861 ShowWindow(hwndConsole, nCmdShow);
\r
863 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
864 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
872 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
873 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
874 ArgSettingsFilename,
\r
875 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
878 typedef void *ArgIniType;
\r
879 #define INVALID (ArgIniType) 6915 /* Some number unlikely to be needed as default for anything */
\r
886 String *pString; // ArgString
\r
887 int *pInt; // ArgInt
\r
888 float *pFloat; // ArgFloat
\r
889 Boolean *pBoolean; // ArgBoolean
\r
890 COLORREF *pColor; // ArgColor
\r
891 ColorClass cc; // ArgAttribs
\r
892 String *pFilename; // ArgFilename
\r
893 BoardSize *pBoardSize; // ArgBoardSize
\r
894 int whichFont; // ArgFont
\r
895 DCB *pDCB; // ArgCommSettings
\r
896 String *pFilename; // ArgSettingsFilename
\r
901 ArgIniType defaultValue;
\r
906 #define XBOARD FALSE
\r
908 ArgDescriptor argDescriptors[] = {
\r
909 /* positional arguments */
\r
910 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE, INVALID },
\r
911 { "", ArgNone, NULL, FALSE, INVALID },
\r
912 /* keyword arguments */
\r
914 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE, INVALID },
\r
915 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE, INVALID },
\r
916 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE, INVALID },
\r
917 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE, INVALID },
\r
918 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE, INVALID },
\r
919 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE, INVALID },
\r
920 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE, INVALID },
\r
921 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE, INVALID },
\r
922 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE, INVALID },
\r
923 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE, INVALID },
\r
924 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE, INVALID },
\r
925 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE, INVALID },
\r
926 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE, (ArgIniType) MOVES_PER_SESSION },
\r
927 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE, INVALID },
\r
928 { "initString", ArgString, (LPVOID) &appData.initString, FALSE, INVALID },
\r
929 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE, (ArgIniType) INIT_STRING },
\r
930 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE, (ArgIniType) INIT_STRING },
\r
931 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
932 FALSE, (ArgIniType) COMPUTER_STRING },
\r
933 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
934 FALSE, (ArgIniType) COMPUTER_STRING },
\r
935 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
936 FALSE, (ArgIniType) FIRST_CHESS_PROGRAM },
\r
937 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE, INVALID },
\r
938 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
939 FALSE, (ArgIniType) SECOND_CHESS_PROGRAM },
\r
940 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE, INVALID },
\r
941 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE, FALSE },
\r
942 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE, FALSE },
\r
943 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE, INVALID },
\r
944 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE, INVALID },
\r
945 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE, FALSE },
\r
946 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE, INVALID },
\r
947 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE, INVALID },
\r
948 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE, INVALID },
\r
949 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE, (ArgIniType) FIRST_HOST },
\r
950 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE, INVALID },
\r
951 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE, (ArgIniType) SECOND_HOST },
\r
952 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE, INVALID },
\r
953 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE, (ArgIniType) FIRST_DIRECTORY },
\r
954 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE, INVALID },
\r
955 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE, (ArgIniType) SECOND_DIRECTORY },
\r
956 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE, INVALID },
\r
958 /* some options only used by the XBoard front end, and ignored in WinBoard */
\r
959 /* Their saving is controlled by XBOARD, which in WinBoard is defined as FALSE */
\r
960 { "internetChessServerInputBox", ArgBoolean, (LPVOID) &appData.icsInputBox, XBOARD, (ArgIniType) FALSE },
\r
961 { "icsinput", ArgTrue, (LPVOID) &appData.icsInputBox, FALSE, INVALID },
\r
962 { "xicsinput", ArgFalse, (LPVOID) &appData.icsInputBox, FALSE, INVALID },
\r
963 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE, (ArgIniType) "" },
\r
964 { "soundProgram", ArgFilename, (LPVOID) &appData.soundProgram, XBOARD, (ArgIniType) "play" },
\r
965 { "fontSizeTolerance", ArgInt, (LPVOID) &appData.fontSizeTolerance, XBOARD, (ArgIniType) 4 },
\r
966 { "lowTimeWarningColor", ArgColor, (LPVOID) &appData.lowTimeWarningColor, XBOARD,
\r
967 (ArgIniType) LOWTIMEWARNING_COLOR },
\r
968 { "lowTimeWarning", ArgBoolean, (LPVOID) &appData.lowTimeWarning, XBOARD, (ArgIniType) FALSE },
\r
969 { "titleInWindow", ArgBoolean, (LPVOID) &appData.titleInWindow, XBOARD, (ArgIniType) FALSE },
\r
970 { "title", ArgTrue, (LPVOID) &appData.titleInWindow, FALSE, INVALID },
\r
971 { "xtitle", ArgFalse, (LPVOID) &appData.titleInWindow, FALSE, INVALID },
\r
972 { "flashCount", ArgInt, (LPVOID) &appData.flashCount, XBOARD, (ArgIniType) FLASH_COUNT },
\r
973 { "flashRate", ArgInt, (LPVOID) &appData.flashRate, XBOARD, (ArgIniType) FLASH_RATE },
\r
974 { "pixmapDirectory", ArgFilename, (LPVOID) &appData.pixmapDirectory, XBOARD, (ArgIniType) "" },
\r
975 { "pixmap", ArgFilename, (LPVOID) &appData.pixmapDirectory, FALSE, INVALID },
\r
976 { "bitmapDirectory", ArgFilename, (LPVOID) &appData.bitmapDirectory, XBOARD, (ArgIniType) "" },
\r
977 { "bm", ArgFilename, (LPVOID) &appData.bitmapDirectory, FALSE, INVALID },
\r
978 { "msLoginDelay", ArgInt, (LPVOID) &appData.msLoginDelay, XBOARD, (ArgIniType) MS_LOGIN_DELAY },
\r
979 { "pasteSelection", ArgBoolean, (LPVOID) &appData.pasteSelection, XBOARD, (ArgIniType) FALSE },
\r
981 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE, (ArgIniType) REMOTE_SHELL },
\r
982 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE, INVALID },
\r
983 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE, INVALID },
\r
984 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE, INVALID },
\r
985 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE, INVALID },
\r
986 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE, INVALID },
\r
987 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE, (ArgIniType) TIME_CONTROL },
\r
988 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE, INVALID },
\r
989 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE, (ArgIniType) TIME_INCREMENT },
\r
990 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE, INVALID },
\r
991 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE, INVALID },
\r
992 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE, (ArgIniType) FALSE },
\r
993 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE, INVALID },
\r
994 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE, INVALID },
\r
995 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE, (ArgIniType) "" },
\r
996 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE, INVALID },
\r
997 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE, (ArgIniType) ICS_PORT },
\r
998 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE, INVALID },
\r
999 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE, (ArgIniType) ICS_COMM_PORT },
\r
1000 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE, INVALID },
\r
1001 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE, INVALID },
\r
1002 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE, INVALID },
\r
1003 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE, (ArgIniType) ICS_LOGON },
\r
1004 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE, INVALID },
\r
1005 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE, INVALID },
\r
1006 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE, INVALID },
\r
1007 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE, INVALID },
\r
1008 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE, INVALID },
\r
1009 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE, (ArgIniType) TELNET_PROGRAM },
\r
1010 { "internetChessserverHelper", ArgFilename, (LPVOID) &appData.icsHelper,
\r
1011 FALSE, INVALID }, // for XB
\r
1012 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE, (ArgIniType) "" },
\r
1013 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE, (ArgIniType) "" },
\r
1014 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE, (ArgIniType) "" },
\r
1015 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE, INVALID },
\r
1016 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE, (ArgIniType) 0 },
\r
1017 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE, INVALID },
\r
1018 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE, (ArgIniType) "" },
\r
1019 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE, INVALID },
\r
1020 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE, (ArgIniType) FALSE },
\r
1021 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE, INVALID },
\r
1022 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE, INVALID },
\r
1023 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE, INVALID },
\r
1024 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE, (ArgIniType) "" },
\r
1025 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE, INVALID },
\r
1026 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE, (ArgIniType) 1 },
\r
1027 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE, INVALID },
\r
1028 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE, (ArgIniType) "" },
\r
1029 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE, INVALID },
\r
1030 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE, (ArgIniType) FALSE },
\r
1031 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE, INVALID },
\r
1032 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE, INVALID },
\r
1033 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE, INVALID },
\r
1034 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE, (ArgIniType) 0 },
\r
1035 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE, INVALID },
\r
1036 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE, (ArgIniType) FALSE },
\r
1037 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE, INVALID },
\r
1038 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE, INVALID },
\r
1039 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE, INVALID },
\r
1040 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE, (ArgIniType) FALSE },
\r
1041 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE, INVALID },
\r
1042 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE, INVALID },
\r
1043 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE, INVALID },
\r
1044 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE, (ArgIniType) TRUE },
\r
1045 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE, INVALID },
\r
1046 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE, INVALID },
\r
1047 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE, INVALID },
\r
1048 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE, (ArgIniType) "" },
\r
1049 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE, INVALID },
\r
1050 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE, (ArgIniType) 0 },
\r
1051 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE, INVALID },
\r
1052 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE, (ArgIniType) FALSE },
\r
1053 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE, INVALID },
\r
1054 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE, INVALID },
\r
1055 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE, INVALID },
\r
1056 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE, (ArgIniType) FALSE },
\r
1057 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE, INVALID },
\r
1058 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE, INVALID },
\r
1059 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE, INVALID },
\r
1060 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE, (ArgIniType) TRUE },
\r
1061 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE, INVALID },
\r
1062 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE, INVALID },
\r
1063 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE, INVALID },
\r
1064 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE, (ArgIniType) TRUE },
\r
1065 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE, INVALID },
\r
1066 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE, INVALID },
\r
1067 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE, INVALID },
\r
1068 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE, (ArgIniType) TRUE },
\r
1069 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE, INVALID },
\r
1070 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE, INVALID },
\r
1071 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE, INVALID },
\r
1072 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE, (ArgIniType) FALSE },
\r
1073 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE, INVALID },
\r
1074 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE, INVALID },
\r
1075 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE, INVALID },
\r
1076 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1077 FALSE, INVALID }, /* only so that old WinBoard.ini files from betas can be read */
\r
1078 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE, INVALID },
\r
1079 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE, INVALID },
\r
1080 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE, INVALID },
\r
1081 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE, INVALID },
\r
1082 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE, INVALID },
\r
1083 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE, INVALID },
\r
1084 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE, INVALID }, /* [AS] */
\r
1085 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1086 TRUE, (ArgIniType) -1 }, /* must come after all fonts */
\r
1087 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE, INVALID },
\r
1088 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1089 FALSE, (ArgIniType) TRUE }, /* historical; kept only so old winboard.ini files will parse */
\r
1090 { "bell", ArgTrue, (LPVOID) &appData.ringBellAfterMoves, FALSE, INVALID }, // for XB
\r
1091 { "xbell", ArgFalse, (LPVOID) &appData.ringBellAfterMoves, FALSE, INVALID }, // for XB
\r
1092 { "movesound", ArgTrue, (LPVOID) &appData.ringBellAfterMoves, FALSE, INVALID }, // for XB
\r
1093 { "xmovesound", ArgFalse, (LPVOID) &appData.ringBellAfterMoves, FALSE, INVALID }, // for XB
\r
1094 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE, INVALID },
\r
1095 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE, INVALID },
\r
1096 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE, INVALID },
\r
1097 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE, INVALID },
\r
1098 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE, (ArgIniType) FALSE },
\r
1099 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE, INVALID },
\r
1100 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE, INVALID },
\r
1101 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE, INVALID },
\r
1102 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE, (ArgIniType) FALSE },
\r
1103 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE, INVALID },
\r
1104 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE, INVALID },
\r
1105 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE, INVALID },
\r
1106 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE, (ArgIniType) FALSE },
\r
1107 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE, INVALID },
\r
1108 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE, INVALID },
\r
1109 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE, INVALID },
\r
1110 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE, (ArgIniType) FALSE },
\r
1111 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE, INVALID },
\r
1112 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE, INVALID },
\r
1113 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE, INVALID },
\r
1114 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE, (ArgIniType) TRUE },
\r
1115 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE, INVALID },
\r
1116 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE, INVALID },
\r
1117 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE, INVALID },
\r
1118 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE, (ArgIniType) TRUE },
\r
1119 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE, INVALID },
\r
1120 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE, INVALID },
\r
1121 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE, INVALID },
\r
1122 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE, (ArgIniType) FALSE },
\r
1123 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE, INVALID },
\r
1124 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE, INVALID },
\r
1125 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE, INVALID },
\r
1126 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE, (ArgIniType) FALSE },
\r
1127 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE, INVALID },
\r
1128 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE, INVALID },
\r
1129 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE, INVALID },
\r
1130 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE, (ArgIniType) FALSE },
\r
1131 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE, INVALID },
\r
1132 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE, INVALID },
\r
1133 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE, INVALID },
\r
1134 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE, (ArgIniType) TRUE },
\r
1135 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE, INVALID },
\r
1136 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE, INVALID },
\r
1137 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE, INVALID },
\r
1138 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE, (ArgIniType) TRUE },
\r
1139 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE, INVALID },
\r
1140 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE, INVALID },
\r
1141 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE, INVALID },
\r
1142 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE, (ArgIniType) TRUE },
\r
1143 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE, INVALID },
\r
1144 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE, INVALID },
\r
1145 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE, INVALID },
\r
1146 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE, (ArgIniType) FALSE },
\r
1147 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE, INVALID },
\r
1148 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE, INVALID },
\r
1149 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE, INVALID },
\r
1150 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE, (ArgIniType) "" },
\r
1151 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE, (ArgIniType) FALSE },
\r
1152 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE, INVALID },
\r
1153 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE, INVALID },
\r
1154 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE, INVALID },
\r
1155 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE, (ArgIniType) "" },
\r
1156 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE, (ArgIniType) TRUE},
\r
1157 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1158 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1159 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1160 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE, (ArgIniType) 5000},
\r
1161 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE, (ArgIniType) TRUE},
\r
1162 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE, INVALID },
\r
1163 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE, INVALID },
\r
1164 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE, INVALID },
\r
1165 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE, (ArgIniType) TRUE },
\r
1166 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE, INVALID },
\r
1167 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE, INVALID },
\r
1168 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE, INVALID },
\r
1169 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE, (ArgIniType) 10 },
\r
1170 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE, (ArgIniType) TRUE },
\r
1171 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE, INVALID },
\r
1172 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE, INVALID },
\r
1173 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE, INVALID },
\r
1174 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE, (ArgIniType) FALSE },
\r
1175 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE, INVALID },
\r
1176 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE, INVALID },
\r
1177 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE, INVALID },
\r
1178 { "highlightLastMove", ArgBoolean,
\r
1179 (LPVOID) &appData.highlightLastMove, TRUE, (ArgIniType) TRUE },
\r
1180 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE, INVALID },
\r
1181 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE, INVALID },
\r
1182 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE, INVALID },
\r
1183 { "highlightDragging", ArgBoolean,
\r
1184 (LPVOID) &appData.highlightDragging, TRUE, INVALID },
\r
1185 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE, INVALID },
\r
1186 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE, INVALID },
\r
1187 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE, INVALID },
\r
1188 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE, (ArgIniType) TRUE },
\r
1189 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE, INVALID },
\r
1190 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE, INVALID },
\r
1191 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE, INVALID },
\r
1192 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE, INVALID },
\r
1193 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE, INVALID },
\r
1194 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE, INVALID },
\r
1195 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE, INVALID },
\r
1196 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE, INVALID },
\r
1197 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE, INVALID },
\r
1198 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE, INVALID },
\r
1199 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE, INVALID },
\r
1200 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE, INVALID },
\r
1201 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE, INVALID },
\r
1202 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE, INVALID },
\r
1203 { "soundShout", ArgFilename, (LPVOID) &appData.soundShout, TRUE, (ArgIniType) "" },
\r
1204 { "soundSShout", ArgFilename, (LPVOID) &appData.soundSShout, TRUE, (ArgIniType) "" },
\r
1205 { "soundCShout", ArgFilename, (LPVOID) &appData.soundSShout, TRUE, (ArgIniType) "" }, // for XB
\r
1206 { "soundChannel1", ArgFilename, (LPVOID) &appData.soundChannel1, TRUE, (ArgIniType) "" },
\r
1207 { "soundChannel", ArgFilename, (LPVOID) &appData.soundChannel, TRUE, (ArgIniType) "" },
\r
1208 { "soundKibitz", ArgFilename, (LPVOID) &appData.soundKibitz, TRUE, (ArgIniType) "" },
\r
1209 { "soundTell", ArgFilename, (LPVOID) &appData.soundTell, TRUE, (ArgIniType) "" },
\r
1210 { "soundChallenge", ArgFilename, (LPVOID) &appData.soundChallenge, TRUE, (ArgIniType) "" },
\r
1211 { "soundRequest", ArgFilename, (LPVOID) &appData.soundRequest, TRUE, (ArgIniType) "" },
\r
1212 { "soundSeek", ArgFilename, (LPVOID) &appData.soundSeek, TRUE, (ArgIniType) "" },
\r
1213 { "soundMove", ArgFilename, (LPVOID) &appData.soundMove, TRUE, (ArgIniType) "" },
\r
1214 { "soundBell", ArgFilename, (LPVOID) &appData.soundBell, TRUE, (ArgIniType) SOUND_BELL },
\r
1215 { "soundIcsWin", ArgFilename, (LPVOID) &appData.soundIcsWin, TRUE, (ArgIniType) "" },
\r
1216 { "soundIcsLoss", ArgFilename, (LPVOID) &appData.soundIcsLoss, TRUE, (ArgIniType) "" },
\r
1217 { "soundIcsDraw", ArgFilename, (LPVOID) &appData.soundIcsDraw, TRUE, (ArgIniType) "" },
\r
1218 { "soundIcsUnfinished", ArgFilename, (LPVOID) &appData.soundIcsUnfinished, TRUE, (ArgIniType) "" },
\r
1219 { "soundIcsAlarm", ArgFilename, (LPVOID) &appData.soundIcsAlarm, TRUE, (ArgIniType) "" },
\r
1220 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE, (ArgIniType) TRUE },
\r
1221 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE, INVALID },
\r
1222 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE, INVALID },
\r
1223 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE, INVALID },
\r
1224 { "reuseChessPrograms", ArgBoolean,
\r
1225 (LPVOID) &appData.reuseFirst, FALSE, INVALID }, /* backward compat only */
\r
1226 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE, (ArgIniType) TRUE },
\r
1227 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE, INVALID },
\r
1228 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE, INVALID },
\r
1229 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE, INVALID },
\r
1230 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE, INVALID },
\r
1231 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE, (ArgIniType) SETTINGS_FILE },
\r
1232 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE, INVALID },
\r
1233 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE, (ArgIniType) TRUE },
\r
1234 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE, (ArgIniType) FALSE },
\r
1235 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE, INVALID },
\r
1236 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE, INVALID },
\r
1237 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE, INVALID },
\r
1238 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE, (ArgIniType) ICS_TEXT_MENU_DEFAULT },
\r
1239 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE, (ArgIniType) ICS_NAMES },
\r
1240 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1241 TRUE, (ArgIniType) FCP_NAMES },
\r
1242 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1243 TRUE, (ArgIniType) SCP_NAMES },
\r
1244 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE, (ArgIniType) "" },
\r
1245 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE, INVALID },
\r
1246 { "variant", ArgString, (LPVOID) &appData.variant, FALSE, (ArgIniType) "normal" },
\r
1247 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE, (ArgIniType) PROTOVER },
\r
1248 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE, (ArgIniType) PROTOVER },
\r
1249 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE, (ArgIniType) TRUE },
\r
1250 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE, INVALID },
\r
1251 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE, INVALID },
\r
1252 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE, INVALID },
\r
1254 /* [AS] New features */
\r
1255 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE, (ArgIniType) FALSE },
\r
1256 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE, (ArgIniType) FALSE },
\r
1257 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE, (ArgIniType) FALSE },
\r
1258 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE, (ArgIniType) FALSE },
\r
1259 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE, (ArgIniType) "" },
\r
1260 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE, (ArgIniType) "" },
\r
1261 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE, (ArgIniType) BACK_TEXTURE_MODE_PLAIN },
\r
1262 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE, (ArgIniType) BACK_TEXTURE_MODE_PLAIN },
\r
1263 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE, (ArgIniType) "" },
\r
1264 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE, (ArgIniType) "" },
\r
1265 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE, (ArgIniType) 0 },
\r
1266 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE, (ArgIniType) 0 },
\r
1267 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE, (ArgIniType) 0 },
\r
1268 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE, (ArgIniType) 0 },
\r
1269 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE, (ArgIniType) 80 },
\r
1270 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE, (ArgIniType) 1 },
\r
1271 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE, (ArgIniType) 0 },
\r
1272 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE, (ArgIniType) 0 },
\r
1273 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE, (ArgIniType) 0 },
\r
1274 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE, (ArgIniType) "winboard.debug" },
\r
1275 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE, INVALID },
\r
1276 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE, (ArgIniType) "Computer Chess Game" },
\r
1277 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE, (ArgIniType) -1 },
\r
1278 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE, (ArgIniType) GLT_DEFAULT_TAGS },
\r
1279 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE, (ArgIniType) TRUE },
\r
1280 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE, (ArgIniType) TRUE },
\r
1281 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE, INVALID },
\r
1282 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE, INVALID },
\r
1283 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE, (ArgIniType) FALSE },
\r
1284 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE, INVALID },
\r
1285 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE, (ArgIniType) TRUE },
\r
1286 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE, (ArgIniType) TRUE },
\r
1287 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE, (ArgIniType) TRUE },
\r
1288 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE, (ArgIniType) TRUE },
\r
1289 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE, (ArgIniType) FALSE },
\r
1290 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE, INVALID },
\r
1291 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE, (ArgIniType) FALSE },
\r
1292 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE, INVALID },
\r
1293 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE, (ArgIniType) TRUE },
\r
1294 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE, INVALID },
\r
1295 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE, INVALID },
\r
1296 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE, (ArgIniType) TRUE },
\r
1297 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE, INVALID },
\r
1298 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE, INVALID },
\r
1299 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE, (ArgIniType) "" },
\r
1300 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE, (ArgIniType) FALSE },
\r
1301 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE, (ArgIniType) "" },
\r
1302 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE, (ArgIniType) 64 },
\r
1303 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE, (ArgIniType) 4 },
\r
1304 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE, (ArgIniType) "c:\\egtb" },
\r
1306 /* [HGM] board-size, adjudication and misc. options */
\r
1307 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE, (ArgIniType) -1 },
\r
1308 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE, (ArgIniType) -1 },
\r
1309 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE, (ArgIniType) -1 },
\r
1310 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE, (ArgIniType) 10000 },
\r
1311 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE, INVALID },
\r
1312 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE, (ArgIniType) FALSE },
\r
1313 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE, (ArgIniType) FALSE },
\r
1314 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE, (ArgIniType) FALSE },
\r
1315 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE, (ArgIniType) FALSE },
\r
1316 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE, (ArgIniType) FALSE },
\r
1317 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE, (ArgIniType) FALSE },
\r
1318 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE, (ArgIniType) FALSE },
\r
1319 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE, (ArgIniType) FALSE },
\r
1320 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE, (ArgIniType) FALSE },
\r
1321 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE, (ArgIniType) 51 },
\r
1322 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE, (ArgIniType) 6 },
\r
1323 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE, INVALID },
\r
1324 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE, (ArgIniType) 1 },
\r
1325 { "userName", ArgString, (LPVOID) &appData.userName, FALSE, INVALID },
\r
1326 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE, INVALID },
\r
1327 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE, INVALID },
\r
1328 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE, (ArgIniType) 1 },
\r
1329 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE, (ArgIniType) "" },
\r
1330 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE, INVALID },
\r
1331 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE, INVALID },
\r
1332 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE, INVALID },
\r
1333 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE, INVALID },
\r
1334 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE, (ArgIniType) "" },
\r
1335 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE, (ArgIniType) "" },
\r
1336 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE, (ArgIniType) "" },
\r
1337 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE, (ArgIniType) "" },
\r
1338 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE, INVALID },
\r
1339 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE, INVALID },
\r
1340 { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE, INVALID },
\r
1343 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE, (ArgIniType) ZIPPY_TALK },
\r
1344 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE, INVALID },
\r
1345 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE, INVALID },
\r
1346 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE, INVALID },
\r
1347 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE, (ArgIniType) ZIPPY_PLAY },
\r
1348 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE, INVALID },
\r
1349 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE, INVALID },
\r
1350 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE, INVALID },
\r
1351 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE, (ArgIniType) ZIPPY_LINES },
\r
1352 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE, (ArgIniType) ZIPPY_PINHEAD },
\r
1353 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE, (ArgIniType) ZIPPY_PASSWORD },
\r
1354 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE, (ArgIniType) ZIPPY_PASSWORD2 },
\r
1355 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1356 FALSE, (ArgIniType) ZIPPY_WRONG_PASSWORD },
\r
1357 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE, (ArgIniType) ZIPPY_ACCEPT_ONLY },
\r
1358 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE, (ArgIniType) ZIPPY_USE_I },
\r
1359 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE, INVALID },
\r
1360 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE, INVALID },
\r
1361 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE, INVALID },
\r
1362 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE, (ArgIniType) ZIPPY_BUGHOUSE },
\r
1363 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1364 FALSE, (ArgIniType) ZIPPY_NOPLAY_CRAFTY },
\r
1365 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE, INVALID },
\r
1366 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE, INVALID },
\r
1367 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE, INVALID },
\r
1368 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE, (ArgIniType) ZIPPY_GAME_END },
\r
1369 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE, (ArgIniType) ZIPPY_GAME_START },
\r
1370 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE, (ArgIniType) ZIPPY_ADJOURN },
\r
1371 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE, INVALID },
\r
1372 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE, INVALID },
\r
1373 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE, INVALID },
\r
1374 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE, (ArgIniType) ZIPPY_ABORT },
\r
1375 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE, INVALID },
\r
1376 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE, INVALID },
\r
1377 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE, INVALID },
\r
1378 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE, (ArgIniType) ZIPPY_VARIANTS },
\r
1379 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE, (ArgIniType) ZIPPY_MAX_GAMES},
\r
1380 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE, (ArgIniType) ZIPPY_REPLAY_TIMEOUT },
\r
1381 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE, INVALID },
\r
1382 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1383 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE, INVALID },
\r
1385 /* [HGM] options for broadcasting and time odds */
\r
1386 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE, (ArgIniType) NULL },
\r
1387 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE, (ArgIniType) FALSE },
\r
1388 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE, (ArgIniType) 15 },
\r
1389 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE, (ArgIniType) 1 },
\r
1390 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE, (ArgIniType) 1 },
\r
1391 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE, INVALID },
\r
1392 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE, (ArgIniType) 1 },
\r
1393 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE, (ArgIniType) 1 },
\r
1394 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE, (ArgIniType) -1 },
\r
1395 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE, (ArgIniType) -1 },
\r
1396 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE, INVALID },
\r
1397 { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE, INVALID },
\r
1398 { "wrapContinuationSequence", ArgString, (LPVOID) &appData.wrapContSeq, FALSE, INVALID },
\r
1399 { "useInternalWrap", ArgTrue, (LPVOID) &appData.useInternalWrap, FALSE, INVALID }, /* noJoin usurps this if set */
\r
1401 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1402 { "minX", ArgZ, (LPVOID) &minX, FALSE, INVALID }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1403 { "minY", ArgZ, (LPVOID) &minY, FALSE, INVALID },
\r
1404 { "winWidth", ArgInt, (LPVOID) &wpMain.width, TRUE, INVALID }, // [HGM] placement: dummies to remember right & bottom
\r
1405 { "winHeight", ArgInt, (LPVOID) &wpMain.height, TRUE, INVALID }, // for attaching auxiliary windows to them
\r
1406 { "x", ArgInt, (LPVOID) &wpMain.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1407 { "y", ArgInt, (LPVOID) &wpMain.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1408 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1409 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1410 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1411 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1412 { "analysisX", ArgX, (LPVOID) &dummy, FALSE, INVALID }, // [HGM] placement: analysis window no longer exists
\r
1413 { "analysisY", ArgY, (LPVOID) &dummy, FALSE, INVALID }, // provided for compatibility with old ini files
\r
1414 { "analysisW", ArgInt, (LPVOID) &dummy, FALSE, INVALID },
\r
1415 { "analysisH", ArgInt, (LPVOID) &dummy, FALSE, INVALID },
\r
1416 { "commentX", ArgX, (LPVOID) &wpComment.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1417 { "commentY", ArgY, (LPVOID) &wpComment.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1418 { "commentW", ArgInt, (LPVOID) &wpComment.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1419 { "commentH", ArgInt, (LPVOID) &wpComment.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1420 { "tagsX", ArgX, (LPVOID) &wpTags.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1421 { "tagsY", ArgY, (LPVOID) &wpTags.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1422 { "tagsW", ArgInt, (LPVOID) &wpTags.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1423 { "tagsH", ArgInt, (LPVOID) &wpTags.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1424 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1425 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1426 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1427 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1428 /* [AS] Layout stuff */
\r
1429 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE, (ArgIniType) TRUE },
\r
1430 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1431 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1432 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1433 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1435 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE, (ArgIniType) TRUE },
\r
1436 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1437 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1438 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1439 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1441 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE, (ArgIniType) TRUE },
\r
1442 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1443 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1444 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1445 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1447 { NULL, ArgNone, NULL, FALSE, INVALID }
\r
1451 /* Kludge for indirection files on command line */
\r
1452 char* lastIndirectionFilename;
\r
1453 ArgDescriptor argDescriptorIndirection =
\r
1454 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1458 ExitArgError(char *msg, char *badArg)
\r
1460 char buf[MSG_SIZ];
\r
1462 sprintf(buf, "%s %s", msg, badArg);
\r
1463 DisplayFatalError(buf, 0, 2);
\r
1467 /* Command line font name parser. NULL name means do nothing.
\r
1468 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1469 For backward compatibility, syntax without the colon is also
\r
1470 accepted, but font names with digits in them won't work in that case.
\r
1473 ParseFontName(char *name, MyFontParams *mfp)
\r
1476 if (name == NULL) return;
\r
1478 q = strchr(p, ':');
\r
1480 if (q - p >= sizeof(mfp->faceName))
\r
1481 ExitArgError("Font name too long:", name);
\r
1482 memcpy(mfp->faceName, p, q - p);
\r
1483 mfp->faceName[q - p] = NULLCHAR;
\r
1486 q = mfp->faceName;
\r
1487 while (*p && !isdigit(*p)) {
\r
1489 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1490 ExitArgError("Font name too long:", name);
\r
1492 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1495 if (!*p) ExitArgError("Font point size missing:", name);
\r
1496 mfp->pointSize = (float) atof(p);
\r
1497 mfp->bold = (strchr(p, 'b') != NULL);
\r
1498 mfp->italic = (strchr(p, 'i') != NULL);
\r
1499 mfp->underline = (strchr(p, 'u') != NULL);
\r
1500 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1501 mfp->charset = DEFAULT_CHARSET;
\r
1502 q = strchr(p, 'c');
\r
1504 mfp->charset = (BYTE) atoi(q+1);
\r
1507 /* Color name parser.
\r
1508 X version accepts X color names, but this one
\r
1509 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1511 ParseColorName(char *name)
\r
1513 int red, green, blue, count;
\r
1514 char buf[MSG_SIZ];
\r
1516 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1518 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1519 &red, &green, &blue);
\r
1522 sprintf(buf, "Can't parse color name %s", name);
\r
1523 DisplayError(buf, 0);
\r
1524 return RGB(0, 0, 0);
\r
1526 return PALETTERGB(red, green, blue);
\r
1530 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1532 char *e = argValue;
\r
1536 if (*e == 'b') eff |= CFE_BOLD;
\r
1537 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1538 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1539 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1540 else if (*e == '#' || isdigit(*e)) break;
\r
1544 *color = ParseColorName(e);
\r
1549 ParseBoardSize(char *name)
\r
1551 BoardSize bs = SizeTiny;
\r
1552 while (sizeInfo[bs].name != NULL) {
\r
1553 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1556 ExitArgError("Unrecognized board size value", name);
\r
1557 return bs; /* not reached */
\r
1562 StringGet(void *getClosure)
\r
1564 char **p = (char **) getClosure;
\r
1569 FileGet(void *getClosure)
\r
1572 FILE* f = (FILE*) getClosure;
\r
1575 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1582 /* Parse settings file named "name". If file found, return the
\r
1583 full name in fullname and return TRUE; else return FALSE */
\r
1585 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1589 int ok; char buf[MSG_SIZ];
\r
1591 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1592 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1593 sprintf(buf, "%s.ini", name);
\r
1594 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1597 f = fopen(fullname, "r");
\r
1599 ParseArgs(FileGet, f);
\r
1608 ParseArgs(GetFunc get, void *cl)
\r
1610 char argName[ARG_MAX];
\r
1611 char argValue[ARG_MAX];
\r
1612 ArgDescriptor *ad;
\r
1621 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1622 if (ch == NULLCHAR) break;
\r
1624 /* Comment to end of line */
\r
1626 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1628 } else if (ch == '/' || ch == '-') {
\r
1631 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1632 ch != '\n' && ch != '\t') {
\r
1638 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1639 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1641 if (ad->argName == NULL)
\r
1642 ExitArgError("Unrecognized argument", argName);
\r
1644 } else if (ch == '@') {
\r
1645 /* Indirection file */
\r
1646 ad = &argDescriptorIndirection;
\r
1649 /* Positional argument */
\r
1650 ad = &argDescriptors[posarg++];
\r
1651 strcpy(argName, ad->argName);
\r
1654 if (ad->argType == ArgTrue) {
\r
1655 *(Boolean *) ad->argLoc = TRUE;
\r
1658 if (ad->argType == ArgFalse) {
\r
1659 *(Boolean *) ad->argLoc = FALSE;
\r
1663 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1664 if (ch == NULLCHAR || ch == '\n') {
\r
1665 ExitArgError("No value provided for argument", argName);
\r
1669 // Quoting with { }. No characters have to (or can) be escaped.
\r
1670 // Thus the string cannot contain a '}' character.
\r
1690 } else if (ch == '\'' || ch == '"') {
\r
1691 // Quoting with ' ' or " ", with \ as escape character.
\r
1692 // Inconvenient for long strings that may contain Windows filenames.
\r
1709 if (ch == start) {
\r
1718 if (ad->argType == ArgFilename
\r
1719 || ad->argType == ArgSettingsFilename) {
\r
1725 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1749 for (i = 0; i < 3; i++) {
\r
1750 if (ch >= '0' && ch <= '7') {
\r
1751 octval = octval*8 + (ch - '0');
\r
1758 *q++ = (char) octval;
\r
1769 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1776 switch (ad->argType) {
\r
1778 *(int *) ad->argLoc = atoi(argValue);
\r
1782 *(int *) ad->argLoc = atoi(argValue) + wpMain.x; // [HGM] placement: translate stored relative to absolute
\r
1786 *(int *) ad->argLoc = atoi(argValue) + wpMain.y; // (this is really kludgey, it should be done where used...)
\r
1790 *(int *) ad->argLoc = atoi(argValue);
\r
1791 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1795 *(float *) ad->argLoc = (float) atof(argValue);
\r
1800 *(char **) ad->argLoc = strdup(argValue);
\r
1803 case ArgSettingsFilename:
\r
1805 char fullname[MSG_SIZ];
\r
1806 if (ParseSettingsFile(argValue, fullname)) {
\r
1807 if (ad->argLoc != NULL) {
\r
1808 *(char **) ad->argLoc = strdup(fullname);
\r
1811 if (ad->argLoc != NULL) {
\r
1813 ExitArgError("Failed to open indirection file", argValue);
\r
1820 switch (argValue[0]) {
\r
1823 *(Boolean *) ad->argLoc = TRUE;
\r
1827 *(Boolean *) ad->argLoc = FALSE;
\r
1830 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1836 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1839 case ArgAttribs: {
\r
1840 ColorClass cc = (ColorClass)ad->argLoc;
\r
1841 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1845 case ArgBoardSize:
\r
1846 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1850 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1853 case ArgCommSettings:
\r
1854 ParseCommSettings(argValue, &dcb);
\r
1858 ExitArgError("Unrecognized argument", argValue);
\r
1867 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1869 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1870 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1873 lf->lfEscapement = 0;
\r
1874 lf->lfOrientation = 0;
\r
1875 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1876 lf->lfItalic = mfp->italic;
\r
1877 lf->lfUnderline = mfp->underline;
\r
1878 lf->lfStrikeOut = mfp->strikeout;
\r
1879 lf->lfCharSet = mfp->charset;
\r
1880 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1881 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1882 lf->lfQuality = DEFAULT_QUALITY;
\r
1883 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1884 strcpy(lf->lfFaceName, mfp->faceName);
\r
1888 CreateFontInMF(MyFont *mf)
\r
1890 LFfromMFP(&mf->lf, &mf->mfp);
\r
1891 if (mf->hf) DeleteObject(mf->hf);
\r
1892 mf->hf = CreateFontIndirect(&mf->lf);
\r
1896 SetDefaultTextAttribs()
\r
1899 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1900 ParseAttribs(&textAttribs[cc].color,
\r
1901 &textAttribs[cc].effects,
\r
1902 defaultTextAttribs[cc]);
\r
1907 SetDefaultSounds()
\r
1908 { // [HGM] only sounds for which no option exists
\r
1910 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1911 textAttribs[cc].sound.name = strdup("");
\r
1912 textAttribs[cc].sound.data = NULL;
\r
1918 { // [HGM] import name from appData first
\r
1921 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1922 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1923 textAttribs[cc].sound.data = NULL;
\r
1924 MyLoadSound(&textAttribs[cc].sound);
\r
1926 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1927 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1928 sounds[sc].data = NULL;
\r
1929 MyLoadSound(&sounds[sc]);
\r
1934 SetDefaultsFromList()
\r
1935 { // [HGM] ini: take defaults from argDescriptor list
\r
1938 for(i=0; argDescriptors[i].argName != NULL; i++) {
\r
1939 if(argDescriptors[i].defaultValue != INVALID)
\r
1940 switch(argDescriptors[i].argType) {
\r
1944 *(Boolean *) argDescriptors[i].argLoc = (int)argDescriptors[i].defaultValue;
\r
1950 *(int *) argDescriptors[i].argLoc = (int)argDescriptors[i].defaultValue;
\r
1954 case ArgSettingsFilename:
\r
1955 *(char **) argDescriptors[i].argLoc = (char *)argDescriptors[i].defaultValue;
\r
1957 case ArgBoardSize:
\r
1958 *(BoardSize *) argDescriptors[i].argLoc = (BoardSize)argDescriptors[i].defaultValue;
\r
1960 case ArgFloat: // floats cannot be casted to int without precision loss
\r
1961 default: ; // some arg types cannot be initialized through table
\r
1967 InitAppData(LPSTR lpCmdLine)
\r
1970 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1973 programName = szAppName;
\r
1975 /* Initialize to defaults */
\r
1976 SetDefaultsFromList(); // this sets most defaults
\r
1978 // some parameters for which there are no options!
\r
1979 appData.Iconic = FALSE; /*unused*/
\r
1980 appData.cmailGameName = "";
\r
1981 appData.icsEngineAnalyze = FALSE;
\r
1983 // float: casting to int is not harmless, so default cannot be contained in table
\r
1984 appData.timeDelay = TIME_DELAY;
\r
1986 // colors have platform-dependent option format and internal representation
\r
1987 // their setting and parsing must remain in front-end
\r
1988 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1989 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1990 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1991 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1992 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1993 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1994 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1995 // the following must be moved out of appData to front-end variables
\r
1996 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1997 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1998 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2000 // some complex, platform-dependent stuff
\r
2001 SetDefaultTextAttribs();
\r
2002 SetDefaultSounds();
\r
2004 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2005 dcb.DCBlength = sizeof(DCB);
\r
2006 dcb.BaudRate = 9600;
\r
2007 dcb.fBinary = TRUE;
\r
2008 dcb.fParity = FALSE;
\r
2009 dcb.fOutxCtsFlow = FALSE;
\r
2010 dcb.fOutxDsrFlow = FALSE;
\r
2011 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2012 dcb.fDsrSensitivity = FALSE;
\r
2013 dcb.fTXContinueOnXoff = TRUE;
\r
2014 dcb.fOutX = FALSE;
\r
2016 dcb.fNull = FALSE;
\r
2017 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2018 dcb.fAbortOnError = FALSE;
\r
2020 dcb.Parity = SPACEPARITY;
\r
2021 dcb.StopBits = ONESTOPBIT;
\r
2023 /* Point font array elements to structures and
\r
2024 parse default font names */
\r
2025 for (i=0; i<NUM_FONTS; i++) {
\r
2026 for (j=0; j<NUM_SIZES; j++) {
\r
2027 font[j][i] = &fontRec[j][i];
\r
2028 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2032 /* Parse default settings file if any */
\r
2033 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2034 settingsFileName = strdup(buf);
\r
2037 /* Parse command line */
\r
2038 ParseArgs(StringGet, &lpCmdLine);
\r
2040 /* [HGM] make sure board size is acceptable */
\r
2041 if(appData.NrFiles > BOARD_FILES ||
\r
2042 appData.NrRanks > BOARD_RANKS )
\r
2043 DisplayFatalError("Recompile with BOARD_RANKS or BOARD_FILES, to support this size", 0, 2);
\r
2045 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2046 * with options from the command line, we now make an even higher priority
\r
2047 * overrule by WB options attached to the engine command line. This so that
\r
2048 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2051 if(appData.firstChessProgram != NULL) {
\r
2052 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2053 static char *f = "first";
\r
2054 char buf[MSG_SIZ], *q = buf;
\r
2055 if(p != NULL) { // engine command line contains WinBoard options
\r
2056 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2057 ParseArgs(StringGet, &q);
\r
2058 p[-1] = 0; // cut them offengine command line
\r
2061 // now do same for second chess program
\r
2062 if(appData.secondChessProgram != NULL) {
\r
2063 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2064 static char *s = "second";
\r
2065 char buf[MSG_SIZ], *q = buf;
\r
2066 if(p != NULL) { // engine command line contains WinBoard options
\r
2067 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2068 ParseArgs(StringGet, &q);
\r
2069 p[-1] = 0; // cut them offengine command line
\r
2074 /* Propagate options that affect others */
\r
2075 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2076 if (appData.icsActive || appData.noChessProgram) {
\r
2077 chessProgram = FALSE; /* not local chess program mode */
\r
2080 /* Open startup dialog if needed */
\r
2081 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2082 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2083 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2084 *appData.secondChessProgram == NULLCHAR))) {
\r
2087 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2088 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2089 FreeProcInstance(lpProc);
\r
2092 /* Make sure save files land in the right (?) directory */
\r
2093 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2094 appData.saveGameFile = strdup(buf);
\r
2096 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2097 appData.savePositionFile = strdup(buf);
\r
2100 /* Finish initialization for fonts and sounds */
\r
2101 for (i=0; i<NUM_FONTS; i++) {
\r
2102 for (j=0; j<NUM_SIZES; j++) {
\r
2103 CreateFontInMF(font[j][i]);
\r
2106 /* xboard, and older WinBoards, controlled the move sound with the
\r
2107 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2108 always turn the option on (so that the backend will call us),
\r
2109 then let the user turn the sound off by setting it to silence if
\r
2110 desired. To accommodate old winboard.ini files saved by old
\r
2111 versions of WinBoard, we also turn off the sound if the option
\r
2112 was initially set to false. */
\r
2113 if (!appData.ringBellAfterMoves) {
\r
2114 sounds[(int)SoundMove].name = strdup("");
\r
2115 appData.ringBellAfterMoves = TRUE;
\r
2117 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2118 SetCurrentDirectory(installDir);
\r
2120 SetCurrentDirectory(currDir);
\r
2122 p = icsTextMenuString;
\r
2123 if (p[0] == '@') {
\r
2124 FILE* f = fopen(p + 1, "r");
\r
2126 DisplayFatalError(p + 1, errno, 2);
\r
2129 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2131 buf[i] = NULLCHAR;
\r
2134 ParseIcsTextMenu(strdup(p));
\r
2141 HMENU hmenu = GetMenu(hwndMain);
\r
2143 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2144 MF_BYCOMMAND|((appData.icsActive &&
\r
2145 *appData.icsCommPort != NULLCHAR) ?
\r
2146 MF_ENABLED : MF_GRAYED));
\r
2147 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2148 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2149 MF_CHECKED : MF_UNCHECKED));
\r
2152 // [HGM] args: these three cases taken out to stay in front-end
\r
2154 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
2155 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
2156 // while the curent board size determines the element. This system should be ported to XBoard.
\r
2157 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
2159 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2160 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2161 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2162 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
2163 ad->argName, mfp->faceName, mfp->pointSize,
\r
2164 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2165 mfp->bold ? "b" : "",
\r
2166 mfp->italic ? "i" : "",
\r
2167 mfp->underline ? "u" : "",
\r
2168 mfp->strikeout ? "s" : "",
\r
2169 (int)mfp->charset);
\r
2175 { // [HGM] copy the names from the internal WB variables to appData
\r
2178 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
2179 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
2180 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
2181 (&appData.soundMove)[sc] = sounds[sc].name;
\r
2185 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
2186 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
2187 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2188 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2189 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2190 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2191 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2192 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2193 (ta->effects) ? " " : "",
\r
2194 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2198 SaveColor(FILE *f, ArgDescriptor *ad)
\r
2199 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
2200 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2201 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2202 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2207 { // [HGM] args: allows testing if main window is realized from back-end
\r
2208 return hwndMain != NULL;
\r
2212 SaveSettings(char* name)
\r
2215 ArgDescriptor *ad;
\r
2216 char dir[MSG_SIZ];
\r
2218 if (!MainWindowUp()) return;
\r
2220 GetCurrentDirectory(MSG_SIZ, dir);
\r
2221 SetCurrentDirectory(installDir);
\r
2222 f = fopen(name, "w");
\r
2223 SetCurrentDirectory(dir);
\r
2225 DisplayError(name, errno);
\r
2228 fprintf(f, ";\n");
\r
2229 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2230 fprintf(f, ";\n");
\r
2231 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2232 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2233 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2234 fprintf(f, ";\n");
\r
2236 GetActualPlacement(hwndMain, &wpMain);
\r
2237 GetActualPlacement(hwndConsole, &wpConsole);
\r
2238 GetActualPlacement(commentDialog, &wpComment);
\r
2239 GetActualPlacement(editTagsDialog, &wpTags);
\r
2240 GetActualPlacement(gameListDialog, &wpGameList);
\r
2242 /* [AS] Move history */
\r
2243 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2244 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
2246 /* [AS] Eval graph */
\r
2247 wpEvalGraph.visible = EvalGraphIsUp();
\r
2248 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
2250 /* [AS] Engine output */
\r
2251 wpEngineOutput.visible = EngineOutputIsUp();
\r
2252 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
2254 // [HGM] in WB we have to copy sound names to appData first
\r
2257 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2258 if (!ad->save) continue;
\r
2259 switch (ad->argType) {
\r
2262 char *p = *(char **)ad->argLoc;
\r
2263 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2264 /* Quote multiline values or \-containing values
\r
2265 with { } if possible */
\r
2266 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2268 /* Else quote with " " */
\r
2269 fprintf(f, "/%s=\"", ad->argName);
\r
2271 if (*p == '\n') fprintf(f, "\n");
\r
2272 else if (*p == '\r') fprintf(f, "\\r");
\r
2273 else if (*p == '\t') fprintf(f, "\\t");
\r
2274 else if (*p == '\b') fprintf(f, "\\b");
\r
2275 else if (*p == '\f') fprintf(f, "\\f");
\r
2276 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2277 else if (*p == '\"') fprintf(f, "\\\"");
\r
2278 else if (*p == '\\') fprintf(f, "\\\\");
\r
2282 fprintf(f, "\"\n");
\r
2288 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2291 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - wpMain.x); // [HGM] placement: stor relative value
\r
2294 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - wpMain.y);
\r
2297 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2300 fprintf(f, "/%s=%s\n", ad->argName,
\r
2301 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2304 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2307 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2315 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2316 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2318 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2321 case ArgBoardSize:
\r
2322 fprintf(f, "/%s=%s\n", ad->argName,
\r
2323 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2326 SaveFontArg(f, ad);
\r
2328 case ArgCommSettings:
\r
2329 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2331 case ArgSettingsFilename: ;
\r
2339 /*---------------------------------------------------------------------------*\
\r
2341 * GDI board drawing routines
\r
2343 \*---------------------------------------------------------------------------*/
\r
2345 /* [AS] Draw square using background texture */
\r
2346 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2351 return; /* Should never happen! */
\r
2354 SetGraphicsMode( dst, GM_ADVANCED );
\r
2361 /* X reflection */
\r
2366 x.eDx = (FLOAT) dw + dx - 1;
\r
2369 SetWorldTransform( dst, &x );
\r
2372 /* Y reflection */
\r
2378 x.eDy = (FLOAT) dh + dy - 1;
\r
2380 SetWorldTransform( dst, &x );
\r
2388 x.eDx = (FLOAT) dx;
\r
2389 x.eDy = (FLOAT) dy;
\r
2392 SetWorldTransform( dst, &x );
\r
2396 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2404 SetWorldTransform( dst, &x );
\r
2406 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2409 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2411 PM_WP = (int) WhitePawn,
\r
2412 PM_WN = (int) WhiteKnight,
\r
2413 PM_WB = (int) WhiteBishop,
\r
2414 PM_WR = (int) WhiteRook,
\r
2415 PM_WQ = (int) WhiteQueen,
\r
2416 PM_WF = (int) WhiteFerz,
\r
2417 PM_WW = (int) WhiteWazir,
\r
2418 PM_WE = (int) WhiteAlfil,
\r
2419 PM_WM = (int) WhiteMan,
\r
2420 PM_WO = (int) WhiteCannon,
\r
2421 PM_WU = (int) WhiteUnicorn,
\r
2422 PM_WH = (int) WhiteNightrider,
\r
2423 PM_WA = (int) WhiteAngel,
\r
2424 PM_WC = (int) WhiteMarshall,
\r
2425 PM_WAB = (int) WhiteCardinal,
\r
2426 PM_WD = (int) WhiteDragon,
\r
2427 PM_WL = (int) WhiteLance,
\r
2428 PM_WS = (int) WhiteCobra,
\r
2429 PM_WV = (int) WhiteFalcon,
\r
2430 PM_WSG = (int) WhiteSilver,
\r
2431 PM_WG = (int) WhiteGrasshopper,
\r
2432 PM_WK = (int) WhiteKing,
\r
2433 PM_BP = (int) BlackPawn,
\r
2434 PM_BN = (int) BlackKnight,
\r
2435 PM_BB = (int) BlackBishop,
\r
2436 PM_BR = (int) BlackRook,
\r
2437 PM_BQ = (int) BlackQueen,
\r
2438 PM_BF = (int) BlackFerz,
\r
2439 PM_BW = (int) BlackWazir,
\r
2440 PM_BE = (int) BlackAlfil,
\r
2441 PM_BM = (int) BlackMan,
\r
2442 PM_BO = (int) BlackCannon,
\r
2443 PM_BU = (int) BlackUnicorn,
\r
2444 PM_BH = (int) BlackNightrider,
\r
2445 PM_BA = (int) BlackAngel,
\r
2446 PM_BC = (int) BlackMarshall,
\r
2447 PM_BG = (int) BlackGrasshopper,
\r
2448 PM_BAB = (int) BlackCardinal,
\r
2449 PM_BD = (int) BlackDragon,
\r
2450 PM_BL = (int) BlackLance,
\r
2451 PM_BS = (int) BlackCobra,
\r
2452 PM_BV = (int) BlackFalcon,
\r
2453 PM_BSG = (int) BlackSilver,
\r
2454 PM_BK = (int) BlackKing
\r
2457 static HFONT hPieceFont = NULL;
\r
2458 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2459 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2460 static int fontBitmapSquareSize = 0;
\r
2461 static char pieceToFontChar[(int) EmptySquare] =
\r
2462 { 'p', 'n', 'b', 'r', 'q',
\r
2463 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2464 'k', 'o', 'm', 'v', 't', 'w',
\r
2465 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2468 extern BOOL SetCharTable( char *table, const char * map );
\r
2469 /* [HGM] moved to backend.c */
\r
2471 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2474 BYTE r1 = GetRValue( color );
\r
2475 BYTE g1 = GetGValue( color );
\r
2476 BYTE b1 = GetBValue( color );
\r
2482 /* Create a uniform background first */
\r
2483 hbrush = CreateSolidBrush( color );
\r
2484 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2485 FillRect( hdc, &rc, hbrush );
\r
2486 DeleteObject( hbrush );
\r
2489 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2490 int steps = squareSize / 2;
\r
2493 for( i=0; i<steps; i++ ) {
\r
2494 BYTE r = r1 - (r1-r2) * i / steps;
\r
2495 BYTE g = g1 - (g1-g2) * i / steps;
\r
2496 BYTE b = b1 - (b1-b2) * i / steps;
\r
2498 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2499 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2500 FillRect( hdc, &rc, hbrush );
\r
2501 DeleteObject(hbrush);
\r
2504 else if( mode == 2 ) {
\r
2505 /* Diagonal gradient, good more or less for every piece */
\r
2506 POINT triangle[3];
\r
2507 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2508 HBRUSH hbrush_old;
\r
2509 int steps = squareSize;
\r
2512 triangle[0].x = squareSize - steps;
\r
2513 triangle[0].y = squareSize;
\r
2514 triangle[1].x = squareSize;
\r
2515 triangle[1].y = squareSize;
\r
2516 triangle[2].x = squareSize;
\r
2517 triangle[2].y = squareSize - steps;
\r
2519 for( i=0; i<steps; i++ ) {
\r
2520 BYTE r = r1 - (r1-r2) * i / steps;
\r
2521 BYTE g = g1 - (g1-g2) * i / steps;
\r
2522 BYTE b = b1 - (b1-b2) * i / steps;
\r
2524 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2525 hbrush_old = SelectObject( hdc, hbrush );
\r
2526 Polygon( hdc, triangle, 3 );
\r
2527 SelectObject( hdc, hbrush_old );
\r
2528 DeleteObject(hbrush);
\r
2533 SelectObject( hdc, hpen );
\r
2538 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2539 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2540 piece: follow the steps as explained below.
\r
2542 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2546 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2550 int backColor = whitePieceColor;
\r
2551 int foreColor = blackPieceColor;
\r
2553 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2554 backColor = appData.fontBackColorWhite;
\r
2555 foreColor = appData.fontForeColorWhite;
\r
2557 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2558 backColor = appData.fontBackColorBlack;
\r
2559 foreColor = appData.fontForeColorBlack;
\r
2563 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2565 hbm_old = SelectObject( hdc, hbm );
\r
2569 rc.right = squareSize;
\r
2570 rc.bottom = squareSize;
\r
2572 /* Step 1: background is now black */
\r
2573 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2575 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2577 pt.x = (squareSize - sz.cx) / 2;
\r
2578 pt.y = (squareSize - sz.cy) / 2;
\r
2580 SetBkMode( hdc, TRANSPARENT );
\r
2581 SetTextColor( hdc, chroma );
\r
2582 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2583 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2585 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2586 /* Step 3: the area outside the piece is filled with white */
\r
2587 // FloodFill( hdc, 0, 0, chroma );
\r
2588 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2589 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2590 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2591 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2592 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2594 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2595 but if the start point is not inside the piece we're lost!
\r
2596 There should be a better way to do this... if we could create a region or path
\r
2597 from the fill operation we would be fine for example.
\r
2599 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2600 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2602 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2603 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2604 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2606 SelectObject( dc2, bm2 );
\r
2607 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2608 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2609 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2610 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2611 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2614 DeleteObject( bm2 );
\r
2617 SetTextColor( hdc, 0 );
\r
2619 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2620 draw the piece again in black for safety.
\r
2622 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2624 SelectObject( hdc, hbm_old );
\r
2626 if( hPieceMask[index] != NULL ) {
\r
2627 DeleteObject( hPieceMask[index] );
\r
2630 hPieceMask[index] = hbm;
\r
2633 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2635 SelectObject( hdc, hbm );
\r
2638 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2639 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2640 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2642 SelectObject( dc1, hPieceMask[index] );
\r
2643 SelectObject( dc2, bm2 );
\r
2644 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2645 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2648 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2649 the piece background and deletes (makes transparent) the rest.
\r
2650 Thanks to that mask, we are free to paint the background with the greates
\r
2651 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2652 We use this, to make gradients and give the pieces a "roundish" look.
\r
2654 SetPieceBackground( hdc, backColor, 2 );
\r
2655 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2659 DeleteObject( bm2 );
\r
2662 SetTextColor( hdc, foreColor );
\r
2663 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2665 SelectObject( hdc, hbm_old );
\r
2667 if( hPieceFace[index] != NULL ) {
\r
2668 DeleteObject( hPieceFace[index] );
\r
2671 hPieceFace[index] = hbm;
\r
2674 static int TranslatePieceToFontPiece( int piece )
\r
2704 case BlackMarshall:
\r
2708 case BlackNightrider:
\r
2714 case BlackUnicorn:
\r
2718 case BlackGrasshopper:
\r
2730 case BlackCardinal:
\r
2737 case WhiteMarshall:
\r
2741 case WhiteNightrider:
\r
2747 case WhiteUnicorn:
\r
2751 case WhiteGrasshopper:
\r
2763 case WhiteCardinal:
\r
2772 void CreatePiecesFromFont()
\r
2775 HDC hdc_window = NULL;
\r
2781 if( fontBitmapSquareSize < 0 ) {
\r
2782 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2786 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2787 fontBitmapSquareSize = -1;
\r
2791 if( fontBitmapSquareSize != squareSize ) {
\r
2792 hdc_window = GetDC( hwndMain );
\r
2793 hdc = CreateCompatibleDC( hdc_window );
\r
2795 if( hPieceFont != NULL ) {
\r
2796 DeleteObject( hPieceFont );
\r
2799 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2800 hPieceMask[i] = NULL;
\r
2801 hPieceFace[i] = NULL;
\r
2807 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2808 fontHeight = appData.fontPieceSize;
\r
2811 fontHeight = (fontHeight * squareSize) / 100;
\r
2813 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2815 lf.lfEscapement = 0;
\r
2816 lf.lfOrientation = 0;
\r
2817 lf.lfWeight = FW_NORMAL;
\r
2819 lf.lfUnderline = 0;
\r
2820 lf.lfStrikeOut = 0;
\r
2821 lf.lfCharSet = DEFAULT_CHARSET;
\r
2822 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2823 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2824 lf.lfQuality = PROOF_QUALITY;
\r
2825 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2826 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2827 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2829 hPieceFont = CreateFontIndirect( &lf );
\r
2831 if( hPieceFont == NULL ) {
\r
2832 fontBitmapSquareSize = -2;
\r
2835 /* Setup font-to-piece character table */
\r
2836 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2837 /* No (or wrong) global settings, try to detect the font */
\r
2838 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2840 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2842 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2843 /* DiagramTT* family */
\r
2844 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2846 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2847 /* Fairy symbols */
\r
2848 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2850 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2851 /* Good Companion (Some characters get warped as literal :-( */
\r
2852 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2853 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2854 SetCharTable(pieceToFontChar, s);
\r
2857 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2858 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2862 /* Create bitmaps */
\r
2863 hfont_old = SelectObject( hdc, hPieceFont );
\r
2864 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2865 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2866 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2868 SelectObject( hdc, hfont_old );
\r
2870 fontBitmapSquareSize = squareSize;
\r
2874 if( hdc != NULL ) {
\r
2878 if( hdc_window != NULL ) {
\r
2879 ReleaseDC( hwndMain, hdc_window );
\r
2884 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2888 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2889 if (gameInfo.event &&
\r
2890 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2891 strcmp(name, "k80s") == 0) {
\r
2892 strcpy(name, "tim");
\r
2894 return LoadBitmap(hinst, name);
\r
2898 /* Insert a color into the program's logical palette
\r
2899 structure. This code assumes the given color is
\r
2900 the result of the RGB or PALETTERGB macro, and it
\r
2901 knows how those macros work (which is documented).
\r
2904 InsertInPalette(COLORREF color)
\r
2906 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2908 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2909 DisplayFatalError("Too many colors", 0, 1);
\r
2910 pLogPal->palNumEntries--;
\r
2914 pe->peFlags = (char) 0;
\r
2915 pe->peRed = (char) (0xFF & color);
\r
2916 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2917 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2923 InitDrawingColors()
\r
2925 if (pLogPal == NULL) {
\r
2926 /* Allocate enough memory for a logical palette with
\r
2927 * PALETTESIZE entries and set the size and version fields
\r
2928 * of the logical palette structure.
\r
2930 pLogPal = (NPLOGPALETTE)
\r
2931 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2932 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2933 pLogPal->palVersion = 0x300;
\r
2935 pLogPal->palNumEntries = 0;
\r
2937 InsertInPalette(lightSquareColor);
\r
2938 InsertInPalette(darkSquareColor);
\r
2939 InsertInPalette(whitePieceColor);
\r
2940 InsertInPalette(blackPieceColor);
\r
2941 InsertInPalette(highlightSquareColor);
\r
2942 InsertInPalette(premoveHighlightColor);
\r
2944 /* create a logical color palette according the information
\r
2945 * in the LOGPALETTE structure.
\r
2947 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2949 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2950 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2951 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2952 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2953 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2954 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2955 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2956 /* [AS] Force rendering of the font-based pieces */
\r
2957 if( fontBitmapSquareSize > 0 ) {
\r
2958 fontBitmapSquareSize = 0;
\r
2964 BoardWidth(int boardSize, int n)
\r
2965 { /* [HGM] argument n added to allow different width and height */
\r
2966 int lineGap = sizeInfo[boardSize].lineGap;
\r
2968 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2969 lineGap = appData.overrideLineGap;
\r
2972 return (n + 1) * lineGap +
\r
2973 n * sizeInfo[boardSize].squareSize;
\r
2976 /* Respond to board resize by dragging edge */
\r
2978 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2980 BoardSize newSize = NUM_SIZES - 1;
\r
2981 static int recurse = 0;
\r
2982 if (IsIconic(hwndMain)) return;
\r
2983 if (recurse > 0) return;
\r
2985 while (newSize > 0) {
\r
2986 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2987 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2988 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2991 boardSize = newSize;
\r
2992 InitDrawingSizes(boardSize, flags);
\r
2999 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3001 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3002 ChessSquare piece;
\r
3003 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3005 SIZE clockSize, messageSize;
\r
3007 char buf[MSG_SIZ];
\r
3009 HMENU hmenu = GetMenu(hwndMain);
\r
3010 RECT crect, wrect, oldRect;
\r
3012 LOGBRUSH logbrush;
\r
3014 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3015 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3017 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3018 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3020 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
3021 oldRect.top = wpMain.y;
\r
3022 oldRect.right = wpMain.x + wpMain.width;
\r
3023 oldRect.bottom = wpMain.y + wpMain.height;
\r
3025 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3026 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3027 squareSize = sizeInfo[boardSize].squareSize;
\r
3028 lineGap = sizeInfo[boardSize].lineGap;
\r
3029 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3031 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3032 lineGap = appData.overrideLineGap;
\r
3035 if (tinyLayout != oldTinyLayout) {
\r
3036 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3038 style &= ~WS_SYSMENU;
\r
3039 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3040 "&Minimize\tCtrl+F4");
\r
3042 style |= WS_SYSMENU;
\r
3043 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3045 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3047 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3048 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3049 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3051 DrawMenuBar(hwndMain);
\r
3054 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3055 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3057 /* Get text area sizes */
\r
3058 hdc = GetDC(hwndMain);
\r
3059 if (appData.clockMode) {
\r
3060 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3062 sprintf(buf, "White");
\r
3064 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3065 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3066 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3067 str = "We only care about the height here";
\r
3068 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3069 SelectObject(hdc, oldFont);
\r
3070 ReleaseDC(hwndMain, hdc);
\r
3072 /* Compute where everything goes */
\r
3073 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3074 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3075 logoHeight = 2*clockSize.cy;
\r
3076 leftLogoRect.left = OUTER_MARGIN;
\r
3077 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3078 leftLogoRect.top = OUTER_MARGIN;
\r
3079 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3081 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3082 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3083 rightLogoRect.top = OUTER_MARGIN;
\r
3084 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3087 whiteRect.left = leftLogoRect.right;
\r
3088 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3089 whiteRect.top = OUTER_MARGIN;
\r
3090 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3092 blackRect.right = rightLogoRect.left;
\r
3093 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3094 blackRect.top = whiteRect.top;
\r
3095 blackRect.bottom = whiteRect.bottom;
\r
3097 whiteRect.left = OUTER_MARGIN;
\r
3098 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3099 whiteRect.top = OUTER_MARGIN;
\r
3100 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3102 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3103 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3104 blackRect.top = whiteRect.top;
\r
3105 blackRect.bottom = whiteRect.bottom;
\r
3108 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3109 if (appData.showButtonBar) {
\r
3110 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3111 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3113 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3115 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3116 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3118 boardRect.left = OUTER_MARGIN;
\r
3119 boardRect.right = boardRect.left + boardWidth;
\r
3120 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3121 boardRect.bottom = boardRect.top + boardHeight;
\r
3123 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3124 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3125 oldBoardSize = boardSize;
\r
3126 oldTinyLayout = tinyLayout;
\r
3127 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3128 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3129 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3130 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3131 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3132 wpMain.height = winH; // without disturbing window attachments
\r
3133 GetWindowRect(hwndMain, &wrect);
\r
3134 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
3135 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3137 // [HGM] placement: let attached windows follow size change.
\r
3138 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
3139 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
3140 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
3141 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
3142 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
3144 /* compensate if menu bar wrapped */
\r
3145 GetClientRect(hwndMain, &crect);
\r
3146 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3147 wpMain.height += offby;
\r
3149 case WMSZ_TOPLEFT:
\r
3150 SetWindowPos(hwndMain, NULL,
\r
3151 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
3152 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3155 case WMSZ_TOPRIGHT:
\r
3157 SetWindowPos(hwndMain, NULL,
\r
3158 wrect.left, wrect.bottom - wpMain.height,
\r
3159 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3162 case WMSZ_BOTTOMLEFT:
\r
3164 SetWindowPos(hwndMain, NULL,
\r
3165 wrect.right - wpMain.width, wrect.top,
\r
3166 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3169 case WMSZ_BOTTOMRIGHT:
\r
3173 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
3174 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3179 for (i = 0; i < N_BUTTONS; i++) {
\r
3180 if (buttonDesc[i].hwnd != NULL) {
\r
3181 DestroyWindow(buttonDesc[i].hwnd);
\r
3182 buttonDesc[i].hwnd = NULL;
\r
3184 if (appData.showButtonBar) {
\r
3185 buttonDesc[i].hwnd =
\r
3186 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3187 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3188 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3189 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3190 (HMENU) buttonDesc[i].id,
\r
3191 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3193 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3194 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3195 MAKELPARAM(FALSE, 0));
\r
3197 if (buttonDesc[i].id == IDM_Pause)
\r
3198 hwndPause = buttonDesc[i].hwnd;
\r
3199 buttonDesc[i].wndproc = (WNDPROC)
\r
3200 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3203 if (gridPen != NULL) DeleteObject(gridPen);
\r
3204 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3205 if (premovePen != NULL) DeleteObject(premovePen);
\r
3206 if (lineGap != 0) {
\r
3207 logbrush.lbStyle = BS_SOLID;
\r
3208 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3210 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3211 lineGap, &logbrush, 0, NULL);
\r
3212 logbrush.lbColor = highlightSquareColor;
\r
3214 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3215 lineGap, &logbrush, 0, NULL);
\r
3217 logbrush.lbColor = premoveHighlightColor;
\r
3219 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3220 lineGap, &logbrush, 0, NULL);
\r
3222 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3223 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3224 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3225 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3226 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3227 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3228 BOARD_WIDTH * (squareSize + lineGap);
\r
3229 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3231 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3232 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3233 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3234 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3235 lineGap / 2 + (i * (squareSize + lineGap));
\r
3236 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3237 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3238 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3242 /* [HGM] Licensing requirement */
\r
3244 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3247 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3249 GothicPopUp( "", VariantNormal);
\r
3252 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3254 /* Load piece bitmaps for this board size */
\r
3255 for (i=0; i<=2; i++) {
\r
3256 for (piece = WhitePawn;
\r
3257 (int) piece < (int) BlackPawn;
\r
3258 piece = (ChessSquare) ((int) piece + 1)) {
\r
3259 if (pieceBitmap[i][piece] != NULL)
\r
3260 DeleteObject(pieceBitmap[i][piece]);
\r
3264 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3265 // Orthodox Chess pieces
\r
3266 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3267 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3268 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3269 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3270 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3271 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3272 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3273 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3274 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3275 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3276 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3277 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3278 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3279 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3280 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3281 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3282 // in Shogi, Hijack the unused Queen for Lance
\r
3283 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3284 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3285 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3287 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3288 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3289 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3292 if(squareSize <= 72 && squareSize >= 33) {
\r
3293 /* A & C are available in most sizes now */
\r
3294 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3295 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3296 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3297 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3298 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3299 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3300 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3301 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3302 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3303 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3304 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3305 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3306 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3307 } else { // Smirf-like
\r
3308 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3309 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3310 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3312 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3313 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3314 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3315 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3316 } else { // WinBoard standard
\r
3317 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3318 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3319 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3324 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3325 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3326 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3327 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3328 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3329 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3330 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3331 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3332 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3333 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3334 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3335 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3336 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3337 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3338 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3339 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3340 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3341 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3342 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3343 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3344 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3345 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3346 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3347 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3348 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3349 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3350 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3351 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3352 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3353 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3354 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3356 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3357 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3358 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3359 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3360 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3361 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3362 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3363 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3364 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3365 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3366 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3367 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3368 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3370 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3371 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3372 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3373 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3374 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3375 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3376 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3377 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3378 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3379 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3380 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3381 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3384 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3385 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3386 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3387 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3388 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3389 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3390 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3391 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3392 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3393 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3394 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3395 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3396 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3397 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3398 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3402 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3403 /* special Shogi support in this size */
\r
3404 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3405 for (piece = WhitePawn;
\r
3406 (int) piece < (int) BlackPawn;
\r
3407 piece = (ChessSquare) ((int) piece + 1)) {
\r
3408 if (pieceBitmap[i][piece] != NULL)
\r
3409 DeleteObject(pieceBitmap[i][piece]);
\r
3412 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3413 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3414 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3415 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3416 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3417 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3418 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3419 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3420 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3421 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3422 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3423 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3424 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3425 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3426 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3427 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3428 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3429 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3430 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3431 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3432 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3433 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3434 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3435 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3436 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3437 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3438 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3439 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3440 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3441 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3442 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3443 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3444 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3445 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3446 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3447 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3448 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3449 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3450 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3451 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3452 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3453 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3459 PieceBitmap(ChessSquare p, int kind)
\r
3461 if ((int) p >= (int) BlackPawn)
\r
3462 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3464 return pieceBitmap[kind][(int) p];
\r
3467 /***************************************************************/
\r
3469 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3470 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3472 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3473 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3477 SquareToPos(int row, int column, int * x, int * y)
\r
3480 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3481 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3483 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3484 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3489 DrawCoordsOnDC(HDC hdc)
\r
3491 static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};
\r
3492 static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};
\r
3493 char str[2] = { NULLCHAR, NULLCHAR };
\r
3494 int oldMode, oldAlign, x, y, start, i;
\r
3498 if (!appData.showCoords)
\r
3501 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3503 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3504 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3505 oldAlign = GetTextAlign(hdc);
\r
3506 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3508 y = boardRect.top + lineGap;
\r
3509 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3511 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3512 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3513 str[0] = files[start + i];
\r
3514 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3515 y += squareSize + lineGap;
\r
3518 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3520 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3521 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3522 str[0] = ranks[start + i];
\r
3523 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3524 x += squareSize + lineGap;
\r
3527 SelectObject(hdc, oldBrush);
\r
3528 SetBkMode(hdc, oldMode);
\r
3529 SetTextAlign(hdc, oldAlign);
\r
3530 SelectObject(hdc, oldFont);
\r
3534 DrawGridOnDC(HDC hdc)
\r
3538 if (lineGap != 0) {
\r
3539 oldPen = SelectObject(hdc, gridPen);
\r
3540 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3541 SelectObject(hdc, oldPen);
\r
3545 #define HIGHLIGHT_PEN 0
\r
3546 #define PREMOVE_PEN 1
\r
3549 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3552 HPEN oldPen, hPen;
\r
3553 if (lineGap == 0) return;
\r
3555 x1 = boardRect.left +
\r
3556 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3557 y1 = boardRect.top +
\r
3558 lineGap/2 + y * (squareSize + lineGap);
\r
3560 x1 = boardRect.left +
\r
3561 lineGap/2 + x * (squareSize + lineGap);
\r
3562 y1 = boardRect.top +
\r
3563 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3565 hPen = pen ? premovePen : highlightPen;
\r
3566 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3567 MoveToEx(hdc, x1, y1, NULL);
\r
3568 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3569 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3570 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3571 LineTo(hdc, x1, y1);
\r
3572 SelectObject(hdc, oldPen);
\r
3576 DrawHighlightsOnDC(HDC hdc)
\r
3579 for (i=0; i<2; i++) {
\r
3580 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3581 DrawHighlightOnDC(hdc, TRUE,
\r
3582 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3585 for (i=0; i<2; i++) {
\r
3586 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3587 premoveHighlightInfo.sq[i].y >= 0) {
\r
3588 DrawHighlightOnDC(hdc, TRUE,
\r
3589 premoveHighlightInfo.sq[i].x,
\r
3590 premoveHighlightInfo.sq[i].y,
\r
3596 /* Note: sqcolor is used only in monoMode */
\r
3597 /* Note that this code is largely duplicated in woptions.c,
\r
3598 function DrawSampleSquare, so that needs to be updated too */
\r
3600 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3602 HBITMAP oldBitmap;
\r
3606 if (appData.blindfold) return;
\r
3608 /* [AS] Use font-based pieces if needed */
\r
3609 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3610 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3611 CreatePiecesFromFont();
\r
3613 if( fontBitmapSquareSize == squareSize ) {
\r
3614 int index = TranslatePieceToFontPiece(piece);
\r
3616 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3620 squareSize, squareSize,
\r
3625 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3629 squareSize, squareSize,
\r
3638 if (appData.monoMode) {
\r
3639 SelectObject(tmphdc, PieceBitmap(piece,
\r
3640 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3641 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3642 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3644 tmpSize = squareSize;
\r
3646 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3647 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3648 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3649 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3650 x += (squareSize - minorSize)>>1;
\r
3651 y += squareSize - minorSize - 2;
\r
3652 tmpSize = minorSize;
\r
3654 if (color || appData.allWhite ) {
\r
3655 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3657 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3658 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3659 if(appData.upsideDown && color==flipView)
\r
3660 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3662 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3663 /* Use black for outline of white pieces */
\r
3664 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3665 if(appData.upsideDown && color==flipView)
\r
3666 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3668 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3670 /* Use square color for details of black pieces */
\r
3671 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3672 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3673 if(appData.upsideDown && !flipView)
\r
3674 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3676 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3678 SelectObject(hdc, oldBrush);
\r
3679 SelectObject(tmphdc, oldBitmap);
\r
3683 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3684 int GetBackTextureMode( int algo )
\r
3686 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3690 case BACK_TEXTURE_MODE_PLAIN:
\r
3691 result = 1; /* Always use identity map */
\r
3693 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3694 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3702 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3703 to handle redraws cleanly (as random numbers would always be different).
\r
3705 VOID RebuildTextureSquareInfo()
\r
3715 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3717 if( liteBackTexture != NULL ) {
\r
3718 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3719 lite_w = bi.bmWidth;
\r
3720 lite_h = bi.bmHeight;
\r
3724 if( darkBackTexture != NULL ) {
\r
3725 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3726 dark_w = bi.bmWidth;
\r
3727 dark_h = bi.bmHeight;
\r
3731 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3732 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3733 if( (col + row) & 1 ) {
\r
3735 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3736 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3737 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3738 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3743 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3744 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3745 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3746 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3753 /* [AS] Arrow highlighting support */
\r
3755 static int A_WIDTH = 5; /* Width of arrow body */
\r
3757 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3758 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3760 static double Sqr( double x )
\r
3765 static int Round( double x )
\r
3767 return (int) (x + 0.5);
\r
3770 /* Draw an arrow between two points using current settings */
\r
3771 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3774 double dx, dy, j, k, x, y;
\r
3776 if( d_x == s_x ) {
\r
3777 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3779 arrow[0].x = s_x + A_WIDTH;
\r
3782 arrow[1].x = s_x + A_WIDTH;
\r
3783 arrow[1].y = d_y - h;
\r
3785 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3786 arrow[2].y = d_y - h;
\r
3791 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3792 arrow[4].y = d_y - h;
\r
3794 arrow[5].x = s_x - A_WIDTH;
\r
3795 arrow[5].y = d_y - h;
\r
3797 arrow[6].x = s_x - A_WIDTH;
\r
3800 else if( d_y == s_y ) {
\r
3801 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3804 arrow[0].y = s_y + A_WIDTH;
\r
3806 arrow[1].x = d_x - w;
\r
3807 arrow[1].y = s_y + A_WIDTH;
\r
3809 arrow[2].x = d_x - w;
\r
3810 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3815 arrow[4].x = d_x - w;
\r
3816 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3818 arrow[5].x = d_x - w;
\r
3819 arrow[5].y = s_y - A_WIDTH;
\r
3822 arrow[6].y = s_y - A_WIDTH;
\r
3825 /* [AS] Needed a lot of paper for this! :-) */
\r
3826 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3827 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3829 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3831 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3836 arrow[0].x = Round(x - j);
\r
3837 arrow[0].y = Round(y + j*dx);
\r
3839 arrow[1].x = Round(x + j);
\r
3840 arrow[1].y = Round(y - j*dx);
\r
3843 x = (double) d_x - k;
\r
3844 y = (double) d_y - k*dy;
\r
3847 x = (double) d_x + k;
\r
3848 y = (double) d_y + k*dy;
\r
3851 arrow[2].x = Round(x + j);
\r
3852 arrow[2].y = Round(y - j*dx);
\r
3854 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3855 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3860 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3861 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3863 arrow[6].x = Round(x - j);
\r
3864 arrow[6].y = Round(y + j*dx);
\r
3867 Polygon( hdc, arrow, 7 );
\r
3870 /* [AS] Draw an arrow between two squares */
\r
3871 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3873 int s_x, s_y, d_x, d_y;
\r
3880 if( s_col == d_col && s_row == d_row ) {
\r
3884 /* Get source and destination points */
\r
3885 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3886 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3889 d_y += squareSize / 4;
\r
3891 else if( d_y < s_y ) {
\r
3892 d_y += 3 * squareSize / 4;
\r
3895 d_y += squareSize / 2;
\r
3899 d_x += squareSize / 4;
\r
3901 else if( d_x < s_x ) {
\r
3902 d_x += 3 * squareSize / 4;
\r
3905 d_x += squareSize / 2;
\r
3908 s_x += squareSize / 2;
\r
3909 s_y += squareSize / 2;
\r
3911 /* Adjust width */
\r
3912 A_WIDTH = squareSize / 14;
\r
3915 stLB.lbStyle = BS_SOLID;
\r
3916 stLB.lbColor = appData.highlightArrowColor;
\r
3919 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3920 holdpen = SelectObject( hdc, hpen );
\r
3921 hbrush = CreateBrushIndirect( &stLB );
\r
3922 holdbrush = SelectObject( hdc, hbrush );
\r
3924 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3926 SelectObject( hdc, holdpen );
\r
3927 SelectObject( hdc, holdbrush );
\r
3928 DeleteObject( hpen );
\r
3929 DeleteObject( hbrush );
\r
3932 BOOL HasHighlightInfo()
\r
3934 BOOL result = FALSE;
\r
3936 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3937 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3945 BOOL IsDrawArrowEnabled()
\r
3947 BOOL result = FALSE;
\r
3949 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3956 VOID DrawArrowHighlight( HDC hdc )
\r
3958 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3959 DrawArrowBetweenSquares( hdc,
\r
3960 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3961 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3965 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3967 HRGN result = NULL;
\r
3969 if( HasHighlightInfo() ) {
\r
3970 int x1, y1, x2, y2;
\r
3971 int sx, sy, dx, dy;
\r
3973 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3974 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3976 sx = MIN( x1, x2 );
\r
3977 sy = MIN( y1, y2 );
\r
3978 dx = MAX( x1, x2 ) + squareSize;
\r
3979 dy = MAX( y1, y2 ) + squareSize;
\r
3981 result = CreateRectRgn( sx, sy, dx, dy );
\r
3988 Warning: this function modifies the behavior of several other functions.
\r
3990 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3991 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3992 repaint is scattered all over the place, which is not good for features such as
\r
3993 "arrow highlighting" that require a full repaint of the board.
\r
3995 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3996 user interaction, when speed is not so important) but especially to avoid errors
\r
3997 in the displayed graphics.
\r
3999 In such patched places, I always try refer to this function so there is a single
\r
4000 place to maintain knowledge.
\r
4002 To restore the original behavior, just return FALSE unconditionally.
\r
4004 BOOL IsFullRepaintPreferrable()
\r
4006 BOOL result = FALSE;
\r
4008 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4009 /* Arrow may appear on the board */
\r
4017 This function is called by DrawPosition to know whether a full repaint must
\r
4020 Only DrawPosition may directly call this function, which makes use of
\r
4021 some state information. Other function should call DrawPosition specifying
\r
4022 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4024 BOOL DrawPositionNeedsFullRepaint()
\r
4026 BOOL result = FALSE;
\r
4029 Probably a slightly better policy would be to trigger a full repaint
\r
4030 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4031 but animation is fast enough that it's difficult to notice.
\r
4033 if( animInfo.piece == EmptySquare ) {
\r
4034 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
4043 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4045 int row, column, x, y, square_color, piece_color;
\r
4046 ChessSquare piece;
\r
4048 HDC texture_hdc = NULL;
\r
4050 /* [AS] Initialize background textures if needed */
\r
4051 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4052 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4053 if( backTextureSquareSize != squareSize
\r
4054 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
4055 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
4056 backTextureSquareSize = squareSize;
\r
4057 RebuildTextureSquareInfo();
\r
4060 texture_hdc = CreateCompatibleDC( hdc );
\r
4063 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4064 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4066 SquareToPos(row, column, &x, &y);
\r
4068 piece = board[row][column];
\r
4070 square_color = ((column + row) % 2) == 1;
\r
4071 if( gameInfo.variant == VariantXiangqi ) {
\r
4072 square_color = !InPalace(row, column);
\r
4073 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4074 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4076 piece_color = (int) piece < (int) BlackPawn;
\r
4079 /* [HGM] holdings file: light square or black */
\r
4080 if(column == BOARD_LEFT-2) {
\r
4081 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4084 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4088 if(column == BOARD_RGHT + 1 ) {
\r
4089 if( row < gameInfo.holdingsSize )
\r
4092 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4096 if(column == BOARD_LEFT-1 ) /* left align */
\r
4097 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4098 else if( column == BOARD_RGHT) /* right align */
\r
4099 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4101 if (appData.monoMode) {
\r
4102 if (piece == EmptySquare) {
\r
4103 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4104 square_color ? WHITENESS : BLACKNESS);
\r
4106 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4109 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4110 /* [AS] Draw the square using a texture bitmap */
\r
4111 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4112 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4113 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4116 squareSize, squareSize,
\r
4119 backTextureSquareInfo[r][c].mode,
\r
4120 backTextureSquareInfo[r][c].x,
\r
4121 backTextureSquareInfo[r][c].y );
\r
4123 SelectObject( texture_hdc, hbm );
\r
4125 if (piece != EmptySquare) {
\r
4126 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4130 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4132 oldBrush = SelectObject(hdc, brush );
\r
4133 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4134 SelectObject(hdc, oldBrush);
\r
4135 if (piece != EmptySquare)
\r
4136 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4141 if( texture_hdc != NULL ) {
\r
4142 DeleteDC( texture_hdc );
\r
4146 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4147 void fputDW(FILE *f, int x)
\r
4149 fputc(x & 255, f);
\r
4150 fputc(x>>8 & 255, f);
\r
4151 fputc(x>>16 & 255, f);
\r
4152 fputc(x>>24 & 255, f);
\r
4155 #define MAX_CLIPS 200 /* more than enough */
\r
4158 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4160 // HBITMAP bufferBitmap;
\r
4165 int w = 100, h = 50;
\r
4167 if(logo == NULL) return;
\r
4168 // GetClientRect(hwndMain, &Rect);
\r
4169 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4170 // Rect.bottom-Rect.top+1);
\r
4171 tmphdc = CreateCompatibleDC(hdc);
\r
4172 hbm = SelectObject(tmphdc, logo);
\r
4173 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4177 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4178 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4179 SelectObject(tmphdc, hbm);
\r
4184 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4186 static Board lastReq, lastDrawn;
\r
4187 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4188 static int lastDrawnFlipView = 0;
\r
4189 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4190 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4193 HBITMAP bufferBitmap;
\r
4194 HBITMAP oldBitmap;
\r
4196 HRGN clips[MAX_CLIPS];
\r
4197 ChessSquare dragged_piece = EmptySquare;
\r
4199 /* I'm undecided on this - this function figures out whether a full
\r
4200 * repaint is necessary on its own, so there's no real reason to have the
\r
4201 * caller tell it that. I think this can safely be set to FALSE - but
\r
4202 * if we trust the callers not to request full repaints unnessesarily, then
\r
4203 * we could skip some clipping work. In other words, only request a full
\r
4204 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4205 * gamestart and similar) --Hawk
\r
4207 Boolean fullrepaint = repaint;
\r
4209 if( DrawPositionNeedsFullRepaint() ) {
\r
4210 fullrepaint = TRUE;
\r
4213 if (board == NULL) {
\r
4214 if (!lastReqValid) {
\r
4219 CopyBoard(lastReq, board);
\r
4223 if (doingSizing) {
\r
4227 if (IsIconic(hwndMain)) {
\r
4231 if (hdc == NULL) {
\r
4232 hdc = GetDC(hwndMain);
\r
4233 if (!appData.monoMode) {
\r
4234 SelectPalette(hdc, hPal, FALSE);
\r
4235 RealizePalette(hdc);
\r
4239 releaseDC = FALSE;
\r
4242 /* Create some work-DCs */
\r
4243 hdcmem = CreateCompatibleDC(hdc);
\r
4244 tmphdc = CreateCompatibleDC(hdc);
\r
4246 /* If dragging is in progress, we temporarely remove the piece */
\r
4247 /* [HGM] or temporarily decrease count if stacked */
\r
4248 /* !! Moved to before board compare !! */
\r
4249 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4250 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4251 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4252 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4253 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4255 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4256 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4257 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4259 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4262 /* Figure out which squares need updating by comparing the
\r
4263 * newest board with the last drawn board and checking if
\r
4264 * flipping has changed.
\r
4266 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4267 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4268 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4269 if (lastDrawn[row][column] != board[row][column]) {
\r
4270 SquareToPos(row, column, &x, &y);
\r
4271 clips[num_clips++] =
\r
4272 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4276 for (i=0; i<2; i++) {
\r
4277 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4278 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4279 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4280 lastDrawnHighlight.sq[i].y >= 0) {
\r
4281 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4282 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4283 clips[num_clips++] =
\r
4284 CreateRectRgn(x - lineGap, y - lineGap,
\r
4285 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4287 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4288 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4289 clips[num_clips++] =
\r
4290 CreateRectRgn(x - lineGap, y - lineGap,
\r
4291 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4295 for (i=0; i<2; i++) {
\r
4296 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4297 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4298 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4299 lastDrawnPremove.sq[i].y >= 0) {
\r
4300 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4301 lastDrawnPremove.sq[i].x, &x, &y);
\r
4302 clips[num_clips++] =
\r
4303 CreateRectRgn(x - lineGap, y - lineGap,
\r
4304 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4306 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4307 premoveHighlightInfo.sq[i].y >= 0) {
\r
4308 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4309 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4310 clips[num_clips++] =
\r
4311 CreateRectRgn(x - lineGap, y - lineGap,
\r
4312 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4317 fullrepaint = TRUE;
\r
4320 /* Create a buffer bitmap - this is the actual bitmap
\r
4321 * being written to. When all the work is done, we can
\r
4322 * copy it to the real DC (the screen). This avoids
\r
4323 * the problems with flickering.
\r
4325 GetClientRect(hwndMain, &Rect);
\r
4326 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4327 Rect.bottom-Rect.top+1);
\r
4328 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4329 if (!appData.monoMode) {
\r
4330 SelectPalette(hdcmem, hPal, FALSE);
\r
4333 /* Create clips for dragging */
\r
4334 if (!fullrepaint) {
\r
4335 if (dragInfo.from.x >= 0) {
\r
4336 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4337 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4339 if (dragInfo.start.x >= 0) {
\r
4340 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4341 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4343 if (dragInfo.pos.x >= 0) {
\r
4344 x = dragInfo.pos.x - squareSize / 2;
\r
4345 y = dragInfo.pos.y - squareSize / 2;
\r
4346 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4348 if (dragInfo.lastpos.x >= 0) {
\r
4349 x = dragInfo.lastpos.x - squareSize / 2;
\r
4350 y = dragInfo.lastpos.y - squareSize / 2;
\r
4351 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4355 /* Are we animating a move?
\r
4357 * - remove the piece from the board (temporarely)
\r
4358 * - calculate the clipping region
\r
4360 if (!fullrepaint) {
\r
4361 if (animInfo.piece != EmptySquare) {
\r
4362 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4363 x = boardRect.left + animInfo.lastpos.x;
\r
4364 y = boardRect.top + animInfo.lastpos.y;
\r
4365 x2 = boardRect.left + animInfo.pos.x;
\r
4366 y2 = boardRect.top + animInfo.pos.y;
\r
4367 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4368 /* Slight kludge. The real problem is that after AnimateMove is
\r
4369 done, the position on the screen does not match lastDrawn.
\r
4370 This currently causes trouble only on e.p. captures in
\r
4371 atomic, where the piece moves to an empty square and then
\r
4372 explodes. The old and new positions both had an empty square
\r
4373 at the destination, but animation has drawn a piece there and
\r
4374 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4375 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4379 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4380 if (num_clips == 0)
\r
4381 fullrepaint = TRUE;
\r
4383 /* Set clipping on the memory DC */
\r
4384 if (!fullrepaint) {
\r
4385 SelectClipRgn(hdcmem, clips[0]);
\r
4386 for (x = 1; x < num_clips; x++) {
\r
4387 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4388 abort(); // this should never ever happen!
\r
4392 /* Do all the drawing to the memory DC */
\r
4393 if(explodeInfo.radius) { // [HGM] atomic
\r
4395 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4396 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4397 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4398 x += squareSize/2;
\r
4399 y += squareSize/2;
\r
4400 if(!fullrepaint) {
\r
4401 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4402 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4404 DrawGridOnDC(hdcmem);
\r
4405 DrawHighlightsOnDC(hdcmem);
\r
4406 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4407 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4408 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4409 SelectObject(hdcmem, oldBrush);
\r
4411 DrawGridOnDC(hdcmem);
\r
4412 DrawHighlightsOnDC(hdcmem);
\r
4413 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4416 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4417 if(appData.autoLogo) {
\r
4419 switch(gameMode) { // pick logos based on game mode
\r
4420 case IcsObserving:
\r
4421 whiteLogo = second.programLogo; // ICS logo
\r
4422 blackLogo = second.programLogo;
\r
4425 case IcsPlayingWhite:
\r
4426 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4427 blackLogo = second.programLogo; // ICS logo
\r
4429 case IcsPlayingBlack:
\r
4430 whiteLogo = second.programLogo; // ICS logo
\r
4431 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4433 case TwoMachinesPlay:
\r
4434 if(first.twoMachinesColor[0] == 'b') {
\r
4435 whiteLogo = second.programLogo;
\r
4436 blackLogo = first.programLogo;
\r
4439 case MachinePlaysWhite:
\r
4440 blackLogo = userLogo;
\r
4442 case MachinePlaysBlack:
\r
4443 whiteLogo = userLogo;
\r
4444 blackLogo = first.programLogo;
\r
4447 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4448 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4451 if( appData.highlightMoveWithArrow ) {
\r
4452 DrawArrowHighlight(hdcmem);
\r
4455 DrawCoordsOnDC(hdcmem);
\r
4457 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4458 /* to make sure lastDrawn contains what is actually drawn */
\r
4460 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4461 if (dragged_piece != EmptySquare) {
\r
4462 /* [HGM] or restack */
\r
4463 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4464 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4466 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4467 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4468 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4469 x = dragInfo.pos.x - squareSize / 2;
\r
4470 y = dragInfo.pos.y - squareSize / 2;
\r
4471 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4472 ((int) dragged_piece < (int) BlackPawn),
\r
4473 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4476 /* Put the animated piece back into place and draw it */
\r
4477 if (animInfo.piece != EmptySquare) {
\r
4478 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4479 x = boardRect.left + animInfo.pos.x;
\r
4480 y = boardRect.top + animInfo.pos.y;
\r
4481 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4482 ((int) animInfo.piece < (int) BlackPawn),
\r
4483 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4486 /* Release the bufferBitmap by selecting in the old bitmap
\r
4487 * and delete the memory DC
\r
4489 SelectObject(hdcmem, oldBitmap);
\r
4492 /* Set clipping on the target DC */
\r
4493 if (!fullrepaint) {
\r
4494 SelectClipRgn(hdc, clips[0]);
\r
4495 for (x = 1; x < num_clips; x++) {
\r
4496 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4497 abort(); // this should never ever happen!
\r
4501 /* Copy the new bitmap onto the screen in one go.
\r
4502 * This way we avoid any flickering
\r
4504 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4505 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4506 boardRect.right - boardRect.left,
\r
4507 boardRect.bottom - boardRect.top,
\r
4508 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4509 if(saveDiagFlag) {
\r
4510 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4511 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4513 GetObject(bufferBitmap, sizeof(b), &b);
\r
4514 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4515 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4516 bih.biWidth = b.bmWidth;
\r
4517 bih.biHeight = b.bmHeight;
\r
4519 bih.biBitCount = b.bmBitsPixel;
\r
4520 bih.biCompression = 0;
\r
4521 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4522 bih.biXPelsPerMeter = 0;
\r
4523 bih.biYPelsPerMeter = 0;
\r
4524 bih.biClrUsed = 0;
\r
4525 bih.biClrImportant = 0;
\r
4526 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4527 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4528 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4529 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4531 wb = b.bmWidthBytes;
\r
4533 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4534 int k = ((int*) pData)[i];
\r
4535 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4536 if(j >= 16) break;
\r
4538 if(j >= nrColors) nrColors = j+1;
\r
4540 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4542 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4543 for(w=0; w<(wb>>2); w+=2) {
\r
4544 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4545 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4546 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4547 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4548 pData[p++] = m | j<<4;
\r
4550 while(p&3) pData[p++] = 0;
\r
4553 wb = ((wb+31)>>5)<<2;
\r
4555 // write BITMAPFILEHEADER
\r
4556 fprintf(diagFile, "BM");
\r
4557 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4558 fputDW(diagFile, 0);
\r
4559 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4560 // write BITMAPINFOHEADER
\r
4561 fputDW(diagFile, 40);
\r
4562 fputDW(diagFile, b.bmWidth);
\r
4563 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4564 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4565 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4566 fputDW(diagFile, 0);
\r
4567 fputDW(diagFile, 0);
\r
4568 fputDW(diagFile, 0);
\r
4569 fputDW(diagFile, 0);
\r
4570 fputDW(diagFile, 0);
\r
4571 fputDW(diagFile, 0);
\r
4572 // write color table
\r
4574 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4575 // write bitmap data
\r
4576 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4577 fputc(pData[i], diagFile);
\r
4581 SelectObject(tmphdc, oldBitmap);
\r
4583 /* Massive cleanup */
\r
4584 for (x = 0; x < num_clips; x++)
\r
4585 DeleteObject(clips[x]);
\r
4588 DeleteObject(bufferBitmap);
\r
4591 ReleaseDC(hwndMain, hdc);
\r
4593 if (lastDrawnFlipView != flipView) {
\r
4595 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4597 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4600 /* CopyBoard(lastDrawn, board);*/
\r
4601 lastDrawnHighlight = highlightInfo;
\r
4602 lastDrawnPremove = premoveHighlightInfo;
\r
4603 lastDrawnFlipView = flipView;
\r
4604 lastDrawnValid = 1;
\r
4607 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4612 saveDiagFlag = 1; diagFile = f;
\r
4613 HDCDrawPosition(NULL, TRUE, NULL);
\r
4617 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4624 /*---------------------------------------------------------------------------*\
\r
4625 | CLIENT PAINT PROCEDURE
\r
4626 | This is the main event-handler for the WM_PAINT message.
\r
4628 \*---------------------------------------------------------------------------*/
\r
4630 PaintProc(HWND hwnd)
\r
4636 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4637 if (IsIconic(hwnd)) {
\r
4638 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4640 if (!appData.monoMode) {
\r
4641 SelectPalette(hdc, hPal, FALSE);
\r
4642 RealizePalette(hdc);
\r
4644 HDCDrawPosition(hdc, 1, NULL);
\r
4646 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4647 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4648 ETO_CLIPPED|ETO_OPAQUE,
\r
4649 &messageRect, messageText, strlen(messageText), NULL);
\r
4650 SelectObject(hdc, oldFont);
\r
4651 DisplayBothClocks();
\r
4653 EndPaint(hwnd,&ps);
\r
4661 * If the user selects on a border boundary, return -1; if off the board,
\r
4662 * return -2. Otherwise map the event coordinate to the square.
\r
4663 * The offset boardRect.left or boardRect.top must already have been
\r
4664 * subtracted from x.
\r
4666 int EventToSquare(x, limit)
\r
4674 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4676 x /= (squareSize + lineGap);
\r
4688 DropEnable dropEnables[] = {
\r
4689 { 'P', DP_Pawn, "Pawn" },
\r
4690 { 'N', DP_Knight, "Knight" },
\r
4691 { 'B', DP_Bishop, "Bishop" },
\r
4692 { 'R', DP_Rook, "Rook" },
\r
4693 { 'Q', DP_Queen, "Queen" },
\r
4697 SetupDropMenu(HMENU hmenu)
\r
4699 int i, count, enable;
\r
4701 extern char white_holding[], black_holding[];
\r
4702 char item[MSG_SIZ];
\r
4704 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4705 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4706 dropEnables[i].piece);
\r
4708 while (p && *p++ == dropEnables[i].piece) count++;
\r
4709 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4710 enable = count > 0 || !appData.testLegality
\r
4711 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4712 && !appData.icsActive);
\r
4713 ModifyMenu(hmenu, dropEnables[i].command,
\r
4714 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4715 dropEnables[i].command, item);
\r
4719 void DragPieceBegin(int x, int y)
\r
4721 dragInfo.lastpos.x = boardRect.left + x;
\r
4722 dragInfo.lastpos.y = boardRect.top + y;
\r
4723 dragInfo.from.x = fromX;
\r
4724 dragInfo.from.y = fromY;
\r
4725 dragInfo.start = dragInfo.from;
\r
4726 SetCapture(hwndMain);
\r
4729 void DragPieceEnd(int x, int y)
\r
4732 dragInfo.start.x = dragInfo.start.y = -1;
\r
4733 dragInfo.from = dragInfo.start;
\r
4734 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4737 /* Event handler for mouse messages */
\r
4739 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4743 static int recursive = 0;
\r
4745 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4748 if (message == WM_MBUTTONUP) {
\r
4749 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4750 to the middle button: we simulate pressing the left button too!
\r
4752 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4753 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4759 pt.x = LOWORD(lParam);
\r
4760 pt.y = HIWORD(lParam);
\r
4761 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4762 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4763 if (!flipView && y >= 0) {
\r
4764 y = BOARD_HEIGHT - 1 - y;
\r
4766 if (flipView && x >= 0) {
\r
4767 x = BOARD_WIDTH - 1 - x;
\r
4770 switch (message) {
\r
4771 case WM_LBUTTONDOWN:
\r
4772 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4773 if (gameMode == EditPosition) {
\r
4774 SetWhiteToPlayEvent();
\r
4775 } else if (gameMode == IcsPlayingBlack ||
\r
4776 gameMode == MachinePlaysWhite) {
\r
4778 } else if (gameMode == EditGame) {
\r
4779 AdjustClock(flipClock, -1);
\r
4781 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4782 if (gameMode == EditPosition) {
\r
4783 SetBlackToPlayEvent();
\r
4784 } else if (gameMode == IcsPlayingWhite ||
\r
4785 gameMode == MachinePlaysBlack) {
\r
4787 } else if (gameMode == EditGame) {
\r
4788 AdjustClock(!flipClock, -1);
\r
4791 dragInfo.start.x = dragInfo.start.y = -1;
\r
4792 dragInfo.from = dragInfo.start;
\r
4793 if(fromX == -1 && frozen) { // not sure where this is for
\r
4794 fromX = fromY = -1;
\r
4795 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4798 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4799 DrawPosition(TRUE, NULL);
\r
4802 case WM_LBUTTONUP:
\r
4803 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4804 DrawPosition(TRUE, NULL);
\r
4807 case WM_MOUSEMOVE:
\r
4808 if ((appData.animateDragging || appData.highlightDragging)
\r
4809 && (wParam & MK_LBUTTON)
\r
4810 && dragInfo.from.x >= 0)
\r
4812 BOOL full_repaint = FALSE;
\r
4814 if (appData.animateDragging) {
\r
4815 dragInfo.pos = pt;
\r
4817 if (appData.highlightDragging) {
\r
4818 SetHighlights(fromX, fromY, x, y);
\r
4819 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4820 full_repaint = TRUE;
\r
4824 DrawPosition( full_repaint, NULL);
\r
4826 dragInfo.lastpos = dragInfo.pos;
\r
4830 case WM_MOUSEWHEEL: // [DM]
\r
4831 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4832 /* Mouse Wheel is being rolled forward
\r
4833 * Play moves forward
\r
4835 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
4836 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4837 /* Mouse Wheel is being rolled backward
\r
4838 * Play moves backward
\r
4840 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
4841 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4845 case WM_MBUTTONDOWN:
\r
4846 case WM_RBUTTONDOWN:
\r
4849 fromX = fromY = -1;
\r
4850 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4851 dragInfo.start.x = dragInfo.start.y = -1;
\r
4852 dragInfo.from = dragInfo.start;
\r
4853 dragInfo.lastpos = dragInfo.pos;
\r
4854 if (appData.highlightDragging) {
\r
4855 ClearHighlights();
\r
4858 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4859 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4860 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
4861 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4862 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
4865 DrawPosition(TRUE, NULL);
\r
4867 switch (gameMode) {
\r
4868 case EditPosition:
\r
4869 case IcsExamining:
\r
4870 if (x < 0 || y < 0) break;
\r
4873 if (message == WM_MBUTTONDOWN) {
\r
4874 buttonCount = 3; /* even if system didn't think so */
\r
4875 if (wParam & MK_SHIFT)
\r
4876 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4878 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4879 } else { /* message == WM_RBUTTONDOWN */
\r
4880 /* Just have one menu, on the right button. Windows users don't
\r
4881 think to try the middle one, and sometimes other software steals
\r
4882 it, or it doesn't really exist. */
\r
4883 if(gameInfo.variant != VariantShogi)
\r
4884 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4886 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4889 case IcsPlayingWhite:
\r
4890 case IcsPlayingBlack:
\r
4892 case MachinePlaysWhite:
\r
4893 case MachinePlaysBlack:
\r
4894 if (appData.testLegality &&
\r
4895 gameInfo.variant != VariantBughouse &&
\r
4896 gameInfo.variant != VariantCrazyhouse) break;
\r
4897 if (x < 0 || y < 0) break;
\r
4900 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4901 SetupDropMenu(hmenu);
\r
4902 MenuPopup(hwnd, pt, hmenu, -1);
\r
4913 /* Preprocess messages for buttons in main window */
\r
4915 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4917 int id = GetWindowLong(hwnd, GWL_ID);
\r
4920 for (i=0; i<N_BUTTONS; i++) {
\r
4921 if (buttonDesc[i].id == id) break;
\r
4923 if (i == N_BUTTONS) return 0;
\r
4924 switch (message) {
\r
4929 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4930 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4937 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4940 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4941 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4942 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4943 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4945 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4947 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4948 PopUpMoveDialog((char)wParam);
\r
4954 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4957 /* Process messages for Promotion dialog box */
\r
4959 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4963 switch (message) {
\r
4964 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4965 /* Center the dialog over the application window */
\r
4966 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4967 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4968 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4969 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4970 SW_SHOW : SW_HIDE);
\r
4971 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4972 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4973 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
4974 PieceToChar(WhiteAngel) != '~') ||
\r
4975 (PieceToChar(BlackAngel) >= 'A' &&
\r
4976 PieceToChar(BlackAngel) != '~') ) ?
\r
4977 SW_SHOW : SW_HIDE);
\r
4978 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4979 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
4980 PieceToChar(WhiteMarshall) != '~') ||
\r
4981 (PieceToChar(BlackMarshall) >= 'A' &&
\r
4982 PieceToChar(BlackMarshall) != '~') ) ?
\r
4983 SW_SHOW : SW_HIDE);
\r
4984 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4985 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
4986 gameInfo.variant != VariantShogi ?
\r
4987 SW_SHOW : SW_HIDE);
\r
4988 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
4989 gameInfo.variant != VariantShogi ?
\r
4990 SW_SHOW : SW_HIDE);
\r
4991 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
4992 gameInfo.variant == VariantShogi ?
\r
4993 SW_SHOW : SW_HIDE);
\r
4994 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
4995 gameInfo.variant == VariantShogi ?
\r
4996 SW_SHOW : SW_HIDE);
\r
4997 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4998 gameInfo.variant == VariantSuper ?
\r
4999 SW_SHOW : SW_HIDE);
\r
5002 case WM_COMMAND: /* message: received a command */
\r
5003 switch (LOWORD(wParam)) {
\r
5005 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5006 ClearHighlights();
\r
5007 DrawPosition(FALSE, NULL);
\r
5010 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5013 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5016 promoChar = PieceToChar(BlackRook);
\r
5019 promoChar = PieceToChar(BlackBishop);
\r
5021 case PB_Chancellor:
\r
5022 promoChar = PieceToChar(BlackMarshall);
\r
5024 case PB_Archbishop:
\r
5025 promoChar = PieceToChar(BlackAngel);
\r
5028 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5033 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5034 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5035 only show the popup when we are already sure the move is valid or
\r
5036 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5037 will figure out it is a promotion from the promoChar. */
\r
5038 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5039 fromX = fromY = -1;
\r
5040 if (!appData.highlightLastMove) {
\r
5041 ClearHighlights();
\r
5042 DrawPosition(FALSE, NULL);
\r
5049 /* Pop up promotion dialog */
\r
5051 PromotionPopup(HWND hwnd)
\r
5055 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5056 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5057 hwnd, (DLGPROC)lpProc);
\r
5058 FreeProcInstance(lpProc);
\r
5064 DrawPosition(TRUE, NULL);
\r
5065 PromotionPopup(hwndMain);
\r
5068 /* Toggle ShowThinking */
\r
5070 ToggleShowThinking()
\r
5072 appData.showThinking = !appData.showThinking;
\r
5073 ShowThinkingEvent();
\r
5077 LoadGameDialog(HWND hwnd, char* title)
\r
5081 char fileTitle[MSG_SIZ];
\r
5082 f = OpenFileDialog(hwnd, "rb", "",
\r
5083 appData.oldSaveStyle ? "gam" : "pgn",
\r
5085 title, &number, fileTitle, NULL);
\r
5087 cmailMsgLoaded = FALSE;
\r
5088 if (number == 0) {
\r
5089 int error = GameListBuild(f);
\r
5091 DisplayError("Cannot build game list", error);
\r
5092 } else if (!ListEmpty(&gameList) &&
\r
5093 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5094 GameListPopUp(f, fileTitle);
\r
5097 GameListDestroy();
\r
5100 LoadGame(f, number, fileTitle, FALSE);
\r
5104 int get_term_width()
\r
5109 HFONT hfont, hold_font;
\r
5114 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5118 // get the text metrics
\r
5119 hdc = GetDC(hText);
\r
5120 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
5121 if (consoleCF.dwEffects & CFE_BOLD)
\r
5122 lf.lfWeight = FW_BOLD;
\r
5123 if (consoleCF.dwEffects & CFE_ITALIC)
\r
5124 lf.lfItalic = TRUE;
\r
5125 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
5126 lf.lfStrikeOut = TRUE;
\r
5127 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
5128 lf.lfUnderline = TRUE;
\r
5129 hfont = CreateFontIndirect(&lf);
\r
5130 hold_font = SelectObject(hdc, hfont);
\r
5131 GetTextMetrics(hdc, &tm);
\r
5132 SelectObject(hdc, hold_font);
\r
5133 DeleteObject(hfont);
\r
5134 ReleaseDC(hText, hdc);
\r
5136 // get the rectangle
\r
5137 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
5139 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
5142 void UpdateICSWidth(HWND hText)
\r
5144 LONG old_width, new_width;
\r
5146 new_width = get_term_width(hText, FALSE);
\r
5147 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
5148 if (new_width != old_width)
\r
5150 ics_update_width(new_width);
\r
5151 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
5156 ChangedConsoleFont()
\r
5159 CHARRANGE tmpsel, sel;
\r
5160 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5161 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5162 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5165 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5166 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5167 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5168 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5169 * size. This was undocumented in the version of MSVC++ that I had
\r
5170 * when I wrote the code, but is apparently documented now.
\r
5172 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5173 cfmt.bCharSet = f->lf.lfCharSet;
\r
5174 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5175 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5176 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5177 /* Why are the following seemingly needed too? */
\r
5178 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5179 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5180 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5182 tmpsel.cpMax = -1; /*999999?*/
\r
5183 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5184 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5185 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5186 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5188 paraf.cbSize = sizeof(paraf);
\r
5189 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5190 paraf.dxStartIndent = 0;
\r
5191 paraf.dxOffset = WRAP_INDENT;
\r
5192 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5193 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5194 UpdateICSWidth(hText);
\r
5197 /*---------------------------------------------------------------------------*\
\r
5199 * Window Proc for main window
\r
5201 \*---------------------------------------------------------------------------*/
\r
5203 /* Process messages for main window, etc. */
\r
5205 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5208 int wmId, wmEvent;
\r
5212 char fileTitle[MSG_SIZ];
\r
5213 char buf[MSG_SIZ];
\r
5214 static SnapData sd;
\r
5216 switch (message) {
\r
5218 case WM_PAINT: /* message: repaint portion of window */
\r
5222 case WM_ERASEBKGND:
\r
5223 if (IsIconic(hwnd)) {
\r
5224 /* Cheat; change the message */
\r
5225 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5227 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5231 case WM_LBUTTONDOWN:
\r
5232 case WM_MBUTTONDOWN:
\r
5233 case WM_RBUTTONDOWN:
\r
5234 case WM_LBUTTONUP:
\r
5235 case WM_MBUTTONUP:
\r
5236 case WM_RBUTTONUP:
\r
5237 case WM_MOUSEMOVE:
\r
5238 case WM_MOUSEWHEEL:
\r
5239 MouseEvent(hwnd, message, wParam, lParam);
\r
5242 JAWS_KB_NAVIGATION
\r
5246 JAWS_ALT_INTERCEPT
\r
5248 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
5249 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5250 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5251 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5253 SendMessage(h, message, wParam, lParam);
\r
5254 } else if(lParam != KF_REPEAT) {
\r
5255 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5256 PopUpMoveDialog((char)wParam);
\r
5257 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5258 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5263 case WM_PALETTECHANGED:
\r
5264 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5266 HDC hdc = GetDC(hwndMain);
\r
5267 SelectPalette(hdc, hPal, TRUE);
\r
5268 nnew = RealizePalette(hdc);
\r
5270 paletteChanged = TRUE;
\r
5271 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5273 ReleaseDC(hwnd, hdc);
\r
5277 case WM_QUERYNEWPALETTE:
\r
5278 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5280 HDC hdc = GetDC(hwndMain);
\r
5281 paletteChanged = FALSE;
\r
5282 SelectPalette(hdc, hPal, FALSE);
\r
5283 nnew = RealizePalette(hdc);
\r
5285 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5287 ReleaseDC(hwnd, hdc);
\r
5292 case WM_COMMAND: /* message: command from application menu */
\r
5293 wmId = LOWORD(wParam);
\r
5294 wmEvent = HIWORD(wParam);
\r
5299 SAY("new game enter a move to play against the computer with white");
\r
5302 case IDM_NewGameFRC:
\r
5303 if( NewGameFRC() == 0 ) {
\r
5308 case IDM_NewVariant:
\r
5309 NewVariantPopup(hwnd);
\r
5312 case IDM_LoadGame:
\r
5313 LoadGameDialog(hwnd, "Load Game from File");
\r
5316 case IDM_LoadNextGame:
\r
5320 case IDM_LoadPrevGame:
\r
5324 case IDM_ReloadGame:
\r
5328 case IDM_LoadPosition:
\r
5329 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5330 Reset(FALSE, TRUE);
\r
5333 f = OpenFileDialog(hwnd, "rb", "",
\r
5334 appData.oldSaveStyle ? "pos" : "fen",
\r
5336 "Load Position from File", &number, fileTitle, NULL);
\r
5338 LoadPosition(f, number, fileTitle);
\r
5342 case IDM_LoadNextPosition:
\r
5343 ReloadPosition(1);
\r
5346 case IDM_LoadPrevPosition:
\r
5347 ReloadPosition(-1);
\r
5350 case IDM_ReloadPosition:
\r
5351 ReloadPosition(0);
\r
5354 case IDM_SaveGame:
\r
5355 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5356 f = OpenFileDialog(hwnd, "a", defName,
\r
5357 appData.oldSaveStyle ? "gam" : "pgn",
\r
5359 "Save Game to File", NULL, fileTitle, NULL);
\r
5361 SaveGame(f, 0, "");
\r
5365 case IDM_SavePosition:
\r
5366 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5367 f = OpenFileDialog(hwnd, "a", defName,
\r
5368 appData.oldSaveStyle ? "pos" : "fen",
\r
5370 "Save Position to File", NULL, fileTitle, NULL);
\r
5372 SavePosition(f, 0, "");
\r
5376 case IDM_SaveDiagram:
\r
5377 defName = "diagram";
\r
5378 f = OpenFileDialog(hwnd, "wb", defName,
\r
5381 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5387 case IDM_CopyGame:
\r
5388 CopyGameToClipboard();
\r
5391 case IDM_PasteGame:
\r
5392 PasteGameFromClipboard();
\r
5395 case IDM_CopyGameListToClipboard:
\r
5396 CopyGameListToClipboard();
\r
5399 /* [AS] Autodetect FEN or PGN data */
\r
5400 case IDM_PasteAny:
\r
5401 PasteGameOrFENFromClipboard();
\r
5404 /* [AS] Move history */
\r
5405 case IDM_ShowMoveHistory:
\r
5406 if( MoveHistoryIsUp() ) {
\r
5407 MoveHistoryPopDown();
\r
5410 MoveHistoryPopUp();
\r
5414 /* [AS] Eval graph */
\r
5415 case IDM_ShowEvalGraph:
\r
5416 if( EvalGraphIsUp() ) {
\r
5417 EvalGraphPopDown();
\r
5421 SetFocus(hwndMain);
\r
5425 /* [AS] Engine output */
\r
5426 case IDM_ShowEngineOutput:
\r
5427 if( EngineOutputIsUp() ) {
\r
5428 EngineOutputPopDown();
\r
5431 EngineOutputPopUp();
\r
5435 /* [AS] User adjudication */
\r
5436 case IDM_UserAdjudication_White:
\r
5437 UserAdjudicationEvent( +1 );
\r
5440 case IDM_UserAdjudication_Black:
\r
5441 UserAdjudicationEvent( -1 );
\r
5444 case IDM_UserAdjudication_Draw:
\r
5445 UserAdjudicationEvent( 0 );
\r
5448 /* [AS] Game list options dialog */
\r
5449 case IDM_GameListOptions:
\r
5450 GameListOptions();
\r
5457 case IDM_CopyPosition:
\r
5458 CopyFENToClipboard();
\r
5461 case IDM_PastePosition:
\r
5462 PasteFENFromClipboard();
\r
5465 case IDM_MailMove:
\r
5469 case IDM_ReloadCMailMsg:
\r
5470 Reset(TRUE, TRUE);
\r
5471 ReloadCmailMsgEvent(FALSE);
\r
5474 case IDM_Minimize:
\r
5475 ShowWindow(hwnd, SW_MINIMIZE);
\r
5482 case IDM_MachineWhite:
\r
5483 MachineWhiteEvent();
\r
5485 * refresh the tags dialog only if it's visible
\r
5487 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5489 tags = PGNTags(&gameInfo);
\r
5490 TagsPopUp(tags, CmailMsg());
\r
5493 SAY("computer starts playing white");
\r
5496 case IDM_MachineBlack:
\r
5497 MachineBlackEvent();
\r
5499 * refresh the tags dialog only if it's visible
\r
5501 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5503 tags = PGNTags(&gameInfo);
\r
5504 TagsPopUp(tags, CmailMsg());
\r
5507 SAY("computer starts playing black");
\r
5510 case IDM_TwoMachines:
\r
5511 TwoMachinesEvent();
\r
5513 * refresh the tags dialog only if it's visible
\r
5515 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5517 tags = PGNTags(&gameInfo);
\r
5518 TagsPopUp(tags, CmailMsg());
\r
5521 SAY("programs start playing each other");
\r
5524 case IDM_AnalysisMode:
\r
5525 if (!first.analysisSupport) {
\r
5526 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5527 DisplayError(buf, 0);
\r
5529 SAY("analyzing current position");
\r
5530 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5531 if (appData.icsActive) {
\r
5532 if (gameMode != IcsObserving) {
\r
5533 sprintf(buf, "You are not observing a game");
\r
5534 DisplayError(buf, 0);
\r
5535 /* secure check */
\r
5536 if (appData.icsEngineAnalyze) {
\r
5537 if (appData.debugMode)
\r
5538 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5539 ExitAnalyzeMode();
\r
5545 /* if enable, user want disable icsEngineAnalyze */
\r
5546 if (appData.icsEngineAnalyze) {
\r
5547 ExitAnalyzeMode();
\r
5551 appData.icsEngineAnalyze = TRUE;
\r
5552 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5555 if (!appData.showThinking) ToggleShowThinking();
\r
5556 AnalyzeModeEvent();
\r
5560 case IDM_AnalyzeFile:
\r
5561 if (!first.analysisSupport) {
\r
5562 char buf[MSG_SIZ];
\r
5563 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5564 DisplayError(buf, 0);
\r
5566 if (!appData.showThinking) ToggleShowThinking();
\r
5567 AnalyzeFileEvent();
\r
5568 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5569 AnalysisPeriodicEvent(1);
\r
5573 case IDM_IcsClient:
\r
5577 case IDM_EditGame:
\r
5582 case IDM_EditPosition:
\r
5583 EditPositionEvent();
\r
5584 SAY("to set up a position type a FEN");
\r
5587 case IDM_Training:
\r
5591 case IDM_ShowGameList:
\r
5592 ShowGameListProc();
\r
5595 case IDM_EditTags:
\r
5599 case IDM_EditComment:
\r
5600 if (commentUp && editComment) {
\r
5603 EditCommentEvent();
\r
5623 case IDM_CallFlag:
\r
5643 case IDM_StopObserving:
\r
5644 StopObservingEvent();
\r
5647 case IDM_StopExamining:
\r
5648 StopExaminingEvent();
\r
5651 case IDM_TypeInMove:
\r
5652 PopUpMoveDialog('\000');
\r
5655 case IDM_TypeInName:
\r
5656 PopUpNameDialog('\000');
\r
5659 case IDM_Backward:
\r
5661 SetFocus(hwndMain);
\r
5668 SetFocus(hwndMain);
\r
5673 SetFocus(hwndMain);
\r
5678 SetFocus(hwndMain);
\r
5685 case IDM_TruncateGame:
\r
5686 TruncateGameEvent();
\r
5693 case IDM_RetractMove:
\r
5694 RetractMoveEvent();
\r
5697 case IDM_FlipView:
\r
5698 flipView = !flipView;
\r
5699 DrawPosition(FALSE, NULL);
\r
5702 case IDM_FlipClock:
\r
5703 flipClock = !flipClock;
\r
5704 DisplayBothClocks();
\r
5705 DrawPosition(FALSE, NULL);
\r
5708 case IDM_MuteSounds:
\r
5709 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5710 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5711 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5714 case IDM_GeneralOptions:
\r
5715 GeneralOptionsPopup(hwnd);
\r
5716 DrawPosition(TRUE, NULL);
\r
5719 case IDM_BoardOptions:
\r
5720 BoardOptionsPopup(hwnd);
\r
5723 case IDM_EnginePlayOptions:
\r
5724 EnginePlayOptionsPopup(hwnd);
\r
5727 case IDM_Engine1Options:
\r
5728 EngineOptionsPopup(hwnd, &first);
\r
5731 case IDM_Engine2Options:
\r
5732 EngineOptionsPopup(hwnd, &second);
\r
5735 case IDM_OptionsUCI:
\r
5736 UciOptionsPopup(hwnd);
\r
5739 case IDM_IcsOptions:
\r
5740 IcsOptionsPopup(hwnd);
\r
5744 FontsOptionsPopup(hwnd);
\r
5748 SoundOptionsPopup(hwnd);
\r
5751 case IDM_CommPort:
\r
5752 CommPortOptionsPopup(hwnd);
\r
5755 case IDM_LoadOptions:
\r
5756 LoadOptionsPopup(hwnd);
\r
5759 case IDM_SaveOptions:
\r
5760 SaveOptionsPopup(hwnd);
\r
5763 case IDM_TimeControl:
\r
5764 TimeControlOptionsPopup(hwnd);
\r
5767 case IDM_SaveSettings:
\r
5768 SaveSettings(settingsFileName);
\r
5771 case IDM_SaveSettingsOnExit:
\r
5772 saveSettingsOnExit = !saveSettingsOnExit;
\r
5773 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5774 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5775 MF_CHECKED : MF_UNCHECKED));
\r
5786 case IDM_AboutGame:
\r
5791 appData.debugMode = !appData.debugMode;
\r
5792 if (appData.debugMode) {
\r
5793 char dir[MSG_SIZ];
\r
5794 GetCurrentDirectory(MSG_SIZ, dir);
\r
5795 SetCurrentDirectory(installDir);
\r
5796 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5797 SetCurrentDirectory(dir);
\r
5798 setbuf(debugFP, NULL);
\r
5805 case IDM_HELPCONTENTS:
\r
5806 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5807 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5808 MessageBox (GetFocus(),
\r
5809 "Unable to activate help",
\r
5810 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5814 case IDM_HELPSEARCH:
\r
5815 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5816 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5817 MessageBox (GetFocus(),
\r
5818 "Unable to activate help",
\r
5819 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5823 case IDM_HELPHELP:
\r
5824 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5825 MessageBox (GetFocus(),
\r
5826 "Unable to activate help",
\r
5827 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5832 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5834 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5835 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5836 FreeProcInstance(lpProc);
\r
5839 case IDM_DirectCommand1:
\r
5840 AskQuestionEvent("Direct Command",
\r
5841 "Send to chess program:", "", "1");
\r
5843 case IDM_DirectCommand2:
\r
5844 AskQuestionEvent("Direct Command",
\r
5845 "Send to second chess program:", "", "2");
\r
5848 case EP_WhitePawn:
\r
5849 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5850 fromX = fromY = -1;
\r
5853 case EP_WhiteKnight:
\r
5854 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5855 fromX = fromY = -1;
\r
5858 case EP_WhiteBishop:
\r
5859 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5860 fromX = fromY = -1;
\r
5863 case EP_WhiteRook:
\r
5864 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5865 fromX = fromY = -1;
\r
5868 case EP_WhiteQueen:
\r
5869 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5870 fromX = fromY = -1;
\r
5873 case EP_WhiteFerz:
\r
5874 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5875 fromX = fromY = -1;
\r
5878 case EP_WhiteWazir:
\r
5879 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5880 fromX = fromY = -1;
\r
5883 case EP_WhiteAlfil:
\r
5884 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5885 fromX = fromY = -1;
\r
5888 case EP_WhiteCannon:
\r
5889 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5890 fromX = fromY = -1;
\r
5893 case EP_WhiteCardinal:
\r
5894 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5895 fromX = fromY = -1;
\r
5898 case EP_WhiteMarshall:
\r
5899 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5900 fromX = fromY = -1;
\r
5903 case EP_WhiteKing:
\r
5904 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5905 fromX = fromY = -1;
\r
5908 case EP_BlackPawn:
\r
5909 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5910 fromX = fromY = -1;
\r
5913 case EP_BlackKnight:
\r
5914 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5915 fromX = fromY = -1;
\r
5918 case EP_BlackBishop:
\r
5919 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5920 fromX = fromY = -1;
\r
5923 case EP_BlackRook:
\r
5924 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5925 fromX = fromY = -1;
\r
5928 case EP_BlackQueen:
\r
5929 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5930 fromX = fromY = -1;
\r
5933 case EP_BlackFerz:
\r
5934 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5935 fromX = fromY = -1;
\r
5938 case EP_BlackWazir:
\r
5939 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5940 fromX = fromY = -1;
\r
5943 case EP_BlackAlfil:
\r
5944 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5945 fromX = fromY = -1;
\r
5948 case EP_BlackCannon:
\r
5949 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5950 fromX = fromY = -1;
\r
5953 case EP_BlackCardinal:
\r
5954 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5955 fromX = fromY = -1;
\r
5958 case EP_BlackMarshall:
\r
5959 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5960 fromX = fromY = -1;
\r
5963 case EP_BlackKing:
\r
5964 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5965 fromX = fromY = -1;
\r
5968 case EP_EmptySquare:
\r
5969 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5970 fromX = fromY = -1;
\r
5973 case EP_ClearBoard:
\r
5974 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5975 fromX = fromY = -1;
\r
5979 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5980 fromX = fromY = -1;
\r
5984 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5985 fromX = fromY = -1;
\r
5989 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5990 fromX = fromY = -1;
\r
5994 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5995 fromX = fromY = -1;
\r
5999 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6000 fromX = fromY = -1;
\r
6004 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6005 fromX = fromY = -1;
\r
6009 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6010 fromX = fromY = -1;
\r
6014 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6015 fromX = fromY = -1;
\r
6019 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6020 fromX = fromY = -1;
\r
6024 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6030 case CLOCK_TIMER_ID:
\r
6031 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6032 clockTimerEvent = 0;
\r
6033 DecrementClocks(); /* call into back end */
\r
6035 case LOAD_GAME_TIMER_ID:
\r
6036 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6037 loadGameTimerEvent = 0;
\r
6038 AutoPlayGameLoop(); /* call into back end */
\r
6040 case ANALYSIS_TIMER_ID:
\r
6041 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6042 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6043 AnalysisPeriodicEvent(0);
\r
6045 KillTimer(hwnd, analysisTimerEvent);
\r
6046 analysisTimerEvent = 0;
\r
6049 case DELAYED_TIMER_ID:
\r
6050 KillTimer(hwnd, delayedTimerEvent);
\r
6051 delayedTimerEvent = 0;
\r
6052 delayedTimerCallback();
\r
6057 case WM_USER_Input:
\r
6058 InputEvent(hwnd, message, wParam, lParam);
\r
6061 /* [AS] Also move "attached" child windows */
\r
6062 case WM_WINDOWPOSCHANGING:
\r
6064 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6065 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6067 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6068 /* Window is moving */
\r
6071 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6072 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
6073 rcMain.right = wpMain.x + wpMain.width;
\r
6074 rcMain.top = wpMain.y;
\r
6075 rcMain.bottom = wpMain.y + wpMain.height;
\r
6077 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6078 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6079 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6080 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6081 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6082 wpMain.x = lpwp->x;
\r
6083 wpMain.y = lpwp->y;
\r
6088 /* [AS] Snapping */
\r
6089 case WM_ENTERSIZEMOVE:
\r
6090 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6091 if (hwnd == hwndMain) {
\r
6092 doingSizing = TRUE;
\r
6095 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6099 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6100 if (hwnd == hwndMain) {
\r
6101 lastSizing = wParam;
\r
6106 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6107 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6109 case WM_EXITSIZEMOVE:
\r
6110 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6111 if (hwnd == hwndMain) {
\r
6113 doingSizing = FALSE;
\r
6114 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6115 GetClientRect(hwnd, &client);
\r
6116 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6118 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6120 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6123 case WM_DESTROY: /* message: window being destroyed */
\r
6124 PostQuitMessage(0);
\r
6128 if (hwnd == hwndMain) {
\r
6133 default: /* Passes it on if unprocessed */
\r
6134 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6139 /*---------------------------------------------------------------------------*\
\r
6141 * Misc utility routines
\r
6143 \*---------------------------------------------------------------------------*/
\r
6146 * Decent random number generator, at least not as bad as Windows
\r
6147 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6149 unsigned int randstate;
\r
6154 randstate = randstate * 1664525 + 1013904223;
\r
6155 return (int) randstate & 0x7fffffff;
\r
6159 mysrandom(unsigned int seed)
\r
6166 * returns TRUE if user selects a different color, FALSE otherwise
\r
6170 ChangeColor(HWND hwnd, COLORREF *which)
\r
6172 static BOOL firstTime = TRUE;
\r
6173 static DWORD customColors[16];
\r
6175 COLORREF newcolor;
\r
6180 /* Make initial colors in use available as custom colors */
\r
6181 /* Should we put the compiled-in defaults here instead? */
\r
6183 customColors[i++] = lightSquareColor & 0xffffff;
\r
6184 customColors[i++] = darkSquareColor & 0xffffff;
\r
6185 customColors[i++] = whitePieceColor & 0xffffff;
\r
6186 customColors[i++] = blackPieceColor & 0xffffff;
\r
6187 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6188 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6190 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6191 customColors[i++] = textAttribs[ccl].color;
\r
6193 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6194 firstTime = FALSE;
\r
6197 cc.lStructSize = sizeof(cc);
\r
6198 cc.hwndOwner = hwnd;
\r
6199 cc.hInstance = NULL;
\r
6200 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6201 cc.lpCustColors = (LPDWORD) customColors;
\r
6202 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6204 if (!ChooseColor(&cc)) return FALSE;
\r
6206 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6207 if (newcolor == *which) return FALSE;
\r
6208 *which = newcolor;
\r
6212 InitDrawingColors();
\r
6213 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6218 MyLoadSound(MySound *ms)
\r
6224 if (ms->data) free(ms->data);
\r
6227 switch (ms->name[0]) {
\r
6233 /* System sound from Control Panel. Don't preload here. */
\r
6237 if (ms->name[1] == NULLCHAR) {
\r
6238 /* "!" alone = silence */
\r
6241 /* Builtin wave resource. Error if not found. */
\r
6242 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6243 if (h == NULL) break;
\r
6244 ms->data = (void *)LoadResource(hInst, h);
\r
6245 if (h == NULL) break;
\r
6250 /* .wav file. Error if not found. */
\r
6251 f = fopen(ms->name, "rb");
\r
6252 if (f == NULL) break;
\r
6253 if (fstat(fileno(f), &st) < 0) break;
\r
6254 ms->data = malloc(st.st_size);
\r
6255 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6261 char buf[MSG_SIZ];
\r
6262 sprintf(buf, "Error loading sound %s", ms->name);
\r
6263 DisplayError(buf, GetLastError());
\r
6269 MyPlaySound(MySound *ms)
\r
6271 BOOLEAN ok = FALSE;
\r
6273 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6274 switch (ms->name[0]) {
\r
6276 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6281 /* System sound from Control Panel (deprecated feature).
\r
6282 "$" alone or an unset sound name gets default beep (still in use). */
\r
6283 if (ms->name[1]) {
\r
6284 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6286 if (!ok) ok = MessageBeep(MB_OK);
\r
6289 /* Builtin wave resource, or "!" alone for silence */
\r
6290 if (ms->name[1]) {
\r
6291 if (ms->data == NULL) return FALSE;
\r
6292 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6298 /* .wav file. Error if not found. */
\r
6299 if (ms->data == NULL) return FALSE;
\r
6300 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6303 /* Don't print an error: this can happen innocently if the sound driver
\r
6304 is busy; for instance, if another instance of WinBoard is playing
\r
6305 a sound at about the same time. */
\r
6311 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6314 OPENFILENAME *ofn;
\r
6315 static UINT *number; /* gross that this is static */
\r
6317 switch (message) {
\r
6318 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6319 /* Center the dialog over the application window */
\r
6320 ofn = (OPENFILENAME *) lParam;
\r
6321 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6322 number = (UINT *) ofn->lCustData;
\r
6323 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6327 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6328 return FALSE; /* Allow for further processing */
\r
6331 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6332 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6334 return FALSE; /* Allow for further processing */
\r
6340 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6342 static UINT *number;
\r
6343 OPENFILENAME *ofname;
\r
6346 case WM_INITDIALOG:
\r
6347 ofname = (OPENFILENAME *)lParam;
\r
6348 number = (UINT *)(ofname->lCustData);
\r
6351 ofnot = (OFNOTIFY *)lParam;
\r
6352 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6353 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6362 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6363 char *nameFilt, char *dlgTitle, UINT *number,
\r
6364 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6366 OPENFILENAME openFileName;
\r
6367 char buf1[MSG_SIZ];
\r
6370 if (fileName == NULL) fileName = buf1;
\r
6371 if (defName == NULL) {
\r
6372 strcpy(fileName, "*.");
\r
6373 strcat(fileName, defExt);
\r
6375 strcpy(fileName, defName);
\r
6377 if (fileTitle) strcpy(fileTitle, "");
\r
6378 if (number) *number = 0;
\r
6380 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6381 openFileName.hwndOwner = hwnd;
\r
6382 openFileName.hInstance = (HANDLE) hInst;
\r
6383 openFileName.lpstrFilter = nameFilt;
\r
6384 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6385 openFileName.nMaxCustFilter = 0L;
\r
6386 openFileName.nFilterIndex = 1L;
\r
6387 openFileName.lpstrFile = fileName;
\r
6388 openFileName.nMaxFile = MSG_SIZ;
\r
6389 openFileName.lpstrFileTitle = fileTitle;
\r
6390 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6391 openFileName.lpstrInitialDir = NULL;
\r
6392 openFileName.lpstrTitle = dlgTitle;
\r
6393 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6394 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6395 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6396 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6397 openFileName.nFileOffset = 0;
\r
6398 openFileName.nFileExtension = 0;
\r
6399 openFileName.lpstrDefExt = defExt;
\r
6400 openFileName.lCustData = (LONG) number;
\r
6401 openFileName.lpfnHook = oldDialog ?
\r
6402 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6403 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6405 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6406 GetOpenFileName(&openFileName)) {
\r
6407 /* open the file */
\r
6408 f = fopen(openFileName.lpstrFile, write);
\r
6410 MessageBox(hwnd, "File open failed", NULL,
\r
6411 MB_OK|MB_ICONEXCLAMATION);
\r
6415 int err = CommDlgExtendedError();
\r
6416 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6425 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6427 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6430 * Get the first pop-up menu in the menu template. This is the
\r
6431 * menu that TrackPopupMenu displays.
\r
6433 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6435 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6438 * TrackPopup uses screen coordinates, so convert the
\r
6439 * coordinates of the mouse click to screen coordinates.
\r
6441 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6443 /* Draw and track the floating pop-up menu. */
\r
6444 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6445 pt.x, pt.y, 0, hwnd, NULL);
\r
6447 /* Destroy the menu.*/
\r
6448 DestroyMenu(hmenu);
\r
6453 int sizeX, sizeY, newSizeX, newSizeY;
\r
6455 } ResizeEditPlusButtonsClosure;
\r
6458 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6460 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6464 if (hChild == cl->hText) return TRUE;
\r
6465 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6466 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6467 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6468 ScreenToClient(cl->hDlg, &pt);
\r
6469 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6470 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6474 /* Resize a dialog that has a (rich) edit field filling most of
\r
6475 the top, with a row of buttons below */
\r
6477 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6480 int newTextHeight, newTextWidth;
\r
6481 ResizeEditPlusButtonsClosure cl;
\r
6483 /*if (IsIconic(hDlg)) return;*/
\r
6484 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6486 cl.hdwp = BeginDeferWindowPos(8);
\r
6488 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6489 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6490 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6491 if (newTextHeight < 0) {
\r
6492 newSizeY += -newTextHeight;
\r
6493 newTextHeight = 0;
\r
6495 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6496 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6502 cl.newSizeX = newSizeX;
\r
6503 cl.newSizeY = newSizeY;
\r
6504 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6506 EndDeferWindowPos(cl.hdwp);
\r
6509 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6511 RECT rChild, rParent;
\r
6512 int wChild, hChild, wParent, hParent;
\r
6513 int wScreen, hScreen, xNew, yNew;
\r
6516 /* Get the Height and Width of the child window */
\r
6517 GetWindowRect (hwndChild, &rChild);
\r
6518 wChild = rChild.right - rChild.left;
\r
6519 hChild = rChild.bottom - rChild.top;
\r
6521 /* Get the Height and Width of the parent window */
\r
6522 GetWindowRect (hwndParent, &rParent);
\r
6523 wParent = rParent.right - rParent.left;
\r
6524 hParent = rParent.bottom - rParent.top;
\r
6526 /* Get the display limits */
\r
6527 hdc = GetDC (hwndChild);
\r
6528 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6529 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6530 ReleaseDC(hwndChild, hdc);
\r
6532 /* Calculate new X position, then adjust for screen */
\r
6533 xNew = rParent.left + ((wParent - wChild) /2);
\r
6536 } else if ((xNew+wChild) > wScreen) {
\r
6537 xNew = wScreen - wChild;
\r
6540 /* Calculate new Y position, then adjust for screen */
\r
6542 yNew = rParent.top + ((hParent - hChild) /2);
\r
6545 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6550 } else if ((yNew+hChild) > hScreen) {
\r
6551 yNew = hScreen - hChild;
\r
6554 /* Set it, and return */
\r
6555 return SetWindowPos (hwndChild, NULL,
\r
6556 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6559 /* Center one window over another */
\r
6560 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6562 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6565 /*---------------------------------------------------------------------------*\
\r
6567 * Startup Dialog functions
\r
6569 \*---------------------------------------------------------------------------*/
\r
6571 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6573 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6575 while (*cd != NULL) {
\r
6576 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6582 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6584 char buf1[ARG_MAX];
\r
6587 if (str[0] == '@') {
\r
6588 FILE* f = fopen(str + 1, "r");
\r
6590 DisplayFatalError(str + 1, errno, 2);
\r
6593 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6595 buf1[len] = NULLCHAR;
\r
6599 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6602 char buf[MSG_SIZ];
\r
6603 char *end = strchr(str, '\n');
\r
6604 if (end == NULL) return;
\r
6605 memcpy(buf, str, end - str);
\r
6606 buf[end - str] = NULLCHAR;
\r
6607 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6613 SetStartupDialogEnables(HWND hDlg)
\r
6615 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6616 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6617 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6618 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6619 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6620 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6621 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6622 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6623 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6624 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6625 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6626 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6627 IsDlgButtonChecked(hDlg, OPT_View));
\r
6631 QuoteForFilename(char *filename)
\r
6633 int dquote, space;
\r
6634 dquote = strchr(filename, '"') != NULL;
\r
6635 space = strchr(filename, ' ') != NULL;
\r
6636 if (dquote || space) {
\r
6648 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6650 char buf[MSG_SIZ];
\r
6653 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6654 q = QuoteForFilename(nthcp);
\r
6655 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6656 if (*nthdir != NULLCHAR) {
\r
6657 q = QuoteForFilename(nthdir);
\r
6658 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6660 if (*nthcp == NULLCHAR) {
\r
6661 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6662 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6663 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6664 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6669 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6671 char buf[MSG_SIZ];
\r
6675 switch (message) {
\r
6676 case WM_INITDIALOG:
\r
6677 /* Center the dialog */
\r
6678 CenterWindow (hDlg, GetDesktopWindow());
\r
6679 /* Initialize the dialog items */
\r
6680 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6681 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6682 firstChessProgramNames);
\r
6683 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6684 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6685 secondChessProgramNames);
\r
6686 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6687 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6688 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6689 if (*appData.icsHelper != NULLCHAR) {
\r
6690 char *q = QuoteForFilename(appData.icsHelper);
\r
6691 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6693 if (*appData.icsHost == NULLCHAR) {
\r
6694 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6695 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6696 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6697 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6698 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6701 if (appData.icsActive) {
\r
6702 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6704 else if (appData.noChessProgram) {
\r
6705 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6708 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6711 SetStartupDialogEnables(hDlg);
\r
6715 switch (LOWORD(wParam)) {
\r
6717 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6718 strcpy(buf, "/fcp=");
\r
6719 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6721 ParseArgs(StringGet, &p);
\r
6722 strcpy(buf, "/scp=");
\r
6723 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6725 ParseArgs(StringGet, &p);
\r
6726 appData.noChessProgram = FALSE;
\r
6727 appData.icsActive = FALSE;
\r
6728 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6729 strcpy(buf, "/ics /icshost=");
\r
6730 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6732 ParseArgs(StringGet, &p);
\r
6733 if (appData.zippyPlay) {
\r
6734 strcpy(buf, "/fcp=");
\r
6735 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6737 ParseArgs(StringGet, &p);
\r
6739 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6740 appData.noChessProgram = TRUE;
\r
6741 appData.icsActive = FALSE;
\r
6743 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6744 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6747 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6748 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6750 ParseArgs(StringGet, &p);
\r
6752 EndDialog(hDlg, TRUE);
\r
6759 case IDM_HELPCONTENTS:
\r
6760 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6761 MessageBox (GetFocus(),
\r
6762 "Unable to activate help",
\r
6763 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6768 SetStartupDialogEnables(hDlg);
\r
6776 /*---------------------------------------------------------------------------*\
\r
6778 * About box dialog functions
\r
6780 \*---------------------------------------------------------------------------*/
\r
6782 /* Process messages for "About" dialog box */
\r
6784 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6786 switch (message) {
\r
6787 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6788 /* Center the dialog over the application window */
\r
6789 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6790 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6794 case WM_COMMAND: /* message: received a command */
\r
6795 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6796 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6797 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6805 /*---------------------------------------------------------------------------*\
\r
6807 * Comment Dialog functions
\r
6809 \*---------------------------------------------------------------------------*/
\r
6812 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6814 static HANDLE hwndText = NULL;
\r
6815 int len, newSizeX, newSizeY, flags;
\r
6816 static int sizeX, sizeY;
\r
6821 switch (message) {
\r
6822 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6823 /* Initialize the dialog items */
\r
6824 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6825 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6826 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6827 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6828 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6829 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6830 SetWindowText(hDlg, commentTitle);
\r
6831 if (editComment) {
\r
6832 SetFocus(hwndText);
\r
6834 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6836 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6837 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6838 MAKELPARAM(FALSE, 0));
\r
6839 /* Size and position the dialog */
\r
6840 if (!commentDialog) {
\r
6841 commentDialog = hDlg;
\r
6842 flags = SWP_NOZORDER;
\r
6843 GetClientRect(hDlg, &rect);
\r
6844 sizeX = rect.right;
\r
6845 sizeY = rect.bottom;
\r
6846 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6847 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6848 WINDOWPLACEMENT wp;
\r
6849 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6850 wp.length = sizeof(WINDOWPLACEMENT);
\r
6852 wp.showCmd = SW_SHOW;
\r
6853 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6854 wp.rcNormalPosition.left = wpComment.x;
\r
6855 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6856 wp.rcNormalPosition.top = wpComment.y;
\r
6857 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6858 SetWindowPlacement(hDlg, &wp);
\r
6860 GetClientRect(hDlg, &rect);
\r
6861 newSizeX = rect.right;
\r
6862 newSizeY = rect.bottom;
\r
6863 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6864 newSizeX, newSizeY);
\r
6871 case WM_COMMAND: /* message: received a command */
\r
6872 switch (LOWORD(wParam)) {
\r
6874 if (editComment) {
\r
6876 /* Read changed options from the dialog box */
\r
6877 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6878 len = GetWindowTextLength(hwndText);
\r
6879 str = (char *) malloc(len + 1);
\r
6880 GetWindowText(hwndText, str, len + 1);
\r
6889 ReplaceComment(commentIndex, str);
\r
6896 case OPT_CancelComment:
\r
6900 case OPT_ClearComment:
\r
6901 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6904 case OPT_EditComment:
\r
6905 EditCommentEvent();
\r
6914 newSizeX = LOWORD(lParam);
\r
6915 newSizeY = HIWORD(lParam);
\r
6916 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6921 case WM_GETMINMAXINFO:
\r
6922 /* Prevent resizing window too small */
\r
6923 mmi = (MINMAXINFO *) lParam;
\r
6924 mmi->ptMinTrackSize.x = 100;
\r
6925 mmi->ptMinTrackSize.y = 100;
\r
6932 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6937 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6939 if (str == NULL) str = "";
\r
6940 p = (char *) malloc(2 * strlen(str) + 2);
\r
6943 if (*str == '\n') *q++ = '\r';
\r
6947 if (commentText != NULL) free(commentText);
\r
6949 commentIndex = index;
\r
6950 commentTitle = title;
\r
6952 editComment = edit;
\r
6954 if (commentDialog) {
\r
6955 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6956 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6958 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6959 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6960 hwndMain, (DLGPROC)lpProc);
\r
6961 FreeProcInstance(lpProc);
\r
6967 /*---------------------------------------------------------------------------*\
\r
6969 * Type-in move dialog functions
\r
6971 \*---------------------------------------------------------------------------*/
\r
6974 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6976 char move[MSG_SIZ];
\r
6978 ChessMove moveType;
\r
6979 int fromX, fromY, toX, toY;
\r
6982 switch (message) {
\r
6983 case WM_INITDIALOG:
\r
6984 move[0] = (char) lParam;
\r
6985 move[1] = NULLCHAR;
\r
6986 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6987 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6988 SetWindowText(hInput, move);
\r
6990 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6994 switch (LOWORD(wParam)) {
\r
6996 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6997 { int n; Board board;
\r
6999 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7000 EditPositionPasteFEN(move);
\r
7001 EndDialog(hDlg, TRUE);
\r
7004 // [HGM] movenum: allow move number to be typed in any mode
\r
7005 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7007 EndDialog(hDlg, TRUE);
\r
7011 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7012 gameMode != Training) {
\r
7013 DisplayMoveError("Displayed move is not current");
\r
7015 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7016 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7017 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7018 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7019 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7020 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7021 if (gameMode != Training)
\r
7022 forwardMostMove = currentMove;
\r
7023 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7025 DisplayMoveError("Could not parse move");
\r
7028 EndDialog(hDlg, TRUE);
\r
7031 EndDialog(hDlg, FALSE);
\r
7042 PopUpMoveDialog(char firstchar)
\r
7046 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7047 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7048 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7049 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7050 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7051 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7052 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7053 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7054 gameMode == Training) {
\r
7055 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7056 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7057 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7058 FreeProcInstance(lpProc);
\r
7062 /*---------------------------------------------------------------------------*\
\r
7064 * Type-in name dialog functions
\r
7066 \*---------------------------------------------------------------------------*/
\r
7069 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7071 char move[MSG_SIZ];
\r
7074 switch (message) {
\r
7075 case WM_INITDIALOG:
\r
7076 move[0] = (char) lParam;
\r
7077 move[1] = NULLCHAR;
\r
7078 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7079 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7080 SetWindowText(hInput, move);
\r
7082 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7086 switch (LOWORD(wParam)) {
\r
7088 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7089 appData.userName = strdup(move);
\r
7092 EndDialog(hDlg, TRUE);
\r
7095 EndDialog(hDlg, FALSE);
\r
7106 PopUpNameDialog(char firstchar)
\r
7110 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7111 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7112 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7113 FreeProcInstance(lpProc);
\r
7116 /*---------------------------------------------------------------------------*\
\r
7120 \*---------------------------------------------------------------------------*/
\r
7122 /* Nonmodal error box */
\r
7123 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7124 WPARAM wParam, LPARAM lParam);
\r
7127 ErrorPopUp(char *title, char *content)
\r
7131 BOOLEAN modal = hwndMain == NULL;
\r
7149 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7150 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7153 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7155 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7156 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7157 hwndMain, (DLGPROC)lpProc);
\r
7158 FreeProcInstance(lpProc);
\r
7165 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7166 if (errorDialog == NULL) return;
\r
7167 DestroyWindow(errorDialog);
\r
7168 errorDialog = NULL;
\r
7172 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7177 switch (message) {
\r
7178 case WM_INITDIALOG:
\r
7179 GetWindowRect(hDlg, &rChild);
\r
7182 SetWindowPos(hDlg, NULL, rChild.left,
\r
7183 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7184 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7188 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7189 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7190 and it doesn't work when you resize the dialog.
\r
7191 For now, just give it a default position.
\r
7193 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7195 errorDialog = hDlg;
\r
7196 SetWindowText(hDlg, errorTitle);
\r
7197 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7198 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7202 switch (LOWORD(wParam)) {
\r
7205 if (errorDialog == hDlg) errorDialog = NULL;
\r
7206 DestroyWindow(hDlg);
\r
7218 HWND gothicDialog = NULL;
\r
7221 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7225 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7227 switch (message) {
\r
7228 case WM_INITDIALOG:
\r
7229 GetWindowRect(hDlg, &rChild);
\r
7231 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
7235 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7236 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7237 and it doesn't work when you resize the dialog.
\r
7238 For now, just give it a default position.
\r
7240 gothicDialog = hDlg;
\r
7241 SetWindowText(hDlg, errorTitle);
\r
7242 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7243 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7247 switch (LOWORD(wParam)) {
\r
7250 if (errorDialog == hDlg) errorDialog = NULL;
\r
7251 DestroyWindow(hDlg);
\r
7263 GothicPopUp(char *title, VariantClass variant)
\r
7266 static char *lastTitle;
\r
7268 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7269 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7271 if(lastTitle != title && gothicDialog != NULL) {
\r
7272 DestroyWindow(gothicDialog);
\r
7273 gothicDialog = NULL;
\r
7275 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7276 title = lastTitle;
\r
7277 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7278 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7279 hwndMain, (DLGPROC)lpProc);
\r
7280 FreeProcInstance(lpProc);
\r
7285 /*---------------------------------------------------------------------------*\
\r
7287 * Ics Interaction console functions
\r
7289 \*---------------------------------------------------------------------------*/
\r
7291 #define HISTORY_SIZE 64
\r
7292 static char *history[HISTORY_SIZE];
\r
7293 int histIn = 0, histP = 0;
\r
7296 SaveInHistory(char *cmd)
\r
7298 if (history[histIn] != NULL) {
\r
7299 free(history[histIn]);
\r
7300 history[histIn] = NULL;
\r
7302 if (*cmd == NULLCHAR) return;
\r
7303 history[histIn] = StrSave(cmd);
\r
7304 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7305 if (history[histIn] != NULL) {
\r
7306 free(history[histIn]);
\r
7307 history[histIn] = NULL;
\r
7313 PrevInHistory(char *cmd)
\r
7316 if (histP == histIn) {
\r
7317 if (history[histIn] != NULL) free(history[histIn]);
\r
7318 history[histIn] = StrSave(cmd);
\r
7320 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7321 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7323 return history[histP];
\r
7329 if (histP == histIn) return NULL;
\r
7330 histP = (histP + 1) % HISTORY_SIZE;
\r
7331 return history[histP];
\r
7338 BOOLEAN immediate;
\r
7339 } IcsTextMenuEntry;
\r
7340 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7341 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7344 ParseIcsTextMenu(char *icsTextMenuString)
\r
7347 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7348 char *p = icsTextMenuString;
\r
7349 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7352 if (e->command != NULL) {
\r
7354 e->command = NULL;
\r
7358 e = icsTextMenuEntry;
\r
7359 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7360 if (*p == ';' || *p == '\n') {
\r
7361 e->item = strdup("-");
\r
7362 e->command = NULL;
\r
7364 } else if (*p == '-') {
\r
7365 e->item = strdup("-");
\r
7366 e->command = NULL;
\r
7370 char *q, *r, *s, *t;
\r
7372 q = strchr(p, ',');
\r
7373 if (q == NULL) break;
\r
7375 r = strchr(q + 1, ',');
\r
7376 if (r == NULL) break;
\r
7378 s = strchr(r + 1, ',');
\r
7379 if (s == NULL) break;
\r
7382 t = strchr(s + 1, c);
\r
7385 t = strchr(s + 1, c);
\r
7387 if (t != NULL) *t = NULLCHAR;
\r
7388 e->item = strdup(p);
\r
7389 e->command = strdup(q + 1);
\r
7390 e->getname = *(r + 1) != '0';
\r
7391 e->immediate = *(s + 1) != '0';
\r
7395 if (t == NULL) break;
\r
7404 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7408 hmenu = LoadMenu(hInst, "TextMenu");
\r
7409 h = GetSubMenu(hmenu, 0);
\r
7411 if (strcmp(e->item, "-") == 0) {
\r
7412 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7414 if (e->item[0] == '|') {
\r
7415 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7416 IDM_CommandX + i, &e->item[1]);
\r
7418 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7427 WNDPROC consoleTextWindowProc;
\r
7430 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7432 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7433 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7437 SetWindowText(hInput, command);
\r
7439 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7441 sel.cpMin = 999999;
\r
7442 sel.cpMax = 999999;
\r
7443 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7448 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7449 if (sel.cpMin == sel.cpMax) {
\r
7450 /* Expand to surrounding word */
\r
7453 tr.chrg.cpMax = sel.cpMin;
\r
7454 tr.chrg.cpMin = --sel.cpMin;
\r
7455 if (sel.cpMin < 0) break;
\r
7456 tr.lpstrText = name;
\r
7457 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7458 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7462 tr.chrg.cpMin = sel.cpMax;
\r
7463 tr.chrg.cpMax = ++sel.cpMax;
\r
7464 tr.lpstrText = name;
\r
7465 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7466 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7469 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7470 MessageBeep(MB_ICONEXCLAMATION);
\r
7474 tr.lpstrText = name;
\r
7475 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7477 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7478 MessageBeep(MB_ICONEXCLAMATION);
\r
7481 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7484 sprintf(buf, "%s %s", command, name);
\r
7485 SetWindowText(hInput, buf);
\r
7486 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7488 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7489 SetWindowText(hInput, buf);
\r
7490 sel.cpMin = 999999;
\r
7491 sel.cpMax = 999999;
\r
7492 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7498 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7503 switch (message) {
\r
7505 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7508 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7511 sel.cpMin = 999999;
\r
7512 sel.cpMax = 999999;
\r
7513 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7514 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7519 if(wParam != '\022') {
\r
7520 if (wParam == '\t') {
\r
7521 if (GetKeyState(VK_SHIFT) < 0) {
\r
7523 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7524 if (buttonDesc[0].hwnd) {
\r
7525 SetFocus(buttonDesc[0].hwnd);
\r
7527 SetFocus(hwndMain);
\r
7531 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7534 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7535 JAWS_DELETE( SetFocus(hInput); )
\r
7536 SendMessage(hInput, message, wParam, lParam);
\r
7539 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7540 case WM_RBUTTONUP:
\r
7541 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7542 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7543 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7546 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7547 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7548 if (sel.cpMin == sel.cpMax) {
\r
7549 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7550 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7552 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7553 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7555 pt.x = LOWORD(lParam);
\r
7556 pt.y = HIWORD(lParam);
\r
7557 MenuPopup(hwnd, pt, hmenu, -1);
\r
7561 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7563 return SendMessage(hInput, message, wParam, lParam);
\r
7564 case WM_MBUTTONDOWN:
\r
7565 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7566 case WM_RBUTTONDOWN:
\r
7567 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7568 /* Move selection here if it was empty */
\r
7570 pt.x = LOWORD(lParam);
\r
7571 pt.y = HIWORD(lParam);
\r
7572 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7573 if (sel.cpMin == sel.cpMax) {
\r
7574 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7575 sel.cpMax = sel.cpMin;
\r
7576 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7578 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7582 switch (LOWORD(wParam)) {
\r
7583 case IDM_QuickPaste:
\r
7585 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7586 if (sel.cpMin == sel.cpMax) {
\r
7587 MessageBeep(MB_ICONEXCLAMATION);
\r
7590 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7591 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7592 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7597 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7600 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7603 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7607 int i = LOWORD(wParam) - IDM_CommandX;
\r
7608 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7609 icsTextMenuEntry[i].command != NULL) {
\r
7610 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7611 icsTextMenuEntry[i].getname,
\r
7612 icsTextMenuEntry[i].immediate);
\r
7620 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7623 WNDPROC consoleInputWindowProc;
\r
7626 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7628 char buf[MSG_SIZ];
\r
7630 static BOOL sendNextChar = FALSE;
\r
7631 static BOOL quoteNextChar = FALSE;
\r
7632 InputSource *is = consoleInputSource;
\r
7636 switch (message) {
\r
7638 if (!appData.localLineEditing || sendNextChar) {
\r
7639 is->buf[0] = (CHAR) wParam;
\r
7641 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7642 sendNextChar = FALSE;
\r
7645 if (quoteNextChar) {
\r
7646 buf[0] = (char) wParam;
\r
7647 buf[1] = NULLCHAR;
\r
7648 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7649 quoteNextChar = FALSE;
\r
7653 case '\r': /* Enter key */
\r
7654 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7655 if (consoleEcho) SaveInHistory(is->buf);
\r
7656 is->buf[is->count++] = '\n';
\r
7657 is->buf[is->count] = NULLCHAR;
\r
7658 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7659 if (consoleEcho) {
\r
7660 ConsoleOutput(is->buf, is->count, TRUE);
\r
7661 } else if (appData.localLineEditing) {
\r
7662 ConsoleOutput("\n", 1, TRUE);
\r
7665 case '\033': /* Escape key */
\r
7666 SetWindowText(hwnd, "");
\r
7667 cf.cbSize = sizeof(CHARFORMAT);
\r
7668 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7669 if (consoleEcho) {
\r
7670 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7672 cf.crTextColor = COLOR_ECHOOFF;
\r
7674 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7675 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7677 case '\t': /* Tab key */
\r
7678 if (GetKeyState(VK_SHIFT) < 0) {
\r
7680 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7683 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7684 if (buttonDesc[0].hwnd) {
\r
7685 SetFocus(buttonDesc[0].hwnd);
\r
7687 SetFocus(hwndMain);
\r
7691 case '\023': /* Ctrl+S */
\r
7692 sendNextChar = TRUE;
\r
7694 case '\021': /* Ctrl+Q */
\r
7695 quoteNextChar = TRUE;
\r
7705 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7706 p = PrevInHistory(buf);
\r
7708 SetWindowText(hwnd, p);
\r
7709 sel.cpMin = 999999;
\r
7710 sel.cpMax = 999999;
\r
7711 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7716 p = NextInHistory();
\r
7718 SetWindowText(hwnd, p);
\r
7719 sel.cpMin = 999999;
\r
7720 sel.cpMax = 999999;
\r
7721 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7727 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7731 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7735 case WM_MBUTTONDOWN:
\r
7736 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7737 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7739 case WM_RBUTTONUP:
\r
7740 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7741 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7742 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7746 hmenu = LoadMenu(hInst, "InputMenu");
\r
7747 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7748 if (sel.cpMin == sel.cpMax) {
\r
7749 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7750 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7752 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7753 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7755 pt.x = LOWORD(lParam);
\r
7756 pt.y = HIWORD(lParam);
\r
7757 MenuPopup(hwnd, pt, hmenu, -1);
\r
7761 switch (LOWORD(wParam)) {
\r
7763 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7765 case IDM_SelectAll:
\r
7767 sel.cpMax = -1; /*999999?*/
\r
7768 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7771 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7774 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7777 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7782 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7785 #define CO_MAX 100000
\r
7786 #define CO_TRIM 1000
\r
7789 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7791 static SnapData sd;
\r
7792 HWND hText, hInput;
\r
7794 static int sizeX, sizeY;
\r
7795 int newSizeX, newSizeY;
\r
7799 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7800 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7802 switch (message) {
\r
7804 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7806 ENLINK *pLink = (ENLINK*)lParam;
\r
7807 if (pLink->msg == WM_LBUTTONUP)
\r
7811 tr.chrg = pLink->chrg;
\r
7812 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7813 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7814 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7815 free(tr.lpstrText);
\r
7819 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7820 hwndConsole = hDlg;
\r
7822 consoleTextWindowProc = (WNDPROC)
\r
7823 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7824 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7825 consoleInputWindowProc = (WNDPROC)
\r
7826 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7827 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7828 Colorize(ColorNormal, TRUE);
\r
7829 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7830 ChangedConsoleFont();
\r
7831 GetClientRect(hDlg, &rect);
\r
7832 sizeX = rect.right;
\r
7833 sizeY = rect.bottom;
\r
7834 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7835 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7836 WINDOWPLACEMENT wp;
\r
7837 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7838 wp.length = sizeof(WINDOWPLACEMENT);
\r
7840 wp.showCmd = SW_SHOW;
\r
7841 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7842 wp.rcNormalPosition.left = wpConsole.x;
\r
7843 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7844 wp.rcNormalPosition.top = wpConsole.y;
\r
7845 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7846 SetWindowPlacement(hDlg, &wp);
\r
7849 // [HGM] Chessknight's change 2004-07-13
\r
7850 else { /* Determine Defaults */
\r
7851 WINDOWPLACEMENT wp;
\r
7852 wpConsole.x = wpMain.width + 1;
\r
7853 wpConsole.y = wpMain.y;
\r
7854 wpConsole.width = screenWidth - wpMain.width;
\r
7855 wpConsole.height = wpMain.height;
\r
7856 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7857 wp.length = sizeof(WINDOWPLACEMENT);
\r
7859 wp.showCmd = SW_SHOW;
\r
7860 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7861 wp.rcNormalPosition.left = wpConsole.x;
\r
7862 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7863 wp.rcNormalPosition.top = wpConsole.y;
\r
7864 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7865 SetWindowPlacement(hDlg, &wp);
\r
7868 // Allow hText to highlight URLs and send notifications on them
\r
7869 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7870 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7871 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7872 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
7886 if (IsIconic(hDlg)) break;
\r
7887 newSizeX = LOWORD(lParam);
\r
7888 newSizeY = HIWORD(lParam);
\r
7889 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7890 RECT rectText, rectInput;
\r
7892 int newTextHeight, newTextWidth;
\r
7893 GetWindowRect(hText, &rectText);
\r
7894 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7895 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7896 if (newTextHeight < 0) {
\r
7897 newSizeY += -newTextHeight;
\r
7898 newTextHeight = 0;
\r
7900 SetWindowPos(hText, NULL, 0, 0,
\r
7901 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7902 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7903 pt.x = rectInput.left;
\r
7904 pt.y = rectInput.top + newSizeY - sizeY;
\r
7905 ScreenToClient(hDlg, &pt);
\r
7906 SetWindowPos(hInput, NULL,
\r
7907 pt.x, pt.y, /* needs client coords */
\r
7908 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7909 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7915 case WM_GETMINMAXINFO:
\r
7916 /* Prevent resizing window too small */
\r
7917 mmi = (MINMAXINFO *) lParam;
\r
7918 mmi->ptMinTrackSize.x = 100;
\r
7919 mmi->ptMinTrackSize.y = 100;
\r
7922 /* [AS] Snapping */
\r
7923 case WM_ENTERSIZEMOVE:
\r
7924 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7927 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7930 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7932 case WM_EXITSIZEMOVE:
\r
7933 UpdateICSWidth(hText);
\r
7934 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7937 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7945 if (hwndConsole) return;
\r
7946 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7947 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7952 ConsoleOutput(char* data, int length, int forceVisible)
\r
7957 char buf[CO_MAX+1];
\r
7960 static int delayLF = 0;
\r
7961 CHARRANGE savesel, sel;
\r
7963 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7971 while (length--) {
\r
7979 } else if (*p == '\007') {
\r
7980 MyPlaySound(&sounds[(int)SoundBell]);
\r
7987 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7988 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7989 /* Save current selection */
\r
7990 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7991 exlen = GetWindowTextLength(hText);
\r
7992 /* Find out whether current end of text is visible */
\r
7993 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7994 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7995 /* Trim existing text if it's too long */
\r
7996 if (exlen + (q - buf) > CO_MAX) {
\r
7997 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8000 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8001 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8003 savesel.cpMin -= trim;
\r
8004 savesel.cpMax -= trim;
\r
8005 if (exlen < 0) exlen = 0;
\r
8006 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8007 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8009 /* Append the new text */
\r
8010 sel.cpMin = exlen;
\r
8011 sel.cpMax = exlen;
\r
8012 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8013 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8014 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8015 if (forceVisible || exlen == 0 ||
\r
8016 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8017 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8018 /* Scroll to make new end of text visible if old end of text
\r
8019 was visible or new text is an echo of user typein */
\r
8020 sel.cpMin = 9999999;
\r
8021 sel.cpMax = 9999999;
\r
8022 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8023 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8024 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8025 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8027 if (savesel.cpMax == exlen || forceVisible) {
\r
8028 /* Move insert point to new end of text if it was at the old
\r
8029 end of text or if the new text is an echo of user typein */
\r
8030 sel.cpMin = 9999999;
\r
8031 sel.cpMax = 9999999;
\r
8032 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8034 /* Restore previous selection */
\r
8035 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8037 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8044 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8048 COLORREF oldFg, oldBg;
\r
8052 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8054 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8055 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8056 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8059 rect.right = x + squareSize;
\r
8061 rect.bottom = y + squareSize;
\r
8064 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8065 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8066 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8067 &rect, str, strlen(str), NULL);
\r
8069 (void) SetTextColor(hdc, oldFg);
\r
8070 (void) SetBkColor(hdc, oldBg);
\r
8071 (void) SelectObject(hdc, oldFont);
\r
8075 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8076 RECT *rect, char *color, char *flagFell)
\r
8080 COLORREF oldFg, oldBg;
\r
8083 if (appData.clockMode) {
\r
8085 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8087 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8094 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8095 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8097 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8098 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8100 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8104 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8105 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8106 rect, str, strlen(str), NULL);
\r
8107 if(logoHeight > 0 && appData.clockMode) {
\r
8109 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8110 r.top = rect->top + logoHeight/2;
\r
8111 r.left = rect->left;
\r
8112 r.right = rect->right;
\r
8113 r.bottom = rect->bottom;
\r
8114 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8115 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8116 &r, str, strlen(str), NULL);
\r
8118 (void) SetTextColor(hdc, oldFg);
\r
8119 (void) SetBkColor(hdc, oldBg);
\r
8120 (void) SelectObject(hdc, oldFont);
\r
8125 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8131 if( count <= 0 ) {
\r
8132 if (appData.debugMode) {
\r
8133 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8136 return ERROR_INVALID_USER_BUFFER;
\r
8139 ResetEvent(ovl->hEvent);
\r
8140 ovl->Offset = ovl->OffsetHigh = 0;
\r
8141 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8145 err = GetLastError();
\r
8146 if (err == ERROR_IO_PENDING) {
\r
8147 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8151 err = GetLastError();
\r
8158 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8163 ResetEvent(ovl->hEvent);
\r
8164 ovl->Offset = ovl->OffsetHigh = 0;
\r
8165 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8169 err = GetLastError();
\r
8170 if (err == ERROR_IO_PENDING) {
\r
8171 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8175 err = GetLastError();
\r
8181 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8182 void CheckForInputBufferFull( InputSource * is )
\r
8184 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8185 /* Look for end of line */
\r
8186 char * p = is->buf;
\r
8188 while( p < is->next && *p != '\n' ) {
\r
8192 if( p >= is->next ) {
\r
8193 if (appData.debugMode) {
\r
8194 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8197 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8198 is->count = (DWORD) -1;
\r
8199 is->next = is->buf;
\r
8205 InputThread(LPVOID arg)
\r
8210 is = (InputSource *) arg;
\r
8211 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8212 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8213 while (is->hThread != NULL) {
\r
8214 is->error = DoReadFile(is->hFile, is->next,
\r
8215 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8216 &is->count, &ovl);
\r
8217 if (is->error == NO_ERROR) {
\r
8218 is->next += is->count;
\r
8220 if (is->error == ERROR_BROKEN_PIPE) {
\r
8221 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8224 is->count = (DWORD) -1;
\r
8225 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8230 CheckForInputBufferFull( is );
\r
8232 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8234 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8236 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8239 CloseHandle(ovl.hEvent);
\r
8240 CloseHandle(is->hFile);
\r
8242 if (appData.debugMode) {
\r
8243 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8250 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8252 NonOvlInputThread(LPVOID arg)
\r
8259 is = (InputSource *) arg;
\r
8260 while (is->hThread != NULL) {
\r
8261 is->error = ReadFile(is->hFile, is->next,
\r
8262 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8263 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8264 if (is->error == NO_ERROR) {
\r
8265 /* Change CRLF to LF */
\r
8266 if (is->next > is->buf) {
\r
8268 i = is->count + 1;
\r
8276 if (prev == '\r' && *p == '\n') {
\r
8288 if (is->error == ERROR_BROKEN_PIPE) {
\r
8289 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8292 is->count = (DWORD) -1;
\r
8296 CheckForInputBufferFull( is );
\r
8298 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8300 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8302 if (is->count < 0) break; /* Quit on error */
\r
8304 CloseHandle(is->hFile);
\r
8309 SocketInputThread(LPVOID arg)
\r
8313 is = (InputSource *) arg;
\r
8314 while (is->hThread != NULL) {
\r
8315 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8316 if ((int)is->count == SOCKET_ERROR) {
\r
8317 is->count = (DWORD) -1;
\r
8318 is->error = WSAGetLastError();
\r
8320 is->error = NO_ERROR;
\r
8321 is->next += is->count;
\r
8322 if (is->count == 0 && is->second == is) {
\r
8323 /* End of file on stderr; quit with no message */
\r
8327 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8329 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8331 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8337 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8341 is = (InputSource *) lParam;
\r
8342 if (is->lineByLine) {
\r
8343 /* Feed in lines one by one */
\r
8344 char *p = is->buf;
\r
8346 while (q < is->next) {
\r
8347 if (*q++ == '\n') {
\r
8348 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8353 /* Move any partial line to the start of the buffer */
\r
8355 while (p < is->next) {
\r
8360 if (is->error != NO_ERROR || is->count == 0) {
\r
8361 /* Notify backend of the error. Note: If there was a partial
\r
8362 line at the end, it is not flushed through. */
\r
8363 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8366 /* Feed in the whole chunk of input at once */
\r
8367 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8368 is->next = is->buf;
\r
8372 /*---------------------------------------------------------------------------*\
\r
8374 * Menu enables. Used when setting various modes.
\r
8376 \*---------------------------------------------------------------------------*/
\r
8384 GreyRevert(Boolean grey)
\r
8385 { // [HGM] vari: for retracting variations in local mode
\r
8386 HMENU hmenu = GetMenu(hwndMain);
\r
8387 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
8391 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8393 while (enab->item > 0) {
\r
8394 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8399 Enables gnuEnables[] = {
\r
8400 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8401 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8402 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8403 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8404 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8405 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8406 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8407 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8408 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8409 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8410 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8414 Enables icsEnables[] = {
\r
8415 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8416 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8417 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8418 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8419 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8420 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8421 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8422 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8423 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8424 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8425 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8426 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8427 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8428 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8429 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8434 Enables zippyEnables[] = {
\r
8435 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8436 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8437 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8438 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8443 Enables ncpEnables[] = {
\r
8444 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8445 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8446 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8447 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8448 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8449 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8450 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8451 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8452 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8453 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8454 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8455 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8456 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8457 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8458 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8459 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8460 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8461 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8462 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8466 Enables trainingOnEnables[] = {
\r
8467 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8468 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8469 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8470 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8471 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8472 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8473 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8474 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8478 Enables trainingOffEnables[] = {
\r
8479 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8480 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8481 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8482 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8483 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8484 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8485 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8486 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8490 /* These modify either ncpEnables or gnuEnables */
\r
8491 Enables cmailEnables[] = {
\r
8492 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8493 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8494 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8495 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8496 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8497 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8498 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8502 Enables machineThinkingEnables[] = {
\r
8503 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8504 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8505 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8506 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8507 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8508 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8509 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8510 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8511 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8512 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8513 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8514 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8515 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8516 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8517 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8521 Enables userThinkingEnables[] = {
\r
8522 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8523 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8524 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8525 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8526 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8527 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8528 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8529 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8530 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8531 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8532 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8533 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8534 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8535 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8536 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8540 /*---------------------------------------------------------------------------*\
\r
8542 * Front-end interface functions exported by XBoard.
\r
8543 * Functions appear in same order as prototypes in frontend.h.
\r
8545 \*---------------------------------------------------------------------------*/
\r
8549 static UINT prevChecked = 0;
\r
8550 static int prevPausing = 0;
\r
8553 if (pausing != prevPausing) {
\r
8554 prevPausing = pausing;
\r
8555 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8556 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8557 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8560 switch (gameMode) {
\r
8561 case BeginningOfGame:
\r
8562 if (appData.icsActive)
\r
8563 nowChecked = IDM_IcsClient;
\r
8564 else if (appData.noChessProgram)
\r
8565 nowChecked = IDM_EditGame;
\r
8567 nowChecked = IDM_MachineBlack;
\r
8569 case MachinePlaysBlack:
\r
8570 nowChecked = IDM_MachineBlack;
\r
8572 case MachinePlaysWhite:
\r
8573 nowChecked = IDM_MachineWhite;
\r
8575 case TwoMachinesPlay:
\r
8576 nowChecked = IDM_TwoMachines;
\r
8579 nowChecked = IDM_AnalysisMode;
\r
8582 nowChecked = IDM_AnalyzeFile;
\r
8585 nowChecked = IDM_EditGame;
\r
8587 case PlayFromGameFile:
\r
8588 nowChecked = IDM_LoadGame;
\r
8590 case EditPosition:
\r
8591 nowChecked = IDM_EditPosition;
\r
8594 nowChecked = IDM_Training;
\r
8596 case IcsPlayingWhite:
\r
8597 case IcsPlayingBlack:
\r
8598 case IcsObserving:
\r
8600 nowChecked = IDM_IcsClient;
\r
8607 if (prevChecked != 0)
\r
8608 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8609 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8610 if (nowChecked != 0)
\r
8611 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8612 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8614 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8615 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8616 MF_BYCOMMAND|MF_ENABLED);
\r
8618 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8619 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8622 prevChecked = nowChecked;
\r
8624 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8625 if (appData.icsActive) {
\r
8626 if (appData.icsEngineAnalyze) {
\r
8627 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8628 MF_BYCOMMAND|MF_CHECKED);
\r
8630 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8631 MF_BYCOMMAND|MF_UNCHECKED);
\r
8639 HMENU hmenu = GetMenu(hwndMain);
\r
8640 SetMenuEnables(hmenu, icsEnables);
\r
8641 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8642 MF_BYPOSITION|MF_ENABLED);
\r
8644 if (appData.zippyPlay) {
\r
8645 SetMenuEnables(hmenu, zippyEnables);
\r
8646 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8647 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8648 MF_BYCOMMAND|MF_ENABLED);
\r
8656 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8662 HMENU hmenu = GetMenu(hwndMain);
\r
8663 SetMenuEnables(hmenu, ncpEnables);
\r
8664 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8665 MF_BYPOSITION|MF_GRAYED);
\r
8666 DrawMenuBar(hwndMain);
\r
8672 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8676 SetTrainingModeOn()
\r
8679 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8680 for (i = 0; i < N_BUTTONS; i++) {
\r
8681 if (buttonDesc[i].hwnd != NULL)
\r
8682 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8687 VOID SetTrainingModeOff()
\r
8690 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8691 for (i = 0; i < N_BUTTONS; i++) {
\r
8692 if (buttonDesc[i].hwnd != NULL)
\r
8693 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8699 SetUserThinkingEnables()
\r
8701 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8705 SetMachineThinkingEnables()
\r
8707 HMENU hMenu = GetMenu(hwndMain);
\r
8708 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8710 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8712 if (gameMode == MachinePlaysBlack) {
\r
8713 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8714 } else if (gameMode == MachinePlaysWhite) {
\r
8715 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8716 } else if (gameMode == TwoMachinesPlay) {
\r
8717 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8723 DisplayTitle(char *str)
\r
8725 char title[MSG_SIZ], *host;
\r
8726 if (str[0] != NULLCHAR) {
\r
8727 strcpy(title, str);
\r
8728 } else if (appData.icsActive) {
\r
8729 if (appData.icsCommPort[0] != NULLCHAR)
\r
8732 host = appData.icsHost;
\r
8733 sprintf(title, "%s: %s", szTitle, host);
\r
8734 } else if (appData.noChessProgram) {
\r
8735 strcpy(title, szTitle);
\r
8737 strcpy(title, szTitle);
\r
8738 strcat(title, ": ");
\r
8739 strcat(title, first.tidy);
\r
8741 SetWindowText(hwndMain, title);
\r
8746 DisplayMessage(char *str1, char *str2)
\r
8750 int remain = MESSAGE_TEXT_MAX - 1;
\r
8753 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8754 messageText[0] = NULLCHAR;
\r
8756 len = strlen(str1);
\r
8757 if (len > remain) len = remain;
\r
8758 strncpy(messageText, str1, len);
\r
8759 messageText[len] = NULLCHAR;
\r
8762 if (*str2 && remain >= 2) {
\r
8764 strcat(messageText, " ");
\r
8767 len = strlen(str2);
\r
8768 if (len > remain) len = remain;
\r
8769 strncat(messageText, str2, len);
\r
8771 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8773 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8777 hdc = GetDC(hwndMain);
\r
8778 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8779 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8780 &messageRect, messageText, strlen(messageText), NULL);
\r
8781 (void) SelectObject(hdc, oldFont);
\r
8782 (void) ReleaseDC(hwndMain, hdc);
\r
8786 DisplayError(char *str, int error)
\r
8788 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8794 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8795 NULL, error, LANG_NEUTRAL,
\r
8796 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8798 sprintf(buf, "%s:\n%s", str, buf2);
\r
8800 ErrorMap *em = errmap;
\r
8801 while (em->err != 0 && em->err != error) em++;
\r
8802 if (em->err != 0) {
\r
8803 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8805 sprintf(buf, "%s:\nError code %d", str, error);
\r
8810 ErrorPopUp("Error", buf);
\r
8815 DisplayMoveError(char *str)
\r
8817 fromX = fromY = -1;
\r
8818 ClearHighlights();
\r
8819 DrawPosition(FALSE, NULL);
\r
8820 if (appData.popupMoveErrors) {
\r
8821 ErrorPopUp("Error", str);
\r
8823 DisplayMessage(str, "");
\r
8824 moveErrorMessageUp = TRUE;
\r
8829 DisplayFatalError(char *str, int error, int exitStatus)
\r
8831 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8833 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8836 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8837 NULL, error, LANG_NEUTRAL,
\r
8838 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8840 sprintf(buf, "%s:\n%s", str, buf2);
\r
8842 ErrorMap *em = errmap;
\r
8843 while (em->err != 0 && em->err != error) em++;
\r
8844 if (em->err != 0) {
\r
8845 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8847 sprintf(buf, "%s:\nError code %d", str, error);
\r
8852 if (appData.debugMode) {
\r
8853 fprintf(debugFP, "%s: %s\n", label, str);
\r
8855 if (appData.popupExitMessage) {
\r
8856 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8857 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8859 ExitEvent(exitStatus);
\r
8864 DisplayInformation(char *str)
\r
8866 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8871 DisplayNote(char *str)
\r
8873 ErrorPopUp("Note", str);
\r
8878 char *title, *question, *replyPrefix;
\r
8883 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8885 static QuestionParams *qp;
\r
8886 char reply[MSG_SIZ];
\r
8889 switch (message) {
\r
8890 case WM_INITDIALOG:
\r
8891 qp = (QuestionParams *) lParam;
\r
8892 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8893 SetWindowText(hDlg, qp->title);
\r
8894 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8895 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8899 switch (LOWORD(wParam)) {
\r
8901 strcpy(reply, qp->replyPrefix);
\r
8902 if (*reply) strcat(reply, " ");
\r
8903 len = strlen(reply);
\r
8904 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8905 strcat(reply, "\n");
\r
8906 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8907 EndDialog(hDlg, TRUE);
\r
8908 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8911 EndDialog(hDlg, FALSE);
\r
8922 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8924 QuestionParams qp;
\r
8928 qp.question = question;
\r
8929 qp.replyPrefix = replyPrefix;
\r
8931 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8932 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8933 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8934 FreeProcInstance(lpProc);
\r
8937 /* [AS] Pick FRC position */
\r
8938 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8940 static int * lpIndexFRC;
\r
8946 case WM_INITDIALOG:
\r
8947 lpIndexFRC = (int *) lParam;
\r
8949 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8951 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8952 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8953 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8954 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8959 switch( LOWORD(wParam) ) {
\r
8961 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8962 EndDialog( hDlg, 0 );
\r
8963 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8966 EndDialog( hDlg, 1 );
\r
8968 case IDC_NFG_Edit:
\r
8969 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8970 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8972 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8975 case IDC_NFG_Random:
\r
8976 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8977 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8990 int index = appData.defaultFrcPosition;
\r
8991 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8993 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8995 if( result == 0 ) {
\r
8996 appData.defaultFrcPosition = index;
\r
9002 /* [AS] Game list options */
\r
9008 static GLT_Item GLT_ItemInfo[] = {
\r
9009 { GLT_EVENT, "Event" },
\r
9010 { GLT_SITE, "Site" },
\r
9011 { GLT_DATE, "Date" },
\r
9012 { GLT_ROUND, "Round" },
\r
9013 { GLT_PLAYERS, "Players" },
\r
9014 { GLT_RESULT, "Result" },
\r
9015 { GLT_WHITE_ELO, "White Rating" },
\r
9016 { GLT_BLACK_ELO, "Black Rating" },
\r
9017 { GLT_TIME_CONTROL,"Time Control" },
\r
9018 { GLT_VARIANT, "Variant" },
\r
9019 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9020 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9024 const char * GLT_FindItem( char id )
\r
9026 const char * result = 0;
\r
9028 GLT_Item * list = GLT_ItemInfo;
\r
9030 while( list->id != 0 ) {
\r
9031 if( list->id == id ) {
\r
9032 result = list->name;
\r
9042 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9044 const char * name = GLT_FindItem( id );
\r
9047 if( index >= 0 ) {
\r
9048 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9051 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9056 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9060 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9063 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9067 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9069 pc = GLT_ALL_TAGS;
\r
9072 if( strchr( tags, *pc ) == 0 ) {
\r
9073 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9078 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9081 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9083 char result = '\0';
\r
9086 GLT_Item * list = GLT_ItemInfo;
\r
9088 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9089 while( list->id != 0 ) {
\r
9090 if( strcmp( list->name, name ) == 0 ) {
\r
9091 result = list->id;
\r
9102 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9104 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9105 int idx2 = idx1 + delta;
\r
9106 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9108 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9111 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9112 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9113 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9114 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9118 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9120 static char glt[64];
\r
9121 static char * lpUserGLT;
\r
9125 case WM_INITDIALOG:
\r
9126 lpUserGLT = (char *) lParam;
\r
9128 strcpy( glt, lpUserGLT );
\r
9130 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9132 /* Initialize list */
\r
9133 GLT_TagsToList( hDlg, glt );
\r
9135 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9140 switch( LOWORD(wParam) ) {
\r
9143 char * pc = lpUserGLT;
\r
9145 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9149 id = GLT_ListItemToTag( hDlg, idx );
\r
9153 } while( id != '\0' );
\r
9155 EndDialog( hDlg, 0 );
\r
9158 EndDialog( hDlg, 1 );
\r
9161 case IDC_GLT_Default:
\r
9162 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9163 GLT_TagsToList( hDlg, glt );
\r
9166 case IDC_GLT_Restore:
\r
9167 strcpy( glt, lpUserGLT );
\r
9168 GLT_TagsToList( hDlg, glt );
\r
9172 GLT_MoveSelection( hDlg, -1 );
\r
9175 case IDC_GLT_Down:
\r
9176 GLT_MoveSelection( hDlg, +1 );
\r
9186 int GameListOptions()
\r
9190 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9192 strcpy( glt, appData.gameListTags );
\r
9194 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9196 if( result == 0 ) {
\r
9197 /* [AS] Memory leak here! */
\r
9198 appData.gameListTags = strdup( glt );
\r
9206 DisplayIcsInteractionTitle(char *str)
\r
9208 char consoleTitle[MSG_SIZ];
\r
9210 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9211 SetWindowText(hwndConsole, consoleTitle);
\r
9215 DrawPosition(int fullRedraw, Board board)
\r
9217 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9220 void NotifyFrontendLogin()
\r
9223 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9229 fromX = fromY = -1;
\r
9230 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9231 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9232 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9233 dragInfo.lastpos = dragInfo.pos;
\r
9234 dragInfo.start.x = dragInfo.start.y = -1;
\r
9235 dragInfo.from = dragInfo.start;
\r
9237 DrawPosition(TRUE, NULL);
\r
9243 CommentPopUp(char *title, char *str)
\r
9245 HWND hwnd = GetActiveWindow();
\r
9246 EitherCommentPopUp(0, title, str, FALSE);
\r
9248 SetActiveWindow(hwnd);
\r
9252 CommentPopDown(void)
\r
9254 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9255 if (commentDialog) {
\r
9256 ShowWindow(commentDialog, SW_HIDE);
\r
9258 commentUp = FALSE;
\r
9262 EditCommentPopUp(int index, char *title, char *str)
\r
9264 EitherCommentPopUp(index, title, str, TRUE);
\r
9271 MyPlaySound(&sounds[(int)SoundMove]);
\r
9274 VOID PlayIcsWinSound()
\r
9276 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9279 VOID PlayIcsLossSound()
\r
9281 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9284 VOID PlayIcsDrawSound()
\r
9286 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9289 VOID PlayIcsUnfinishedSound()
\r
9291 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9297 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9305 consoleEcho = TRUE;
\r
9306 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9307 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9308 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9317 consoleEcho = FALSE;
\r
9318 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9319 /* This works OK: set text and background both to the same color */
\r
9321 cf.crTextColor = COLOR_ECHOOFF;
\r
9322 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9323 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9326 /* No Raw()...? */
\r
9328 void Colorize(ColorClass cc, int continuation)
\r
9330 currentColorClass = cc;
\r
9331 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9332 consoleCF.crTextColor = textAttribs[cc].color;
\r
9333 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9334 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9340 static char buf[MSG_SIZ];
\r
9341 DWORD bufsiz = MSG_SIZ;
\r
9343 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9344 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9346 if (!GetUserName(buf, &bufsiz)) {
\r
9347 /*DisplayError("Error getting user name", GetLastError());*/
\r
9348 strcpy(buf, "User");
\r
9356 static char buf[MSG_SIZ];
\r
9357 DWORD bufsiz = MSG_SIZ;
\r
9359 if (!GetComputerName(buf, &bufsiz)) {
\r
9360 /*DisplayError("Error getting host name", GetLastError());*/
\r
9361 strcpy(buf, "Unknown");
\r
9368 ClockTimerRunning()
\r
9370 return clockTimerEvent != 0;
\r
9376 if (clockTimerEvent == 0) return FALSE;
\r
9377 KillTimer(hwndMain, clockTimerEvent);
\r
9378 clockTimerEvent = 0;
\r
9383 StartClockTimer(long millisec)
\r
9385 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9386 (UINT) millisec, NULL);
\r
9390 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9393 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9395 if(appData.noGUI) return;
\r
9396 hdc = GetDC(hwndMain);
\r
9397 if (!IsIconic(hwndMain)) {
\r
9398 DisplayAClock(hdc, timeRemaining, highlight,
\r
9399 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9401 if (highlight && iconCurrent == iconBlack) {
\r
9402 iconCurrent = iconWhite;
\r
9403 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9404 if (IsIconic(hwndMain)) {
\r
9405 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9408 (void) ReleaseDC(hwndMain, hdc);
\r
9410 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9414 DisplayBlackClock(long timeRemaining, int highlight)
\r
9417 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9419 if(appData.noGUI) return;
\r
9420 hdc = GetDC(hwndMain);
\r
9421 if (!IsIconic(hwndMain)) {
\r
9422 DisplayAClock(hdc, timeRemaining, highlight,
\r
9423 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9425 if (highlight && iconCurrent == iconWhite) {
\r
9426 iconCurrent = iconBlack;
\r
9427 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9428 if (IsIconic(hwndMain)) {
\r
9429 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9432 (void) ReleaseDC(hwndMain, hdc);
\r
9434 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9439 LoadGameTimerRunning()
\r
9441 return loadGameTimerEvent != 0;
\r
9445 StopLoadGameTimer()
\r
9447 if (loadGameTimerEvent == 0) return FALSE;
\r
9448 KillTimer(hwndMain, loadGameTimerEvent);
\r
9449 loadGameTimerEvent = 0;
\r
9454 StartLoadGameTimer(long millisec)
\r
9456 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9457 (UINT) millisec, NULL);
\r
9465 char fileTitle[MSG_SIZ];
\r
9467 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9468 f = OpenFileDialog(hwndMain, "a", defName,
\r
9469 appData.oldSaveStyle ? "gam" : "pgn",
\r
9471 "Save Game to File", NULL, fileTitle, NULL);
\r
9473 SaveGame(f, 0, "");
\r
9480 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9482 if (delayedTimerEvent != 0) {
\r
9483 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9484 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9486 KillTimer(hwndMain, delayedTimerEvent);
\r
9487 delayedTimerEvent = 0;
\r
9488 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9489 delayedTimerCallback();
\r
9491 delayedTimerCallback = cb;
\r
9492 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9493 (UINT) millisec, NULL);
\r
9496 DelayedEventCallback
\r
9499 if (delayedTimerEvent) {
\r
9500 return delayedTimerCallback;
\r
9507 CancelDelayedEvent()
\r
9509 if (delayedTimerEvent) {
\r
9510 KillTimer(hwndMain, delayedTimerEvent);
\r
9511 delayedTimerEvent = 0;
\r
9515 DWORD GetWin32Priority(int nice)
\r
9516 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9518 REALTIME_PRIORITY_CLASS 0x00000100
\r
9519 HIGH_PRIORITY_CLASS 0x00000080
\r
9520 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9521 NORMAL_PRIORITY_CLASS 0x00000020
\r
9522 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9523 IDLE_PRIORITY_CLASS 0x00000040
\r
9525 if (nice < -15) return 0x00000080;
\r
9526 if (nice < 0) return 0x00008000;
\r
9527 if (nice == 0) return 0x00000020;
\r
9528 if (nice < 15) return 0x00004000;
\r
9529 return 0x00000040;
\r
9532 /* Start a child process running the given program.
\r
9533 The process's standard output can be read from "from", and its
\r
9534 standard input can be written to "to".
\r
9535 Exit with fatal error if anything goes wrong.
\r
9536 Returns an opaque pointer that can be used to destroy the process
\r
9540 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9542 #define BUFSIZE 4096
\r
9544 HANDLE hChildStdinRd, hChildStdinWr,
\r
9545 hChildStdoutRd, hChildStdoutWr;
\r
9546 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9547 SECURITY_ATTRIBUTES saAttr;
\r
9549 PROCESS_INFORMATION piProcInfo;
\r
9550 STARTUPINFO siStartInfo;
\r
9552 char buf[MSG_SIZ];
\r
9555 if (appData.debugMode) {
\r
9556 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9561 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9562 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9563 saAttr.bInheritHandle = TRUE;
\r
9564 saAttr.lpSecurityDescriptor = NULL;
\r
9567 * The steps for redirecting child's STDOUT:
\r
9568 * 1. Create anonymous pipe to be STDOUT for child.
\r
9569 * 2. Create a noninheritable duplicate of read handle,
\r
9570 * and close the inheritable read handle.
\r
9573 /* Create a pipe for the child's STDOUT. */
\r
9574 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9575 return GetLastError();
\r
9578 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9579 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9580 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9581 FALSE, /* not inherited */
\r
9582 DUPLICATE_SAME_ACCESS);
\r
9584 return GetLastError();
\r
9586 CloseHandle(hChildStdoutRd);
\r
9589 * The steps for redirecting child's STDIN:
\r
9590 * 1. Create anonymous pipe to be STDIN for child.
\r
9591 * 2. Create a noninheritable duplicate of write handle,
\r
9592 * and close the inheritable write handle.
\r
9595 /* Create a pipe for the child's STDIN. */
\r
9596 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9597 return GetLastError();
\r
9600 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9601 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9602 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9603 FALSE, /* not inherited */
\r
9604 DUPLICATE_SAME_ACCESS);
\r
9606 return GetLastError();
\r
9608 CloseHandle(hChildStdinWr);
\r
9610 /* Arrange to (1) look in dir for the child .exe file, and
\r
9611 * (2) have dir be the child's working directory. Interpret
\r
9612 * dir relative to the directory WinBoard loaded from. */
\r
9613 GetCurrentDirectory(MSG_SIZ, buf);
\r
9614 SetCurrentDirectory(installDir);
\r
9615 SetCurrentDirectory(dir);
\r
9617 /* Now create the child process. */
\r
9619 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9620 siStartInfo.lpReserved = NULL;
\r
9621 siStartInfo.lpDesktop = NULL;
\r
9622 siStartInfo.lpTitle = NULL;
\r
9623 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9624 siStartInfo.cbReserved2 = 0;
\r
9625 siStartInfo.lpReserved2 = NULL;
\r
9626 siStartInfo.hStdInput = hChildStdinRd;
\r
9627 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9628 siStartInfo.hStdError = hChildStdoutWr;
\r
9630 fSuccess = CreateProcess(NULL,
\r
9631 cmdLine, /* command line */
\r
9632 NULL, /* process security attributes */
\r
9633 NULL, /* primary thread security attrs */
\r
9634 TRUE, /* handles are inherited */
\r
9635 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9636 NULL, /* use parent's environment */
\r
9638 &siStartInfo, /* STARTUPINFO pointer */
\r
9639 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9641 err = GetLastError();
\r
9642 SetCurrentDirectory(buf); /* return to prev directory */
\r
9647 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9648 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9649 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9652 /* Close the handles we don't need in the parent */
\r
9653 CloseHandle(piProcInfo.hThread);
\r
9654 CloseHandle(hChildStdinRd);
\r
9655 CloseHandle(hChildStdoutWr);
\r
9657 /* Prepare return value */
\r
9658 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9659 cp->kind = CPReal;
\r
9660 cp->hProcess = piProcInfo.hProcess;
\r
9661 cp->pid = piProcInfo.dwProcessId;
\r
9662 cp->hFrom = hChildStdoutRdDup;
\r
9663 cp->hTo = hChildStdinWrDup;
\r
9665 *pr = (void *) cp;
\r
9667 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9668 2000 where engines sometimes don't see the initial command(s)
\r
9669 from WinBoard and hang. I don't understand how that can happen,
\r
9670 but the Sleep is harmless, so I've put it in. Others have also
\r
9671 reported what may be the same problem, so hopefully this will fix
\r
9672 it for them too. */
\r
9680 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9682 ChildProc *cp; int result;
\r
9684 cp = (ChildProc *) pr;
\r
9685 if (cp == NULL) return;
\r
9687 switch (cp->kind) {
\r
9689 /* TerminateProcess is considered harmful, so... */
\r
9690 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9691 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9692 /* The following doesn't work because the chess program
\r
9693 doesn't "have the same console" as WinBoard. Maybe
\r
9694 we could arrange for this even though neither WinBoard
\r
9695 nor the chess program uses a console for stdio? */
\r
9696 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9698 /* [AS] Special termination modes for misbehaving programs... */
\r
9699 if( signal == 9 ) {
\r
9700 result = TerminateProcess( cp->hProcess, 0 );
\r
9702 if ( appData.debugMode) {
\r
9703 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9706 else if( signal == 10 ) {
\r
9707 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9709 if( dw != WAIT_OBJECT_0 ) {
\r
9710 result = TerminateProcess( cp->hProcess, 0 );
\r
9712 if ( appData.debugMode) {
\r
9713 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9719 CloseHandle(cp->hProcess);
\r
9723 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9727 closesocket(cp->sock);
\r
9732 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9733 closesocket(cp->sock);
\r
9734 closesocket(cp->sock2);
\r
9742 InterruptChildProcess(ProcRef pr)
\r
9746 cp = (ChildProc *) pr;
\r
9747 if (cp == NULL) return;
\r
9748 switch (cp->kind) {
\r
9750 /* The following doesn't work because the chess program
\r
9751 doesn't "have the same console" as WinBoard. Maybe
\r
9752 we could arrange for this even though neither WinBoard
\r
9753 nor the chess program uses a console for stdio */
\r
9754 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9759 /* Can't interrupt */
\r
9763 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9770 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9772 char cmdLine[MSG_SIZ];
\r
9774 if (port[0] == NULLCHAR) {
\r
9775 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9777 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9779 return StartChildProcess(cmdLine, "", pr);
\r
9783 /* Code to open TCP sockets */
\r
9786 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9791 struct sockaddr_in sa, mysa;
\r
9792 struct hostent FAR *hp;
\r
9793 unsigned short uport;
\r
9794 WORD wVersionRequested;
\r
9797 /* Initialize socket DLL */
\r
9798 wVersionRequested = MAKEWORD(1, 1);
\r
9799 err = WSAStartup(wVersionRequested, &wsaData);
\r
9800 if (err != 0) return err;
\r
9803 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9804 err = WSAGetLastError();
\r
9809 /* Bind local address using (mostly) don't-care values.
\r
9811 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9812 mysa.sin_family = AF_INET;
\r
9813 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9814 uport = (unsigned short) 0;
\r
9815 mysa.sin_port = htons(uport);
\r
9816 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9817 == SOCKET_ERROR) {
\r
9818 err = WSAGetLastError();
\r
9823 /* Resolve remote host name */
\r
9824 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9825 if (!(hp = gethostbyname(host))) {
\r
9826 unsigned int b0, b1, b2, b3;
\r
9828 err = WSAGetLastError();
\r
9830 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9831 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9832 hp->h_addrtype = AF_INET;
\r
9834 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9835 hp->h_addr_list[0] = (char *) malloc(4);
\r
9836 hp->h_addr_list[0][0] = (char) b0;
\r
9837 hp->h_addr_list[0][1] = (char) b1;
\r
9838 hp->h_addr_list[0][2] = (char) b2;
\r
9839 hp->h_addr_list[0][3] = (char) b3;
\r
9845 sa.sin_family = hp->h_addrtype;
\r
9846 uport = (unsigned short) atoi(port);
\r
9847 sa.sin_port = htons(uport);
\r
9848 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9850 /* Make connection */
\r
9851 if (connect(s, (struct sockaddr *) &sa,
\r
9852 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9853 err = WSAGetLastError();
\r
9858 /* Prepare return value */
\r
9859 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9860 cp->kind = CPSock;
\r
9862 *pr = (ProcRef *) cp;
\r
9868 OpenCommPort(char *name, ProcRef *pr)
\r
9873 char fullname[MSG_SIZ];
\r
9875 if (*name != '\\')
\r
9876 sprintf(fullname, "\\\\.\\%s", name);
\r
9878 strcpy(fullname, name);
\r
9880 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9881 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9882 if (h == (HANDLE) -1) {
\r
9883 return GetLastError();
\r
9887 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9889 /* Accumulate characters until a 100ms pause, then parse */
\r
9890 ct.ReadIntervalTimeout = 100;
\r
9891 ct.ReadTotalTimeoutMultiplier = 0;
\r
9892 ct.ReadTotalTimeoutConstant = 0;
\r
9893 ct.WriteTotalTimeoutMultiplier = 0;
\r
9894 ct.WriteTotalTimeoutConstant = 0;
\r
9895 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9897 /* Prepare return value */
\r
9898 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9899 cp->kind = CPComm;
\r
9902 *pr = (ProcRef *) cp;
\r
9908 OpenLoopback(ProcRef *pr)
\r
9910 DisplayFatalError("Not implemented", 0, 1);
\r
9916 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9921 struct sockaddr_in sa, mysa;
\r
9922 struct hostent FAR *hp;
\r
9923 unsigned short uport;
\r
9924 WORD wVersionRequested;
\r
9927 char stderrPortStr[MSG_SIZ];
\r
9929 /* Initialize socket DLL */
\r
9930 wVersionRequested = MAKEWORD(1, 1);
\r
9931 err = WSAStartup(wVersionRequested, &wsaData);
\r
9932 if (err != 0) return err;
\r
9934 /* Resolve remote host name */
\r
9935 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9936 if (!(hp = gethostbyname(host))) {
\r
9937 unsigned int b0, b1, b2, b3;
\r
9939 err = WSAGetLastError();
\r
9941 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9942 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9943 hp->h_addrtype = AF_INET;
\r
9945 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9946 hp->h_addr_list[0] = (char *) malloc(4);
\r
9947 hp->h_addr_list[0][0] = (char) b0;
\r
9948 hp->h_addr_list[0][1] = (char) b1;
\r
9949 hp->h_addr_list[0][2] = (char) b2;
\r
9950 hp->h_addr_list[0][3] = (char) b3;
\r
9956 sa.sin_family = hp->h_addrtype;
\r
9957 uport = (unsigned short) 514;
\r
9958 sa.sin_port = htons(uport);
\r
9959 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9961 /* Bind local socket to unused "privileged" port address
\r
9963 s = INVALID_SOCKET;
\r
9964 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9965 mysa.sin_family = AF_INET;
\r
9966 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9967 for (fromPort = 1023;; fromPort--) {
\r
9968 if (fromPort < 0) {
\r
9970 return WSAEADDRINUSE;
\r
9972 if (s == INVALID_SOCKET) {
\r
9973 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9974 err = WSAGetLastError();
\r
9979 uport = (unsigned short) fromPort;
\r
9980 mysa.sin_port = htons(uport);
\r
9981 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9982 == SOCKET_ERROR) {
\r
9983 err = WSAGetLastError();
\r
9984 if (err == WSAEADDRINUSE) continue;
\r
9988 if (connect(s, (struct sockaddr *) &sa,
\r
9989 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9990 err = WSAGetLastError();
\r
9991 if (err == WSAEADDRINUSE) {
\r
10002 /* Bind stderr local socket to unused "privileged" port address
\r
10004 s2 = INVALID_SOCKET;
\r
10005 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10006 mysa.sin_family = AF_INET;
\r
10007 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10008 for (fromPort = 1023;; fromPort--) {
\r
10009 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10010 if (fromPort < 0) {
\r
10011 (void) closesocket(s);
\r
10013 return WSAEADDRINUSE;
\r
10015 if (s2 == INVALID_SOCKET) {
\r
10016 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10017 err = WSAGetLastError();
\r
10023 uport = (unsigned short) fromPort;
\r
10024 mysa.sin_port = htons(uport);
\r
10025 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10026 == SOCKET_ERROR) {
\r
10027 err = WSAGetLastError();
\r
10028 if (err == WSAEADDRINUSE) continue;
\r
10029 (void) closesocket(s);
\r
10033 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10034 err = WSAGetLastError();
\r
10035 if (err == WSAEADDRINUSE) {
\r
10037 s2 = INVALID_SOCKET;
\r
10040 (void) closesocket(s);
\r
10041 (void) closesocket(s2);
\r
10047 prevStderrPort = fromPort; // remember port used
\r
10048 sprintf(stderrPortStr, "%d", fromPort);
\r
10050 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10051 err = WSAGetLastError();
\r
10052 (void) closesocket(s);
\r
10053 (void) closesocket(s2);
\r
10058 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10059 err = WSAGetLastError();
\r
10060 (void) closesocket(s);
\r
10061 (void) closesocket(s2);
\r
10065 if (*user == NULLCHAR) user = UserName();
\r
10066 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10067 err = WSAGetLastError();
\r
10068 (void) closesocket(s);
\r
10069 (void) closesocket(s2);
\r
10073 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10074 err = WSAGetLastError();
\r
10075 (void) closesocket(s);
\r
10076 (void) closesocket(s2);
\r
10081 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10082 err = WSAGetLastError();
\r
10083 (void) closesocket(s);
\r
10084 (void) closesocket(s2);
\r
10088 (void) closesocket(s2); /* Stop listening */
\r
10090 /* Prepare return value */
\r
10091 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10092 cp->kind = CPRcmd;
\r
10095 *pr = (ProcRef *) cp;
\r
10102 AddInputSource(ProcRef pr, int lineByLine,
\r
10103 InputCallback func, VOIDSTAR closure)
\r
10105 InputSource *is, *is2 = NULL;
\r
10106 ChildProc *cp = (ChildProc *) pr;
\r
10108 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10109 is->lineByLine = lineByLine;
\r
10111 is->closure = closure;
\r
10112 is->second = NULL;
\r
10113 is->next = is->buf;
\r
10114 if (pr == NoProc) {
\r
10115 is->kind = CPReal;
\r
10116 consoleInputSource = is;
\r
10118 is->kind = cp->kind;
\r
10120 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10121 we create all threads suspended so that the is->hThread variable can be
\r
10122 safely assigned, then let the threads start with ResumeThread.
\r
10124 switch (cp->kind) {
\r
10126 is->hFile = cp->hFrom;
\r
10127 cp->hFrom = NULL; /* now owned by InputThread */
\r
10129 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10130 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10134 is->hFile = cp->hFrom;
\r
10135 cp->hFrom = NULL; /* now owned by InputThread */
\r
10137 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10138 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10142 is->sock = cp->sock;
\r
10144 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10145 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10149 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10151 is->sock = cp->sock;
\r
10152 is->second = is2;
\r
10153 is2->sock = cp->sock2;
\r
10154 is2->second = is2;
\r
10156 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10157 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10159 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10160 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10164 if( is->hThread != NULL ) {
\r
10165 ResumeThread( is->hThread );
\r
10168 if( is2 != NULL && is2->hThread != NULL ) {
\r
10169 ResumeThread( is2->hThread );
\r
10173 return (InputSourceRef) is;
\r
10177 RemoveInputSource(InputSourceRef isr)
\r
10181 is = (InputSource *) isr;
\r
10182 is->hThread = NULL; /* tell thread to stop */
\r
10183 CloseHandle(is->hThread);
\r
10184 if (is->second != NULL) {
\r
10185 is->second->hThread = NULL;
\r
10186 CloseHandle(is->second->hThread);
\r
10190 int no_wrap(char *message, int count)
\r
10192 ConsoleOutput(message, count, FALSE);
\r
10197 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10200 int outCount = SOCKET_ERROR;
\r
10201 ChildProc *cp = (ChildProc *) pr;
\r
10202 static OVERLAPPED ovl;
\r
10203 static int line = 0;
\r
10205 if (pr == NoProc)
\r
10207 if (appData.noJoin || !appData.useInternalWrap)
\r
10208 return no_wrap(message, count);
\r
10211 int width = get_term_width();
\r
10212 int len = wrap(NULL, message, count, width, &line);
\r
10213 char *msg = malloc(len);
\r
10217 return no_wrap(message, count);
\r
10220 dbgchk = wrap(msg, message, count, width, &line);
\r
10221 if (dbgchk != len && appData.debugMode)
\r
10222 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
10223 ConsoleOutput(msg, len, FALSE);
\r
10230 if (ovl.hEvent == NULL) {
\r
10231 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10233 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10235 switch (cp->kind) {
\r
10238 outCount = send(cp->sock, message, count, 0);
\r
10239 if (outCount == SOCKET_ERROR) {
\r
10240 *outError = WSAGetLastError();
\r
10242 *outError = NO_ERROR;
\r
10247 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10248 &dOutCount, NULL)) {
\r
10249 *outError = NO_ERROR;
\r
10250 outCount = (int) dOutCount;
\r
10252 *outError = GetLastError();
\r
10257 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10258 &dOutCount, &ovl);
\r
10259 if (*outError == NO_ERROR) {
\r
10260 outCount = (int) dOutCount;
\r
10268 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10271 /* Ignore delay, not implemented for WinBoard */
\r
10272 return OutputToProcess(pr, message, count, outError);
\r
10277 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10278 char *buf, int count, int error)
\r
10280 DisplayFatalError("Not implemented", 0, 1);
\r
10283 /* see wgamelist.c for Game List functions */
\r
10284 /* see wedittags.c for Edit Tags functions */
\r
10291 char buf[MSG_SIZ];
\r
10294 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10295 f = fopen(buf, "r");
\r
10297 ProcessICSInitScript(f);
\r
10305 StartAnalysisClock()
\r
10307 if (analysisTimerEvent) return;
\r
10308 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10309 (UINT) 2000, NULL);
\r
10313 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10315 highlightInfo.sq[0].x = fromX;
\r
10316 highlightInfo.sq[0].y = fromY;
\r
10317 highlightInfo.sq[1].x = toX;
\r
10318 highlightInfo.sq[1].y = toY;
\r
10322 ClearHighlights()
\r
10324 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10325 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10329 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10331 premoveHighlightInfo.sq[0].x = fromX;
\r
10332 premoveHighlightInfo.sq[0].y = fromY;
\r
10333 premoveHighlightInfo.sq[1].x = toX;
\r
10334 premoveHighlightInfo.sq[1].y = toY;
\r
10338 ClearPremoveHighlights()
\r
10340 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10341 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10345 ShutDownFrontEnd()
\r
10347 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10348 DeleteClipboardTempFiles();
\r
10354 if (IsIconic(hwndMain))
\r
10355 ShowWindow(hwndMain, SW_RESTORE);
\r
10357 SetActiveWindow(hwndMain);
\r
10361 * Prototypes for animation support routines
\r
10363 static void ScreenSquare(int column, int row, POINT * pt);
\r
10364 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10365 POINT frames[], int * nFrames);
\r
10369 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10370 { // [HGM] atomic: animate blast wave
\r
10372 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10373 explodeInfo.fromX = fromX;
\r
10374 explodeInfo.fromY = fromY;
\r
10375 explodeInfo.toX = toX;
\r
10376 explodeInfo.toY = toY;
\r
10377 for(i=1; i<nFrames; i++) {
\r
10378 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10379 DrawPosition(FALSE, NULL);
\r
10380 Sleep(appData.animSpeed);
\r
10382 explodeInfo.radius = 0;
\r
10383 DrawPosition(TRUE, NULL);
\r
10386 #define kFactor 4
\r
10389 AnimateMove(board, fromX, fromY, toX, toY)
\r
10396 ChessSquare piece;
\r
10397 POINT start, finish, mid;
\r
10398 POINT frames[kFactor * 2 + 1];
\r
10401 if (!appData.animate) return;
\r
10402 if (doingSizing) return;
\r
10403 if (fromY < 0 || fromX < 0) return;
\r
10404 piece = board[fromY][fromX];
\r
10405 if (piece >= EmptySquare) return;
\r
10407 ScreenSquare(fromX, fromY, &start);
\r
10408 ScreenSquare(toX, toY, &finish);
\r
10410 /* All pieces except knights move in straight line */
\r
10411 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10412 mid.x = start.x + (finish.x - start.x) / 2;
\r
10413 mid.y = start.y + (finish.y - start.y) / 2;
\r
10415 /* Knight: make diagonal movement then straight */
\r
10416 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10417 mid.x = start.x + (finish.x - start.x) / 2;
\r
10418 mid.y = finish.y;
\r
10420 mid.x = finish.x;
\r
10421 mid.y = start.y + (finish.y - start.y) / 2;
\r
10425 /* Don't use as many frames for very short moves */
\r
10426 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10427 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10429 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10431 animInfo.from.x = fromX;
\r
10432 animInfo.from.y = fromY;
\r
10433 animInfo.to.x = toX;
\r
10434 animInfo.to.y = toY;
\r
10435 animInfo.lastpos = start;
\r
10436 animInfo.piece = piece;
\r
10437 for (n = 0; n < nFrames; n++) {
\r
10438 animInfo.pos = frames[n];
\r
10439 DrawPosition(FALSE, NULL);
\r
10440 animInfo.lastpos = animInfo.pos;
\r
10441 Sleep(appData.animSpeed);
\r
10443 animInfo.pos = finish;
\r
10444 DrawPosition(FALSE, NULL);
\r
10445 animInfo.piece = EmptySquare;
\r
10446 if(gameInfo.variant == VariantAtomic &&
\r
10447 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10448 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10451 /* Convert board position to corner of screen rect and color */
\r
10454 ScreenSquare(column, row, pt)
\r
10455 int column; int row; POINT * pt;
\r
10458 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10459 pt->y = lineGap + row * (squareSize + lineGap);
\r
10461 pt->x = lineGap + column * (squareSize + lineGap);
\r
10462 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10466 /* Generate a series of frame coords from start->mid->finish.
\r
10467 The movement rate doubles until the half way point is
\r
10468 reached, then halves back down to the final destination,
\r
10469 which gives a nice slow in/out effect. The algorithmn
\r
10470 may seem to generate too many intermediates for short
\r
10471 moves, but remember that the purpose is to attract the
\r
10472 viewers attention to the piece about to be moved and
\r
10473 then to where it ends up. Too few frames would be less
\r
10477 Tween(start, mid, finish, factor, frames, nFrames)
\r
10478 POINT * start; POINT * mid;
\r
10479 POINT * finish; int factor;
\r
10480 POINT frames[]; int * nFrames;
\r
10482 int n, fraction = 1, count = 0;
\r
10484 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10485 for (n = 0; n < factor; n++)
\r
10487 for (n = 0; n < factor; n++) {
\r
10488 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10489 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10491 fraction = fraction / 2;
\r
10495 frames[count] = *mid;
\r
10498 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10500 for (n = 0; n < factor; n++) {
\r
10501 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10502 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10504 fraction = fraction * 2;
\r
10506 *nFrames = count;
\r
10510 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10512 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10514 EvalGraphSet( first, last, current, pvInfoList );
\r