2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
\r
6 * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
\r
8 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
9 * which was written and is copyrighted by Wayne Christopher.
\r
11 * The following terms apply to Digital Equipment Corporation's copyright
\r
12 * interest in XBoard:
\r
13 * ------------------------------------------------------------------------
\r
14 * All Rights Reserved
\r
16 * Permission to use, copy, modify, and distribute this software and its
\r
17 * documentation for any purpose and without fee is hereby granted,
\r
18 * provided that the above copyright notice appear in all copies and that
\r
19 * both that copyright notice and this permission notice appear in
\r
20 * supporting documentation, and that the name of Digital not be
\r
21 * used in advertising or publicity pertaining to distribution of the
\r
22 * software without specific, written prior permission.
\r
24 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
25 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
26 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
27 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
28 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
29 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
31 * ------------------------------------------------------------------------
\r
33 * The following terms apply to the enhanced version of XBoard distributed
\r
34 * by the Free Software Foundation:
\r
35 * ------------------------------------------------------------------------
\r
36 * This program is free software; you can redistribute it and/or modify
\r
37 * it under the terms of the GNU General Public License as published by
\r
38 * the Free Software Foundation; either version 2 of the License, or
\r
39 * (at your option) any later version.
\r
41 * This program is distributed in the hope that it will be useful,
\r
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
44 * GNU General Public License for more details.
\r
46 * You should have received a copy of the GNU General Public License
\r
47 * along with this program; if not, write to the Free Software
\r
48 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
49 * ------------------------------------------------------------------------
\r
54 #include <windows.h>
\r
55 #include <winuser.h>
\r
56 #include <winsock.h>
\r
62 #include <sys/stat.h>
\r
65 #include <commdlg.h>
\r
67 #include <richedit.h>
\r
68 #include <mmsystem.h>
\r
76 #include "winboard.h"
\r
77 #include "frontend.h"
\r
78 #include "backend.h"
\r
80 #include "wclipbrd.h"
\r
81 #include "wgamelist.h"
\r
82 #include "wedittags.h"
\r
83 #include "woptions.h"
\r
84 #include "wsockerr.h"
\r
85 #include "defaults.h"
\r
89 void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
92 void mysrandom(unsigned int seed);
\r
94 extern int whiteFlag, blackFlag;
\r
95 Boolean flipClock = FALSE;
\r
97 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
100 ChessSquare piece;
\r
101 POINT pos; /* window coordinates of current pos */
\r
102 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
103 POINT from; /* board coordinates of the piece's orig pos */
\r
104 POINT to; /* board coordinates of the piece's new pos */
\r
107 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
110 POINT start; /* window coordinates of start pos */
\r
111 POINT pos; /* window coordinates of current pos */
\r
112 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
113 POINT from; /* board coordinates of the piece's orig pos */
\r
116 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
119 POINT sq[2]; /* board coordinates of from, to squares */
\r
122 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
123 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
125 /* Window class names */
\r
126 char szAppName[] = "WinBoard";
\r
127 char szConsoleName[] = "WBConsole";
\r
129 /* Title bar text */
\r
130 char szTitle[] = "WinBoard";
\r
131 char szConsoleTitle[] = "ICS Interaction";
\r
134 char *settingsFileName;
\r
135 BOOLEAN saveSettingsOnExit;
\r
136 char installDir[MSG_SIZ];
\r
138 BoardSize boardSize;
\r
139 BOOLEAN chessProgram;
\r
140 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
141 static int squareSize, lineGap, minorSize;
\r
142 static int winWidth, winHeight;
\r
143 static RECT messageRect, whiteRect, blackRect;
\r
144 static char messageText[MESSAGE_TEXT_MAX];
\r
145 static int clockTimerEvent = 0;
\r
146 static int loadGameTimerEvent = 0;
\r
147 static int analysisTimerEvent = 0;
\r
148 static DelayedEventCallback delayedTimerCallback;
\r
149 static int delayedTimerEvent = 0;
\r
150 static int buttonCount = 2;
\r
151 char *icsTextMenuString;
\r
153 char *firstChessProgramNames;
\r
154 char *secondChessProgramNames;
\r
156 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
158 #define PALETTESIZE 256
\r
160 HINSTANCE hInst; /* current instance */
\r
161 HWND hwndMain = NULL; /* root window*/
\r
162 HWND hwndConsole = NULL;
\r
163 BOOLEAN alwaysOnTop = FALSE;
\r
165 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
166 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
168 ColorClass currentColorClass;
\r
170 HWND hCommPort = NULL; /* currently open comm port */
\r
171 static HWND hwndPause; /* pause button */
\r
172 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
173 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
174 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
175 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
176 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
177 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
178 static HPEN gridPen = NULL;
\r
179 static HPEN highlightPen = NULL;
\r
180 static HPEN premovePen = NULL;
\r
181 static NPLOGPALETTE pLogPal;
\r
182 static BOOL paletteChanged = FALSE;
\r
183 static HICON iconWhite, iconBlack, iconCurrent;
\r
184 static int doingSizing = FALSE;
\r
185 static int lastSizing = 0;
\r
186 static int prevStderrPort;
\r
188 /* [AS] Support for background textures */
\r
189 #define BACK_TEXTURE_MODE_DISABLED 0
\r
190 #define BACK_TEXTURE_MODE_PLAIN 1
\r
191 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
193 static HBITMAP liteBackTexture = NULL;
\r
194 static HBITMAP darkBackTexture = NULL;
\r
195 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
196 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
197 static int backTextureSquareSize = 0;
\r
198 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
200 #if __GNUC__ && !defined(_winmajor)
\r
201 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
203 #define oldDialog (_winmajor < 4)
\r
206 char *defaultTextAttribs[] =
\r
208 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
209 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
219 int cliWidth, cliHeight;
\r
222 SizeInfo sizeInfo[] =
\r
224 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
225 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
226 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
227 { "petite", 33, 1, 1, 1, 0, 0 },
\r
228 { "slim", 37, 2, 1, 0, 0, 0 },
\r
229 { "small", 40, 2, 1, 0, 0, 0 },
\r
230 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
231 { "middling", 49, 2, 0, 0, 0, 0 },
\r
232 { "average", 54, 2, 0, 0, 0, 0 },
\r
233 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
234 { "medium", 64, 3, 0, 0, 0, 0 },
\r
235 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
236 { "large", 80, 3, 0, 0, 0, 0 },
\r
237 { "big", 87, 3, 0, 0, 0, 0 },
\r
238 { "huge", 95, 3, 0, 0, 0, 0 },
\r
239 { "giant", 108, 3, 0, 0, 0, 0 },
\r
240 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
241 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
242 { NULL, 0, 0, 0, 0, 0, 0 }
\r
245 #define MF(x) {x, {0, }, {0, }, 0}
\r
246 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
248 { 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
249 { 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
250 { 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
251 { 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
252 { 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
253 { 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
254 { 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
255 { 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
256 { 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
257 { 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
258 { 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
259 { 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
260 { 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
261 { 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
262 { 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
263 { 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
264 { 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
265 { 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
268 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
277 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
278 #define N_BUTTONS 5
\r
280 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
282 {"<<", IDM_ToStart, NULL, NULL},
\r
283 {"<", IDM_Backward, NULL, NULL},
\r
284 {"P", IDM_Pause, NULL, NULL},
\r
285 {">", IDM_Forward, NULL, NULL},
\r
286 {">>", IDM_ToEnd, NULL, NULL},
\r
289 int tinyLayout = 0, smallLayout = 0;
\r
290 #define MENU_BAR_ITEMS 6
\r
291 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
292 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
293 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
297 MySound sounds[(int)NSoundClasses];
\r
298 MyTextAttribs textAttribs[(int)NColorClasses];
\r
300 MyColorizeAttribs colorizeAttribs[] = {
\r
301 { (COLORREF)0, 0, "Shout Text" },
\r
302 { (COLORREF)0, 0, "SShout/CShout" },
\r
303 { (COLORREF)0, 0, "Channel 1 Text" },
\r
304 { (COLORREF)0, 0, "Channel Text" },
\r
305 { (COLORREF)0, 0, "Kibitz Text" },
\r
306 { (COLORREF)0, 0, "Tell Text" },
\r
307 { (COLORREF)0, 0, "Challenge Text" },
\r
308 { (COLORREF)0, 0, "Request Text" },
\r
309 { (COLORREF)0, 0, "Seek Text" },
\r
310 { (COLORREF)0, 0, "Normal Text" },
\r
311 { (COLORREF)0, 0, "None" }
\r
316 static char *commentTitle;
\r
317 static char *commentText;
\r
318 static int commentIndex;
\r
319 static Boolean editComment = FALSE;
\r
320 HWND commentDialog = NULL;
\r
321 BOOLEAN commentDialogUp = FALSE;
\r
322 static int commentX, commentY, commentH, commentW;
\r
324 static char *analysisTitle;
\r
325 static char *analysisText;
\r
326 HWND analysisDialog = NULL;
\r
327 BOOLEAN analysisDialogUp = FALSE;
\r
328 static int analysisX, analysisY, analysisH, analysisW;
\r
330 char errorTitle[MSG_SIZ];
\r
331 char errorMessage[2*MSG_SIZ];
\r
332 HWND errorDialog = NULL;
\r
333 BOOLEAN moveErrorMessageUp = FALSE;
\r
334 BOOLEAN consoleEcho = TRUE;
\r
335 CHARFORMAT consoleCF;
\r
336 COLORREF consoleBackgroundColor;
\r
338 char *programVersion;
\r
344 typedef int CPKind;
\r
353 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
356 #define INPUT_SOURCE_BUF_SIZE 4096
\r
358 typedef struct _InputSource {
\r
365 char buf[INPUT_SOURCE_BUF_SIZE];
\r
369 InputCallback func;
\r
370 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
374 InputSource *consoleInputSource;
\r
379 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
380 VOID ConsoleCreate();
\r
382 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
383 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
384 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
385 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
387 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
388 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
389 void ParseIcsTextMenu(char *icsTextMenuString);
\r
390 VOID PopUpMoveDialog(char firstchar);
\r
391 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
395 int GameListOptions();
\r
397 HWND moveHistoryDialog = NULL;
\r
398 BOOLEAN moveHistoryDialogUp = FALSE;
\r
400 WindowPlacement wpMoveHistory;
\r
402 HWND evalGraphDialog = NULL;
\r
403 BOOLEAN evalGraphDialogUp = FALSE;
\r
405 WindowPlacement wpEvalGraph;
\r
407 HWND engineOutputDialog = NULL;
\r
408 BOOLEAN engineOutputDialogUp = FALSE;
\r
410 WindowPlacement wpEngineOutput;
\r
412 VOID MoveHistoryPopUp();
\r
413 VOID MoveHistoryPopDown();
\r
414 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
415 BOOL MoveHistoryIsUp();
\r
417 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
418 VOID EvalGraphPopUp();
\r
419 VOID EvalGraphPopDown();
\r
420 BOOL EvalGraphIsUp();
\r
422 VOID EngineOutputPopUp();
\r
423 VOID EngineOutputPopDown();
\r
424 BOOL EngineOutputIsUp();
\r
425 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
427 VOID GothicPopUp(char *title, char up);
\r
429 * Setting "frozen" should disable all user input other than deleting
\r
430 * the window. We do this while engines are initializing themselves.
\r
432 static int frozen = 0;
\r
433 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
439 if (frozen) return;
\r
441 hmenu = GetMenu(hwndMain);
\r
442 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
443 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
445 DrawMenuBar(hwndMain);
\r
448 /* Undo a FreezeUI */
\r
454 if (!frozen) return;
\r
456 hmenu = GetMenu(hwndMain);
\r
457 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
458 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
460 DrawMenuBar(hwndMain);
\r
463 /*---------------------------------------------------------------------------*\
\r
467 \*---------------------------------------------------------------------------*/
\r
470 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
471 LPSTR lpCmdLine, int nCmdShow)
\r
474 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
478 LoadLibrary("RICHED32.DLL");
\r
479 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
481 if (!InitApplication(hInstance)) {
\r
484 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
488 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
489 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
490 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
492 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
494 while (GetMessage(&msg, /* message structure */
\r
495 NULL, /* handle of window receiving the message */
\r
496 0, /* lowest message to examine */
\r
497 0)) /* highest message to examine */
\r
499 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
500 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
501 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
502 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
503 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
504 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
505 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
506 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
507 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
508 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
509 TranslateMessage(&msg); /* Translates virtual key codes */
\r
510 DispatchMessage(&msg); /* Dispatches message to window */
\r
515 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
518 /*---------------------------------------------------------------------------*\
\r
520 * Initialization functions
\r
522 \*---------------------------------------------------------------------------*/
\r
525 InitApplication(HINSTANCE hInstance)
\r
529 /* Fill in window class structure with parameters that describe the */
\r
532 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
533 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
534 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
535 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
536 wc.hInstance = hInstance; /* Owner of this class */
\r
537 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
538 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
539 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
540 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
541 wc.lpszClassName = szAppName; /* Name to register as */
\r
543 /* Register the window class and return success/failure code. */
\r
544 if (!RegisterClass(&wc)) return FALSE;
\r
546 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
547 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
549 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
550 wc.hInstance = hInstance;
\r
551 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
552 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
553 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
554 wc.lpszMenuName = NULL;
\r
555 wc.lpszClassName = szConsoleName;
\r
557 if (!RegisterClass(&wc)) return FALSE;
\r
562 /* Set by InitInstance, used by EnsureOnScreen */
\r
563 int screenHeight, screenWidth;
\r
566 EnsureOnScreen(int *x, int *y)
\r
568 int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
569 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
570 if (*x > screenWidth - 32) *x = 0;
\r
571 if (*y > screenHeight - 32) *y = 0;
\r
572 if (*x < 10) *x = 10;
\r
573 if (*y < gap) *y = gap;
\r
577 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
579 HWND hwnd; /* Main window handle. */
\r
581 WINDOWPLACEMENT wp;
\r
584 hInst = hInstance; /* Store instance handle in our global variable */
\r
586 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
587 *filepart = NULLCHAR;
\r
589 GetCurrentDirectory(MSG_SIZ, installDir);
\r
591 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
592 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
593 if (appData.debugMode) {
\r
594 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
595 setbuf(debugFP, NULL);
\r
600 InitEngineUCI( installDir, &first );
\r
601 InitEngineUCI( installDir, &second );
\r
603 /* Create a main window for this application instance. */
\r
604 hwnd = CreateWindow(szAppName, szTitle,
\r
605 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
606 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
607 NULL, NULL, hInstance, NULL);
\r
610 /* If window could not be created, return "failure" */
\r
615 iconWhite = LoadIcon(hInstance, "icon_white");
\r
616 iconBlack = LoadIcon(hInstance, "icon_black");
\r
617 iconCurrent = iconWhite;
\r
618 InitDrawingColors();
\r
619 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
620 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
621 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
622 /* Compute window size for each board size, and use the largest
\r
623 size that fits on this screen as the default. */
\r
624 InitDrawingSizes((BoardSize)ibs, 0);
\r
625 if (boardSize == (BoardSize)-1 &&
\r
626 winHeight <= screenHeight
\r
627 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
628 && winWidth <= screenWidth) {
\r
629 boardSize = (BoardSize)ibs;
\r
632 InitDrawingSizes(boardSize, 0);
\r
634 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
636 /* [AS] Load textures if specified */
\r
637 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
639 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
640 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
641 liteBackTextureMode = appData.liteBackTextureMode;
\r
643 if (liteBackTexture == NULL && appData.debugMode) {
\r
644 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
648 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
649 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
650 darkBackTextureMode = appData.darkBackTextureMode;
\r
652 if (darkBackTexture == NULL && appData.debugMode) {
\r
653 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
657 mysrandom( (unsigned) time(NULL) );
\r
659 /* Make a console window if needed */
\r
660 if (appData.icsActive) {
\r
664 /* [AS] Restore layout */
\r
665 if( wpMoveHistory.visible ) {
\r
666 MoveHistoryPopUp();
\r
669 if( wpEvalGraph.visible ) {
\r
673 if( wpEngineOutput.visible ) {
\r
674 EngineOutputPopUp();
\r
679 /* Make the window visible; update its client area; and return "success" */
\r
680 EnsureOnScreen(&boardX, &boardY);
\r
681 wp.length = sizeof(WINDOWPLACEMENT);
\r
683 wp.showCmd = nCmdShow;
\r
684 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
685 wp.rcNormalPosition.left = boardX;
\r
686 wp.rcNormalPosition.right = boardX + winWidth;
\r
687 wp.rcNormalPosition.top = boardY;
\r
688 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
689 SetWindowPlacement(hwndMain, &wp);
\r
691 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
692 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
694 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
695 if( gameInfo.variant != VariantFischeRandom ) {
\r
696 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
701 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
702 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
704 ShowWindow(hwndConsole, nCmdShow);
\r
706 UpdateWindow(hwnd);
\r
714 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
715 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
716 ArgSettingsFilename
\r
724 String *pString; // ArgString
\r
725 int *pInt; // ArgInt
\r
726 float *pFloat; // ArgFloat
\r
727 Boolean *pBoolean; // ArgBoolean
\r
728 COLORREF *pColor; // ArgColor
\r
729 ColorClass cc; // ArgAttribs
\r
730 String *pFilename; // ArgFilename
\r
731 BoardSize *pBoardSize; // ArgBoardSize
\r
732 int whichFont; // ArgFont
\r
733 DCB *pDCB; // ArgCommSettings
\r
734 String *pFilename; // ArgSettingsFilename
\r
742 ArgDescriptor argDescriptors[] = {
\r
743 /* positional arguments */
\r
744 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
745 { "", ArgNone, NULL },
\r
746 /* keyword arguments */
\r
747 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
748 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
749 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
750 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
751 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
752 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
753 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
754 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
755 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
756 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
757 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
758 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
759 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
760 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
761 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
762 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
763 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
764 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
766 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
768 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
770 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
771 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
773 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
774 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
775 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
776 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
777 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
778 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
779 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
780 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
781 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
782 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
783 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
784 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
785 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
786 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
787 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
788 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
789 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
790 /*!!bitmapDirectory?*/
\r
791 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
792 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
793 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
794 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
795 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
796 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
797 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
798 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
799 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
800 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
801 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
802 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
803 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
804 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
805 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
806 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
807 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
808 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
809 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
810 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
811 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
812 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
813 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
814 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
815 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
816 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
817 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
818 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
819 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
820 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
821 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
822 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
823 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
824 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
825 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
826 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
827 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
828 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
829 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
830 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
831 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
832 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
833 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
834 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
835 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
836 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
837 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
838 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
839 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
840 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
841 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
842 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
843 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
844 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
845 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
846 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
847 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
848 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
849 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
850 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
851 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
852 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
853 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
854 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
855 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
856 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
857 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
858 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
859 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
860 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
861 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
862 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
863 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
864 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
865 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
866 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
867 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
868 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
869 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
870 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
871 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
872 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
873 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
874 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
875 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
876 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
877 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
878 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
879 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
880 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
881 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
882 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
883 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
884 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
885 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
886 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
887 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
888 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
889 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
890 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
891 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
892 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
893 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
894 TRUE }, /* must come after all fonts */
\r
895 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
896 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
897 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
898 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
899 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
900 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
901 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
902 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
903 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
904 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
905 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
906 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
907 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
908 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
909 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
910 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
911 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
912 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
913 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
914 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
915 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
916 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
917 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
918 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
919 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
920 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
921 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
922 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
923 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
924 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
925 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
927 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
928 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
930 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
931 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
932 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
933 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
934 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
935 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
936 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
937 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
938 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
939 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
940 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
941 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
942 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
943 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
944 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
945 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
946 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
947 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
948 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
949 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
950 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
951 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
952 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
953 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
954 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
955 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
956 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
957 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
958 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
959 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
960 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
961 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
962 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
963 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
964 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
965 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
966 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
967 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
968 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
969 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
970 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
971 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
972 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
973 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
974 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
975 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
976 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
977 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
978 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
979 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
980 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
981 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
982 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
983 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
984 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
985 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
986 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
987 { "highlightLastMove", ArgBoolean,
\r
988 (LPVOID) &appData.highlightLastMove, TRUE },
\r
989 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
990 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
991 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
992 { "highlightDragging", ArgBoolean,
\r
993 (LPVOID) &appData.highlightDragging, TRUE },
\r
994 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
995 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
996 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
997 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
998 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
999 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1000 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1001 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1002 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1003 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1004 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1005 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1006 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1007 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1008 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1009 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1010 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1011 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1012 { "soundShout", ArgFilename,
\r
1013 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1014 { "soundSShout", ArgFilename,
\r
1015 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1016 { "soundChannel1", ArgFilename,
\r
1017 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1018 { "soundChannel", ArgFilename,
\r
1019 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1020 { "soundKibitz", ArgFilename,
\r
1021 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1022 { "soundTell", ArgFilename,
\r
1023 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1024 { "soundChallenge", ArgFilename,
\r
1025 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1026 { "soundRequest", ArgFilename,
\r
1027 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1028 { "soundSeek", ArgFilename,
\r
1029 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1030 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1031 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1032 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1033 { "soundIcsLoss", ArgFilename,
\r
1034 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1035 { "soundIcsDraw", ArgFilename,
\r
1036 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1037 { "soundIcsUnfinished", ArgFilename,
\r
1038 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1039 { "soundIcsAlarm", ArgFilename,
\r
1040 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1041 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1042 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1043 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1044 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1045 { "reuseChessPrograms", ArgBoolean,
\r
1046 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1047 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1048 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1049 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1050 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1051 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1052 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1053 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1054 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1055 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1056 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1057 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1058 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1059 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1060 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1061 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1062 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1063 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1064 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1065 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1066 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1067 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1068 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1069 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1070 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1071 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1072 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1073 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1074 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1075 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1076 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1077 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1078 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1079 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1080 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1081 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1082 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1083 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1085 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1087 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1088 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1089 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1090 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1091 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1092 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1093 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1094 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1095 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1096 /* [AS] New features */
\r
1097 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1098 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1099 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1100 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1101 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1102 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1103 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1104 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1105 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1106 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1107 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1108 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1109 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1110 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1111 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1112 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1113 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1114 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1115 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1116 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1117 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1118 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1119 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1120 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1121 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1122 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1123 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1124 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1125 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1126 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1127 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1128 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1129 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1130 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1131 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1132 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1133 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1134 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1135 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1136 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1137 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1138 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1139 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1140 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1141 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1142 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1143 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1144 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1146 /* [AS] Layout stuff */
\r
1147 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1148 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1149 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1150 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1151 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1153 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1154 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1155 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1156 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1157 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1159 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1160 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1161 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1162 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1163 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1165 /* [HGM] board-size, adjudication and misc. options */
\r
1166 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1167 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1168 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1169 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1170 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1171 { "flipBlack", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1172 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1173 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1174 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1175 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1176 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1177 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1178 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1179 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1182 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1183 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1184 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1185 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1186 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1187 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1188 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1189 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1190 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1191 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1192 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1193 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1194 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1196 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1197 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1198 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1199 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1200 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1201 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1202 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1204 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1205 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1206 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1207 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1208 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1209 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1210 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1211 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1212 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1213 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1214 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1215 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1216 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1217 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1218 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1219 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1220 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1221 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1223 { NULL, ArgNone, NULL, FALSE }
\r
1227 /* Kludge for indirection files on command line */
\r
1228 char* lastIndirectionFilename;
\r
1229 ArgDescriptor argDescriptorIndirection =
\r
1230 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1234 ExitArgError(char *msg, char *badArg)
\r
1236 char buf[MSG_SIZ];
\r
1238 sprintf(buf, "%s %s", msg, badArg);
\r
1239 DisplayFatalError(buf, 0, 2);
\r
1243 /* Command line font name parser. NULL name means do nothing.
\r
1244 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1245 For backward compatibility, syntax without the colon is also
\r
1246 accepted, but font names with digits in them won't work in that case.
\r
1249 ParseFontName(char *name, MyFontParams *mfp)
\r
1252 if (name == NULL) return;
\r
1254 q = strchr(p, ':');
\r
1256 if (q - p >= sizeof(mfp->faceName))
\r
1257 ExitArgError("Font name too long:", name);
\r
1258 memcpy(mfp->faceName, p, q - p);
\r
1259 mfp->faceName[q - p] = NULLCHAR;
\r
1262 q = mfp->faceName;
\r
1263 while (*p && !isdigit(*p)) {
\r
1265 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1266 ExitArgError("Font name too long:", name);
\r
1268 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1271 if (!*p) ExitArgError("Font point size missing:", name);
\r
1272 mfp->pointSize = (float) atof(p);
\r
1273 mfp->bold = (strchr(p, 'b') != NULL);
\r
1274 mfp->italic = (strchr(p, 'i') != NULL);
\r
1275 mfp->underline = (strchr(p, 'u') != NULL);
\r
1276 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1279 /* Color name parser.
\r
1280 X version accepts X color names, but this one
\r
1281 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1283 ParseColorName(char *name)
\r
1285 int red, green, blue, count;
\r
1286 char buf[MSG_SIZ];
\r
1288 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1290 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1291 &red, &green, &blue);
\r
1294 sprintf(buf, "Can't parse color name %s", name);
\r
1295 DisplayError(buf, 0);
\r
1296 return RGB(0, 0, 0);
\r
1298 return PALETTERGB(red, green, blue);
\r
1302 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1304 char *e = argValue;
\r
1308 if (*e == 'b') eff |= CFE_BOLD;
\r
1309 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1310 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1311 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1312 else if (*e == '#' || isdigit(*e)) break;
\r
1316 *color = ParseColorName(e);
\r
1321 ParseBoardSize(char *name)
\r
1323 BoardSize bs = SizeTiny;
\r
1324 while (sizeInfo[bs].name != NULL) {
\r
1325 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1328 ExitArgError("Unrecognized board size value", name);
\r
1329 return bs; /* not reached */
\r
1334 StringGet(void *getClosure)
\r
1336 char **p = (char **) getClosure;
\r
1341 FileGet(void *getClosure)
\r
1344 FILE* f = (FILE*) getClosure;
\r
1353 /* Parse settings file named "name". If file found, return the
\r
1354 full name in fullname and return TRUE; else return FALSE */
\r
1356 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1361 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1362 f = fopen(fullname, "r");
\r
1364 ParseArgs(FileGet, f);
\r
1373 ParseArgs(GetFunc get, void *cl)
\r
1375 char argName[ARG_MAX];
\r
1376 char argValue[ARG_MAX];
\r
1377 ArgDescriptor *ad;
\r
1386 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1387 if (ch == NULLCHAR) break;
\r
1389 /* Comment to end of line */
\r
1391 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1393 } else if (ch == '/' || ch == '-') {
\r
1396 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1397 ch != '\n' && ch != '\t') {
\r
1403 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1404 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1406 if (ad->argName == NULL)
\r
1407 ExitArgError("Unrecognized argument", argName);
\r
1409 } else if (ch == '@') {
\r
1410 /* Indirection file */
\r
1411 ad = &argDescriptorIndirection;
\r
1414 /* Positional argument */
\r
1415 ad = &argDescriptors[posarg++];
\r
1416 strcpy(argName, ad->argName);
\r
1419 if (ad->argType == ArgTrue) {
\r
1420 *(Boolean *) ad->argLoc = TRUE;
\r
1423 if (ad->argType == ArgFalse) {
\r
1424 *(Boolean *) ad->argLoc = FALSE;
\r
1428 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1429 if (ch == NULLCHAR || ch == '\n') {
\r
1430 ExitArgError("No value provided for argument", argName);
\r
1434 // Quoting with { }. No characters have to (or can) be escaped.
\r
1435 // Thus the string cannot contain a '}' character.
\r
1455 } else if (ch == '\'' || ch == '"') {
\r
1456 // Quoting with ' ' or " ", with \ as escape character.
\r
1457 // Inconvenient for long strings that may contain Windows filenames.
\r
1474 if (ch == start) {
\r
1483 if (ad->argType == ArgFilename
\r
1484 || ad->argType == ArgSettingsFilename) {
\r
1490 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1514 for (i = 0; i < 3; i++) {
\r
1515 if (ch >= '0' && ch <= '7') {
\r
1516 octval = octval*8 + (ch - '0');
\r
1523 *q++ = (char) octval;
\r
1534 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1541 switch (ad->argType) {
\r
1543 *(int *) ad->argLoc = atoi(argValue);
\r
1547 *(float *) ad->argLoc = (float) atof(argValue);
\r
1552 *(char **) ad->argLoc = strdup(argValue);
\r
1555 case ArgSettingsFilename:
\r
1557 char fullname[MSG_SIZ];
\r
1558 if (ParseSettingsFile(argValue, fullname)) {
\r
1559 if (ad->argLoc != NULL) {
\r
1560 *(char **) ad->argLoc = strdup(fullname);
\r
1563 if (ad->argLoc != NULL) {
\r
1565 ExitArgError("Failed to open indirection file", argValue);
\r
1572 switch (argValue[0]) {
\r
1575 *(Boolean *) ad->argLoc = TRUE;
\r
1579 *(Boolean *) ad->argLoc = FALSE;
\r
1582 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1588 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1591 case ArgAttribs: {
\r
1592 ColorClass cc = (ColorClass)ad->argLoc;
\r
1593 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1597 case ArgBoardSize:
\r
1598 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1602 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1605 case ArgCommSettings:
\r
1606 ParseCommSettings(argValue, &dcb);
\r
1610 ExitArgError("Unrecognized argument", argValue);
\r
1617 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1619 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1620 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1623 lf->lfEscapement = 0;
\r
1624 lf->lfOrientation = 0;
\r
1625 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1626 lf->lfItalic = mfp->italic;
\r
1627 lf->lfUnderline = mfp->underline;
\r
1628 lf->lfStrikeOut = mfp->strikeout;
\r
1629 lf->lfCharSet = DEFAULT_CHARSET;
\r
1630 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1631 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1632 lf->lfQuality = DEFAULT_QUALITY;
\r
1633 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1634 strcpy(lf->lfFaceName, mfp->faceName);
\r
1638 CreateFontInMF(MyFont *mf)
\r
1640 LFfromMFP(&mf->lf, &mf->mfp);
\r
1641 if (mf->hf) DeleteObject(mf->hf);
\r
1642 mf->hf = CreateFontIndirect(&mf->lf);
\r
1646 SetDefaultTextAttribs()
\r
1649 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1650 ParseAttribs(&textAttribs[cc].color,
\r
1651 &textAttribs[cc].effects,
\r
1652 defaultTextAttribs[cc]);
\r
1657 SetDefaultSounds()
\r
1661 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1662 textAttribs[cc].sound.name = strdup("");
\r
1663 textAttribs[cc].sound.data = NULL;
\r
1665 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1666 sounds[sc].name = strdup("");
\r
1667 sounds[sc].data = NULL;
\r
1669 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1677 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1678 MyLoadSound(&textAttribs[cc].sound);
\r
1680 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1681 MyLoadSound(&sounds[sc]);
\r
1686 InitAppData(LPSTR lpCmdLine)
\r
1689 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1692 programName = szAppName;
\r
1694 /* Initialize to defaults */
\r
1695 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1696 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1697 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1698 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1699 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1700 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1701 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1702 SetDefaultTextAttribs();
\r
1703 SetDefaultSounds();
\r
1704 appData.movesPerSession = MOVES_PER_SESSION;
\r
1705 appData.initString = INIT_STRING;
\r
1706 appData.secondInitString = INIT_STRING;
\r
1707 appData.firstComputerString = COMPUTER_STRING;
\r
1708 appData.secondComputerString = COMPUTER_STRING;
\r
1709 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1710 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1711 appData.firstPlaysBlack = FALSE;
\r
1712 appData.noChessProgram = FALSE;
\r
1713 chessProgram = FALSE;
\r
1714 appData.firstHost = FIRST_HOST;
\r
1715 appData.secondHost = SECOND_HOST;
\r
1716 appData.firstDirectory = FIRST_DIRECTORY;
\r
1717 appData.secondDirectory = SECOND_DIRECTORY;
\r
1718 appData.bitmapDirectory = "";
\r
1719 appData.remoteShell = REMOTE_SHELL;
\r
1720 appData.remoteUser = "";
\r
1721 appData.timeDelay = TIME_DELAY;
\r
1722 appData.timeControl = TIME_CONTROL;
\r
1723 appData.timeIncrement = TIME_INCREMENT;
\r
1724 appData.icsActive = FALSE;
\r
1725 appData.icsHost = "";
\r
1726 appData.icsPort = ICS_PORT;
\r
1727 appData.icsCommPort = ICS_COMM_PORT;
\r
1728 appData.icsLogon = ICS_LOGON;
\r
1729 appData.icsHelper = "";
\r
1730 appData.useTelnet = FALSE;
\r
1731 appData.telnetProgram = TELNET_PROGRAM;
\r
1732 appData.gateway = "";
\r
1733 appData.loadGameFile = "";
\r
1734 appData.loadGameIndex = 0;
\r
1735 appData.saveGameFile = "";
\r
1736 appData.autoSaveGames = FALSE;
\r
1737 appData.loadPositionFile = "";
\r
1738 appData.loadPositionIndex = 1;
\r
1739 appData.savePositionFile = "";
\r
1740 appData.matchMode = FALSE;
\r
1741 appData.matchGames = 0;
\r
1742 appData.monoMode = FALSE;
\r
1743 appData.debugMode = FALSE;
\r
1744 appData.clockMode = TRUE;
\r
1745 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1746 appData.Iconic = FALSE; /*unused*/
\r
1747 appData.searchTime = "";
\r
1748 appData.searchDepth = 0;
\r
1749 appData.showCoords = FALSE;
\r
1750 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1751 appData.autoCallFlag = FALSE;
\r
1752 appData.flipView = FALSE;
\r
1753 appData.autoFlipView = TRUE;
\r
1754 appData.cmailGameName = "";
\r
1755 appData.alwaysPromoteToQueen = FALSE;
\r
1756 appData.oldSaveStyle = FALSE;
\r
1757 appData.quietPlay = FALSE;
\r
1758 appData.showThinking = FALSE;
\r
1759 appData.ponderNextMove = TRUE;
\r
1760 appData.periodicUpdates = TRUE;
\r
1761 appData.popupExitMessage = TRUE;
\r
1762 appData.popupMoveErrors = FALSE;
\r
1763 appData.autoObserve = FALSE;
\r
1764 appData.autoComment = FALSE;
\r
1765 appData.animate = TRUE;
\r
1766 appData.animSpeed = 10;
\r
1767 appData.animateDragging = TRUE;
\r
1768 appData.highlightLastMove = TRUE;
\r
1769 appData.getMoveList = TRUE;
\r
1770 appData.testLegality = TRUE;
\r
1771 appData.premove = TRUE;
\r
1772 appData.premoveWhite = FALSE;
\r
1773 appData.premoveWhiteText = "";
\r
1774 appData.premoveBlack = FALSE;
\r
1775 appData.premoveBlackText = "";
\r
1776 appData.icsAlarm = TRUE;
\r
1777 appData.icsAlarmTime = 5000;
\r
1778 appData.autoRaiseBoard = TRUE;
\r
1779 appData.localLineEditing = TRUE;
\r
1780 appData.colorize = TRUE;
\r
1781 appData.reuseFirst = TRUE;
\r
1782 appData.reuseSecond = TRUE;
\r
1783 appData.blindfold = FALSE;
\r
1784 dcb.DCBlength = sizeof(DCB);
\r
1785 dcb.BaudRate = 9600;
\r
1786 dcb.fBinary = TRUE;
\r
1787 dcb.fParity = FALSE;
\r
1788 dcb.fOutxCtsFlow = FALSE;
\r
1789 dcb.fOutxDsrFlow = FALSE;
\r
1790 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1791 dcb.fDsrSensitivity = FALSE;
\r
1792 dcb.fTXContinueOnXoff = TRUE;
\r
1793 dcb.fOutX = FALSE;
\r
1795 dcb.fNull = FALSE;
\r
1796 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1797 dcb.fAbortOnError = FALSE;
\r
1798 dcb.wReserved = 0;
\r
1800 dcb.Parity = SPACEPARITY;
\r
1801 dcb.StopBits = ONESTOPBIT;
\r
1802 settingsFileName = SETTINGS_FILE;
\r
1803 saveSettingsOnExit = TRUE;
\r
1804 boardX = CW_USEDEFAULT;
\r
1805 boardY = CW_USEDEFAULT;
\r
1806 consoleX = CW_USEDEFAULT;
\r
1807 consoleY = CW_USEDEFAULT;
\r
1808 consoleW = CW_USEDEFAULT;
\r
1809 consoleH = CW_USEDEFAULT;
\r
1810 analysisX = CW_USEDEFAULT;
\r
1811 analysisY = CW_USEDEFAULT;
\r
1812 analysisW = CW_USEDEFAULT;
\r
1813 analysisH = CW_USEDEFAULT;
\r
1814 commentX = CW_USEDEFAULT;
\r
1815 commentY = CW_USEDEFAULT;
\r
1816 commentW = CW_USEDEFAULT;
\r
1817 commentH = CW_USEDEFAULT;
\r
1818 editTagsX = CW_USEDEFAULT;
\r
1819 editTagsY = CW_USEDEFAULT;
\r
1820 editTagsW = CW_USEDEFAULT;
\r
1821 editTagsH = CW_USEDEFAULT;
\r
1822 gameListX = CW_USEDEFAULT;
\r
1823 gameListY = CW_USEDEFAULT;
\r
1824 gameListW = CW_USEDEFAULT;
\r
1825 gameListH = CW_USEDEFAULT;
\r
1826 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1827 icsNames = ICS_NAMES;
\r
1828 firstChessProgramNames = FCP_NAMES;
\r
1829 secondChessProgramNames = SCP_NAMES;
\r
1830 appData.initialMode = "";
\r
1831 appData.variant = "normal";
\r
1832 appData.firstProtocolVersion = PROTOVER;
\r
1833 appData.secondProtocolVersion = PROTOVER;
\r
1834 appData.showButtonBar = TRUE;
\r
1836 /* [AS] New properties (see comments in header file) */
\r
1837 appData.firstScoreIsAbsolute = FALSE;
\r
1838 appData.secondScoreIsAbsolute = FALSE;
\r
1839 appData.saveExtendedInfoInPGN = FALSE;
\r
1840 appData.hideThinkingFromHuman = FALSE;
\r
1841 appData.liteBackTextureFile = "";
\r
1842 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1843 appData.darkBackTextureFile = "";
\r
1844 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1845 appData.renderPiecesWithFont = "";
\r
1846 appData.fontToPieceTable = "";
\r
1847 appData.fontBackColorWhite = 0;
\r
1848 appData.fontForeColorWhite = 0;
\r
1849 appData.fontBackColorBlack = 0;
\r
1850 appData.fontForeColorBlack = 0;
\r
1851 appData.fontPieceSize = 80;
\r
1852 appData.overrideLineGap = 1;
\r
1853 appData.adjudicateLossThreshold = 0;
\r
1854 appData.delayBeforeQuit = 0;
\r
1855 appData.delayAfterQuit = 0;
\r
1856 appData.nameOfDebugFile = "winboard.debug";
\r
1857 appData.pgnEventHeader = "Computer Chess Game";
\r
1858 appData.defaultFrcPosition = -1;
\r
1859 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1860 appData.saveOutOfBookInfo = TRUE;
\r
1861 appData.showEvalInMoveHistory = TRUE;
\r
1862 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1863 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1864 appData.highlightMoveWithArrow = FALSE;
\r
1865 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1866 appData.useStickyWindows = TRUE;
\r
1867 appData.adjudicateDrawMoves = 0;
\r
1868 appData.autoDisplayComment = TRUE;
\r
1869 appData.autoDisplayTags = TRUE;
\r
1870 appData.firstIsUCI = FALSE;
\r
1871 appData.secondIsUCI = FALSE;
\r
1872 appData.firstHasOwnBookUCI = TRUE;
\r
1873 appData.secondHasOwnBookUCI = TRUE;
\r
1874 appData.polyglotDir = "";
\r
1875 appData.usePolyglotBook = FALSE;
\r
1876 appData.polyglotBook = "";
\r
1877 appData.defaultHashSize = 64;
\r
1878 appData.defaultCacheSizeEGTB = 4;
\r
1879 appData.defaultPathEGTB = "c:\\egtb";
\r
1881 InitWindowPlacement( &wpMoveHistory );
\r
1882 InitWindowPlacement( &wpEvalGraph );
\r
1883 InitWindowPlacement( &wpEngineOutput );
\r
1885 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1886 appData.NrFiles = -1;
\r
1887 appData.NrRanks = -1;
\r
1888 appData.holdingsSize = -1;
\r
1889 appData.testClaims = FALSE;
\r
1890 appData.checkMates = FALSE;
\r
1891 appData.materialDraws= FALSE;
\r
1892 appData.trivialDraws = FALSE;
\r
1893 appData.ruleMoves = 51;
\r
1894 appData.drawRepeats = 6;
\r
1895 appData.matchPause = 10000;
\r
1896 appData.alphaRank = FALSE;
\r
1897 appData.allWhite = FALSE;
\r
1898 appData.upsideDown = FALSE;
\r
1901 appData.zippyTalk = ZIPPY_TALK;
\r
1902 appData.zippyPlay = ZIPPY_PLAY;
\r
1903 appData.zippyLines = ZIPPY_LINES;
\r
1904 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1905 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1906 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1907 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1908 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1909 appData.zippyUseI = ZIPPY_USE_I;
\r
1910 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1911 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1912 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1913 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1914 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1915 appData.zippyAbort = ZIPPY_ABORT;
\r
1916 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1917 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1918 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1921 /* Point font array elements to structures and
\r
1922 parse default font names */
\r
1923 for (i=0; i<NUM_FONTS; i++) {
\r
1924 for (j=0; j<NUM_SIZES; j++) {
\r
1925 font[j][i] = &fontRec[j][i];
\r
1926 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1930 /* Parse default settings file if any */
\r
1931 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1932 settingsFileName = strdup(buf);
\r
1935 /* Parse command line */
\r
1936 ParseArgs(StringGet, &lpCmdLine);
\r
1938 /* [HGM] make sure board size is acceptable */
\r
1939 if(appData.NrFiles > BOARD_SIZE ||
\r
1940 appData.NrRanks > BOARD_SIZE )
\r
1941 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
1943 /* Propagate options that affect others */
\r
1944 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1945 if (appData.icsActive || appData.noChessProgram) {
\r
1946 chessProgram = FALSE; /* not local chess program mode */
\r
1949 /* Open startup dialog if needed */
\r
1950 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1951 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1952 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1953 *appData.secondChessProgram == NULLCHAR))) {
\r
1956 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1957 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1958 FreeProcInstance(lpProc);
\r
1961 /* Make sure save files land in the right (?) directory */
\r
1962 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1963 appData.saveGameFile = strdup(buf);
\r
1965 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1966 appData.savePositionFile = strdup(buf);
\r
1969 /* Finish initialization for fonts and sounds */
\r
1970 for (i=0; i<NUM_FONTS; i++) {
\r
1971 for (j=0; j<NUM_SIZES; j++) {
\r
1972 CreateFontInMF(font[j][i]);
\r
1975 /* xboard, and older WinBoards, controlled the move sound with the
\r
1976 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1977 always turn the option on (so that the backend will call us),
\r
1978 then let the user turn the sound off by setting it to silence if
\r
1979 desired. To accommodate old winboard.ini files saved by old
\r
1980 versions of WinBoard, we also turn off the sound if the option
\r
1981 was initially set to false. */
\r
1982 if (!appData.ringBellAfterMoves) {
\r
1983 sounds[(int)SoundMove].name = strdup("");
\r
1984 appData.ringBellAfterMoves = TRUE;
\r
1986 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1987 SetCurrentDirectory(installDir);
\r
1989 SetCurrentDirectory(currDir);
\r
1991 p = icsTextMenuString;
\r
1992 if (p[0] == '@') {
\r
1993 FILE* f = fopen(p + 1, "r");
\r
1995 DisplayFatalError(p + 1, errno, 2);
\r
1998 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2000 buf[i] = NULLCHAR;
\r
2003 ParseIcsTextMenu(strdup(p));
\r
2010 HMENU hmenu = GetMenu(hwndMain);
\r
2012 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2013 MF_BYCOMMAND|((appData.icsActive &&
\r
2014 *appData.icsCommPort != NULLCHAR) ?
\r
2015 MF_ENABLED : MF_GRAYED));
\r
2016 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2017 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2018 MF_CHECKED : MF_UNCHECKED));
\r
2023 SaveSettings(char* name)
\r
2026 ArgDescriptor *ad;
\r
2027 WINDOWPLACEMENT wp;
\r
2028 char dir[MSG_SIZ];
\r
2030 if (!hwndMain) return;
\r
2032 GetCurrentDirectory(MSG_SIZ, dir);
\r
2033 SetCurrentDirectory(installDir);
\r
2034 f = fopen(name, "w");
\r
2035 SetCurrentDirectory(dir);
\r
2037 DisplayError(name, errno);
\r
2040 fprintf(f, ";\n");
\r
2041 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2042 fprintf(f, ";\n");
\r
2043 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2044 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2045 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2046 fprintf(f, ";\n");
\r
2048 wp.length = sizeof(WINDOWPLACEMENT);
\r
2049 GetWindowPlacement(hwndMain, &wp);
\r
2050 boardX = wp.rcNormalPosition.left;
\r
2051 boardY = wp.rcNormalPosition.top;
\r
2053 if (hwndConsole) {
\r
2054 GetWindowPlacement(hwndConsole, &wp);
\r
2055 consoleX = wp.rcNormalPosition.left;
\r
2056 consoleY = wp.rcNormalPosition.top;
\r
2057 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2058 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2061 if (analysisDialog) {
\r
2062 GetWindowPlacement(analysisDialog, &wp);
\r
2063 analysisX = wp.rcNormalPosition.left;
\r
2064 analysisY = wp.rcNormalPosition.top;
\r
2065 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2066 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2069 if (commentDialog) {
\r
2070 GetWindowPlacement(commentDialog, &wp);
\r
2071 commentX = wp.rcNormalPosition.left;
\r
2072 commentY = wp.rcNormalPosition.top;
\r
2073 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2074 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2077 if (editTagsDialog) {
\r
2078 GetWindowPlacement(editTagsDialog, &wp);
\r
2079 editTagsX = wp.rcNormalPosition.left;
\r
2080 editTagsY = wp.rcNormalPosition.top;
\r
2081 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2082 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2085 if (gameListDialog) {
\r
2086 GetWindowPlacement(gameListDialog, &wp);
\r
2087 gameListX = wp.rcNormalPosition.left;
\r
2088 gameListY = wp.rcNormalPosition.top;
\r
2089 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2090 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2093 /* [AS] Move history */
\r
2094 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2096 if( moveHistoryDialog ) {
\r
2097 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2098 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2099 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2100 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2101 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2104 /* [AS] Eval graph */
\r
2105 wpEvalGraph.visible = EvalGraphIsUp();
\r
2107 if( evalGraphDialog ) {
\r
2108 GetWindowPlacement(evalGraphDialog, &wp);
\r
2109 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2110 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2111 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2112 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2115 /* [AS] Engine output */
\r
2116 wpEngineOutput.visible = EngineOutputIsUp();
\r
2118 if( engineOutputDialog ) {
\r
2119 GetWindowPlacement(engineOutputDialog, &wp);
\r
2120 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2121 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2122 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2123 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2126 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2127 if (!ad->save) continue;
\r
2128 switch (ad->argType) {
\r
2131 char *p = *(char **)ad->argLoc;
\r
2132 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2133 /* Quote multiline values or \-containing values
\r
2134 with { } if possible */
\r
2135 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2137 /* Else quote with " " */
\r
2138 fprintf(f, "/%s=\"", ad->argName);
\r
2140 if (*p == '\n') fprintf(f, "\n");
\r
2141 else if (*p == '\r') fprintf(f, "\\r");
\r
2142 else if (*p == '\t') fprintf(f, "\\t");
\r
2143 else if (*p == '\b') fprintf(f, "\\b");
\r
2144 else if (*p == '\f') fprintf(f, "\\f");
\r
2145 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2146 else if (*p == '\"') fprintf(f, "\\\"");
\r
2147 else if (*p == '\\') fprintf(f, "\\\\");
\r
2151 fprintf(f, "\"\n");
\r
2156 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2159 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2162 fprintf(f, "/%s=%s\n", ad->argName,
\r
2163 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2166 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2169 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2173 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2174 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2175 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2180 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2181 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2182 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2183 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2184 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2185 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2186 (ta->effects) ? " " : "",
\r
2187 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2191 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2192 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2194 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2197 case ArgBoardSize:
\r
2198 fprintf(f, "/%s=%s\n", ad->argName,
\r
2199 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2204 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2205 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2206 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2207 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2208 ad->argName, mfp->faceName, mfp->pointSize,
\r
2209 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2210 mfp->bold ? "b" : "",
\r
2211 mfp->italic ? "i" : "",
\r
2212 mfp->underline ? "u" : "",
\r
2213 mfp->strikeout ? "s" : "");
\r
2217 case ArgCommSettings:
\r
2218 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2226 /*---------------------------------------------------------------------------*\
\r
2228 * GDI board drawing routines
\r
2230 \*---------------------------------------------------------------------------*/
\r
2232 /* [AS] Draw square using background texture */
\r
2233 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2238 return; /* Should never happen! */
\r
2241 SetGraphicsMode( dst, GM_ADVANCED );
\r
2248 /* X reflection */
\r
2253 x.eDx = (FLOAT) dw + dx - 1;
\r
2256 SetWorldTransform( dst, &x );
\r
2259 /* Y reflection */
\r
2265 x.eDy = (FLOAT) dh + dy - 1;
\r
2267 SetWorldTransform( dst, &x );
\r
2275 x.eDx = (FLOAT) dx;
\r
2276 x.eDy = (FLOAT) dy;
\r
2279 SetWorldTransform( dst, &x );
\r
2283 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2291 SetWorldTransform( dst, &x );
\r
2293 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2296 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2298 PM_WP = (int) WhitePawn,
\r
2299 PM_WN = (int) WhiteKnight,
\r
2300 PM_WB = (int) WhiteBishop,
\r
2301 PM_WR = (int) WhiteRook,
\r
2302 PM_WQ = (int) WhiteQueen,
\r
2303 PM_WF = (int) WhiteFerz,
\r
2304 PM_WW = (int) WhiteWazir,
\r
2305 PM_WE = (int) WhiteAlfil,
\r
2306 PM_WM = (int) WhiteMan,
\r
2307 PM_WO = (int) WhiteCannon,
\r
2308 PM_WU = (int) WhiteUnicorn,
\r
2309 PM_WH = (int) WhiteNightrider,
\r
2310 PM_WA = (int) WhiteCardinal,
\r
2311 PM_WC = (int) WhiteMarshall,
\r
2312 PM_WG = (int) WhiteGrasshopper,
\r
2313 PM_WK = (int) WhiteKing,
\r
2314 PM_BP = (int) BlackPawn,
\r
2315 PM_BN = (int) BlackKnight,
\r
2316 PM_BB = (int) BlackBishop,
\r
2317 PM_BR = (int) BlackRook,
\r
2318 PM_BQ = (int) BlackQueen,
\r
2319 PM_BF = (int) BlackFerz,
\r
2320 PM_BW = (int) BlackWazir,
\r
2321 PM_BE = (int) BlackAlfil,
\r
2322 PM_BM = (int) BlackMan,
\r
2323 PM_BO = (int) BlackCannon,
\r
2324 PM_BU = (int) BlackUnicorn,
\r
2325 PM_BH = (int) BlackNightrider,
\r
2326 PM_BA = (int) BlackCardinal,
\r
2327 PM_BC = (int) BlackMarshall,
\r
2328 PM_BG = (int) BlackGrasshopper,
\r
2329 PM_BK = (int) BlackKing
\r
2332 static HFONT hPieceFont = NULL;
\r
2333 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2334 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2335 static int fontBitmapSquareSize = 0;
\r
2336 static char pieceToFontChar[(int) EmptySquare] =
\r
2337 { 'p', 'n', 'b', 'r', 'q',
\r
2338 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2339 'k', 'o', 'm', 'v', 't', 'w',
\r
2340 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2343 extern BOOL SetCharTable( char *table, const char * map );
\r
2344 /* [HGM] moved to backend.c */
\r
2346 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2349 BYTE r1 = GetRValue( color );
\r
2350 BYTE g1 = GetGValue( color );
\r
2351 BYTE b1 = GetBValue( color );
\r
2357 /* Create a uniform background first */
\r
2358 hbrush = CreateSolidBrush( color );
\r
2359 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2360 FillRect( hdc, &rc, hbrush );
\r
2361 DeleteObject( hbrush );
\r
2364 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2365 int steps = squareSize / 2;
\r
2368 for( i=0; i<steps; i++ ) {
\r
2369 BYTE r = r1 - (r1-r2) * i / steps;
\r
2370 BYTE g = g1 - (g1-g2) * i / steps;
\r
2371 BYTE b = b1 - (b1-b2) * i / steps;
\r
2373 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2374 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2375 FillRect( hdc, &rc, hbrush );
\r
2376 DeleteObject(hbrush);
\r
2379 else if( mode == 2 ) {
\r
2380 /* Diagonal gradient, good more or less for every piece */
\r
2381 POINT triangle[3];
\r
2382 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2383 HBRUSH hbrush_old;
\r
2384 int steps = squareSize;
\r
2387 triangle[0].x = squareSize - steps;
\r
2388 triangle[0].y = squareSize;
\r
2389 triangle[1].x = squareSize;
\r
2390 triangle[1].y = squareSize;
\r
2391 triangle[2].x = squareSize;
\r
2392 triangle[2].y = squareSize - steps;
\r
2394 for( i=0; i<steps; i++ ) {
\r
2395 BYTE r = r1 - (r1-r2) * i / steps;
\r
2396 BYTE g = g1 - (g1-g2) * i / steps;
\r
2397 BYTE b = b1 - (b1-b2) * i / steps;
\r
2399 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2400 hbrush_old = SelectObject( hdc, hbrush );
\r
2401 Polygon( hdc, triangle, 3 );
\r
2402 SelectObject( hdc, hbrush_old );
\r
2403 DeleteObject(hbrush);
\r
2408 SelectObject( hdc, hpen );
\r
2413 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2414 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2415 piece: follow the steps as explained below.
\r
2417 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2421 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2425 int backColor = whitePieceColor;
\r
2426 int foreColor = blackPieceColor;
\r
2427 int shapeIndex = index < 6 ? index+6 : index;
\r
2429 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2430 backColor = appData.fontBackColorWhite;
\r
2431 foreColor = appData.fontForeColorWhite;
\r
2433 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2434 backColor = appData.fontBackColorBlack;
\r
2435 foreColor = appData.fontForeColorBlack;
\r
2439 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2441 hbm_old = SelectObject( hdc, hbm );
\r
2445 rc.right = squareSize;
\r
2446 rc.bottom = squareSize;
\r
2448 /* Step 1: background is now black */
\r
2449 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2451 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2453 pt.x = (squareSize - sz.cx) / 2;
\r
2454 pt.y = (squareSize - sz.cy) / 2;
\r
2456 SetBkMode( hdc, TRANSPARENT );
\r
2457 SetTextColor( hdc, chroma );
\r
2458 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2459 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2461 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2462 /* Step 3: the area outside the piece is filled with white */
\r
2463 FloodFill( hdc, 0, 0, chroma );
\r
2464 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2466 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2467 but if the start point is not inside the piece we're lost!
\r
2468 There should be a better way to do this... if we could create a region or path
\r
2469 from the fill operation we would be fine for example.
\r
2471 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2473 SetTextColor( hdc, 0 );
\r
2475 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2476 draw the piece again in black for safety.
\r
2478 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2480 SelectObject( hdc, hbm_old );
\r
2482 if( hPieceMask[index] != NULL ) {
\r
2483 DeleteObject( hPieceMask[index] );
\r
2486 hPieceMask[index] = hbm;
\r
2489 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2491 SelectObject( hdc, hbm );
\r
2494 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2495 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2496 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2498 SelectObject( dc1, hPieceMask[index] );
\r
2499 SelectObject( dc2, bm2 );
\r
2500 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2501 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2504 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2505 the piece background and deletes (makes transparent) the rest.
\r
2506 Thanks to that mask, we are free to paint the background with the greates
\r
2507 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2508 We use this, to make gradients and give the pieces a "roundish" look.
\r
2510 SetPieceBackground( hdc, backColor, 2 );
\r
2511 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2515 DeleteObject( bm2 );
\r
2518 SetTextColor( hdc, foreColor );
\r
2519 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2521 SelectObject( hdc, hbm_old );
\r
2523 if( hPieceFace[index] != NULL ) {
\r
2524 DeleteObject( hPieceFace[index] );
\r
2527 hPieceFace[index] = hbm;
\r
2530 static int TranslatePieceToFontPiece( int piece )
\r
2558 case BlackCardinal:
\r
2560 case BlackMarshall:
\r
2564 case BlackNightrider:
\r
2570 case BlackUnicorn:
\r
2574 case BlackGrasshopper:
\r
2578 case WhiteCardinal:
\r
2580 case WhiteMarshall:
\r
2584 case WhiteNightrider:
\r
2590 case WhiteUnicorn:
\r
2594 case WhiteGrasshopper:
\r
2604 void CreatePiecesFromFont()
\r
2607 HDC hdc_window = NULL;
\r
2613 if( fontBitmapSquareSize < 0 ) {
\r
2614 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2618 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2619 fontBitmapSquareSize = -1;
\r
2623 if( fontBitmapSquareSize != squareSize ) {
\r
2624 hdc_window = GetDC( hwndMain );
\r
2625 hdc = CreateCompatibleDC( hdc_window );
\r
2627 if( hPieceFont != NULL ) {
\r
2628 DeleteObject( hPieceFont );
\r
2631 for( i=0; i<12; i++ ) {
\r
2632 hPieceMask[i] = NULL;
\r
2633 hPieceFace[i] = NULL;
\r
2639 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2640 fontHeight = appData.fontPieceSize;
\r
2643 fontHeight = (fontHeight * squareSize) / 100;
\r
2645 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2647 lf.lfEscapement = 0;
\r
2648 lf.lfOrientation = 0;
\r
2649 lf.lfWeight = FW_NORMAL;
\r
2651 lf.lfUnderline = 0;
\r
2652 lf.lfStrikeOut = 0;
\r
2653 lf.lfCharSet = DEFAULT_CHARSET;
\r
2654 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2655 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2656 lf.lfQuality = PROOF_QUALITY;
\r
2657 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2658 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2659 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2661 hPieceFont = CreateFontIndirect( &lf );
\r
2663 if( hPieceFont == NULL ) {
\r
2664 fontBitmapSquareSize = -2;
\r
2667 /* Setup font-to-piece character table */
\r
2668 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2669 /* No (or wrong) global settings, try to detect the font */
\r
2670 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2672 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2674 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2675 /* DiagramTT* family */
\r
2676 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2678 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2679 /* Fairy symbols */
\r
2680 SetCharTable(pieceToFontChar, "PNBRQFWEMOUHACGSKpnbrqfwemouhacgsk");
\r
2682 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2683 /* Good Companion (Some characters get warped as literal :-( */
\r
2684 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2685 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2686 SetCharTable(pieceToFontChar, s);
\r
2689 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2690 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2694 /* Create bitmaps */
\r
2695 hfont_old = SelectObject( hdc, hPieceFont );
\r
2697 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2698 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2699 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2700 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2701 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2702 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2703 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2704 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2705 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2706 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2707 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2708 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2710 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2711 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2712 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2713 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2714 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2715 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2716 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2717 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2718 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2719 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2720 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2721 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2722 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2723 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2724 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2725 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2726 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2727 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2728 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2729 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2732 SelectObject( hdc, hfont_old );
\r
2734 fontBitmapSquareSize = squareSize;
\r
2738 if( hdc != NULL ) {
\r
2742 if( hdc_window != NULL ) {
\r
2743 ReleaseDC( hwndMain, hdc_window );
\r
2748 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2752 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2753 if (gameInfo.event &&
\r
2754 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2755 strcmp(name, "k80s") == 0) {
\r
2756 strcpy(name, "tim");
\r
2758 return LoadBitmap(hinst, name);
\r
2762 /* Insert a color into the program's logical palette
\r
2763 structure. This code assumes the given color is
\r
2764 the result of the RGB or PALETTERGB macro, and it
\r
2765 knows how those macros work (which is documented).
\r
2768 InsertInPalette(COLORREF color)
\r
2770 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2772 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2773 DisplayFatalError("Too many colors", 0, 1);
\r
2774 pLogPal->palNumEntries--;
\r
2778 pe->peFlags = (char) 0;
\r
2779 pe->peRed = (char) (0xFF & color);
\r
2780 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2781 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2787 InitDrawingColors()
\r
2789 if (pLogPal == NULL) {
\r
2790 /* Allocate enough memory for a logical palette with
\r
2791 * PALETTESIZE entries and set the size and version fields
\r
2792 * of the logical palette structure.
\r
2794 pLogPal = (NPLOGPALETTE)
\r
2795 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2796 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2797 pLogPal->palVersion = 0x300;
\r
2799 pLogPal->palNumEntries = 0;
\r
2801 InsertInPalette(lightSquareColor);
\r
2802 InsertInPalette(darkSquareColor);
\r
2803 InsertInPalette(whitePieceColor);
\r
2804 InsertInPalette(blackPieceColor);
\r
2805 InsertInPalette(highlightSquareColor);
\r
2806 InsertInPalette(premoveHighlightColor);
\r
2808 /* create a logical color palette according the information
\r
2809 * in the LOGPALETTE structure.
\r
2811 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2813 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2814 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2815 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2816 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2817 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2818 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2820 /* [AS] Force rendering of the font-based pieces */
\r
2821 if( fontBitmapSquareSize > 0 ) {
\r
2822 fontBitmapSquareSize = 0;
\r
2828 BoardWidth(int boardSize, int n)
\r
2829 { /* [HGM] argument n added to allow different width and height */
\r
2830 int lineGap = sizeInfo[boardSize].lineGap;
\r
2832 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2833 lineGap = appData.overrideLineGap;
\r
2836 return (n + 1) * lineGap +
\r
2837 n * sizeInfo[boardSize].squareSize;
\r
2840 /* Respond to board resize by dragging edge */
\r
2842 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2844 BoardSize newSize = NUM_SIZES - 1;
\r
2845 static int recurse = 0;
\r
2846 if (IsIconic(hwndMain)) return;
\r
2847 if (recurse > 0) return;
\r
2849 while (newSize > 0 &&
\r
2850 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2851 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2854 boardSize = newSize;
\r
2855 InitDrawingSizes(boardSize, flags);
\r
2862 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2864 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2865 ChessSquare piece;
\r
2866 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2868 SIZE clockSize, messageSize;
\r
2870 char buf[MSG_SIZ];
\r
2872 HMENU hmenu = GetMenu(hwndMain);
\r
2873 RECT crect, wrect;
\r
2875 LOGBRUSH logbrush;
\r
2877 /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */
\r
2878 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2880 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2881 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2882 squareSize = sizeInfo[boardSize].squareSize;
\r
2883 lineGap = sizeInfo[boardSize].lineGap;
\r
2884 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2886 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2887 lineGap = appData.overrideLineGap;
\r
2890 if (tinyLayout != oldTinyLayout) {
\r
2891 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2893 style &= ~WS_SYSMENU;
\r
2894 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2895 "&Minimize\tCtrl+F4");
\r
2897 style |= WS_SYSMENU;
\r
2898 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2900 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2902 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2903 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2904 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2906 DrawMenuBar(hwndMain);
\r
2909 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
2910 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
2912 /* Get text area sizes */
\r
2913 hdc = GetDC(hwndMain);
\r
2914 if (appData.clockMode) {
\r
2915 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2917 sprintf(buf, "White");
\r
2919 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2920 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2921 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2922 str = "We only care about the height here";
\r
2923 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2924 SelectObject(hdc, oldFont);
\r
2925 ReleaseDC(hwndMain, hdc);
\r
2927 /* Compute where everything goes */
\r
2928 whiteRect.left = OUTER_MARGIN;
\r
2929 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2930 whiteRect.top = OUTER_MARGIN;
\r
2931 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2933 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2934 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2935 blackRect.top = whiteRect.top;
\r
2936 blackRect.bottom = whiteRect.bottom;
\r
2938 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2939 if (appData.showButtonBar) {
\r
2940 messageRect.right = blackRect.right
\r
2941 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2943 messageRect.right = blackRect.right;
\r
2945 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2946 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2948 boardRect.left = whiteRect.left;
\r
2949 boardRect.right = boardRect.left + boardWidth;
\r
2950 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2951 boardRect.bottom = boardRect.top + boardHeight;
\r
2953 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2954 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2955 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2956 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2957 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2958 GetWindowRect(hwndMain, &wrect);
\r
2959 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2960 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2961 /* compensate if menu bar wrapped */
\r
2962 GetClientRect(hwndMain, &crect);
\r
2963 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2964 winHeight += offby;
\r
2966 case WMSZ_TOPLEFT:
\r
2967 SetWindowPos(hwndMain, NULL,
\r
2968 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2969 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2972 case WMSZ_TOPRIGHT:
\r
2974 SetWindowPos(hwndMain, NULL,
\r
2975 wrect.left, wrect.bottom - winHeight,
\r
2976 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2979 case WMSZ_BOTTOMLEFT:
\r
2981 SetWindowPos(hwndMain, NULL,
\r
2982 wrect.right - winWidth, wrect.top,
\r
2983 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2986 case WMSZ_BOTTOMRIGHT:
\r
2990 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2991 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2996 for (i = 0; i < N_BUTTONS; i++) {
\r
2997 if (buttonDesc[i].hwnd != NULL) {
\r
2998 DestroyWindow(buttonDesc[i].hwnd);
\r
2999 buttonDesc[i].hwnd = NULL;
\r
3001 if (appData.showButtonBar) {
\r
3002 buttonDesc[i].hwnd =
\r
3003 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3004 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3005 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3006 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3007 (HMENU) buttonDesc[i].id,
\r
3008 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3010 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3011 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3012 MAKELPARAM(FALSE, 0));
\r
3014 if (buttonDesc[i].id == IDM_Pause)
\r
3015 hwndPause = buttonDesc[i].hwnd;
\r
3016 buttonDesc[i].wndproc = (WNDPROC)
\r
3017 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3020 if (gridPen != NULL) DeleteObject(gridPen);
\r
3021 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3022 if (premovePen != NULL) DeleteObject(premovePen);
\r
3023 if (lineGap != 0) {
\r
3024 logbrush.lbStyle = BS_SOLID;
\r
3025 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3027 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3028 lineGap, &logbrush, 0, NULL);
\r
3029 logbrush.lbColor = highlightSquareColor;
\r
3031 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3032 lineGap, &logbrush, 0, NULL);
\r
3034 logbrush.lbColor = premoveHighlightColor;
\r
3036 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3037 lineGap, &logbrush, 0, NULL);
\r
3039 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3040 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3041 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3042 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3043 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3044 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3045 BOARD_WIDTH * (squareSize + lineGap);
\r
3046 lineGap / 2 + (i * (squareSize + lineGap));
\r
3047 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3049 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3050 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3051 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3052 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3053 lineGap / 2 + (i * (squareSize + lineGap));
\r
3054 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3055 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3056 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3061 /* [HGM] Gothic licensing requirement */
\r
3062 GothicPopUp( GOTHIC, gameInfo.variant == VariantGothic );
\r
3065 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3066 oldBoardSize = boardSize;
\r
3067 oldTinyLayout = tinyLayout;
\r
3069 /* Load piece bitmaps for this board size */
\r
3070 for (i=0; i<=2; i++) {
\r
3071 for (piece = WhitePawn;
\r
3072 (int) piece < (int) BlackPawn;
\r
3073 piece = (ChessSquare) ((int) piece + 1)) {
\r
3074 if (pieceBitmap[i][piece] != NULL)
\r
3075 DeleteObject(pieceBitmap[i][piece]);
\r
3079 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3080 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3081 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3082 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3083 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3084 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3085 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3086 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3087 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3088 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3089 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3090 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3091 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3092 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3093 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3094 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3095 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3096 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3097 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3099 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3100 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3101 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3103 if(squareSize==72 || squareSize==49) { /* experiment with some home-made bitmaps */
\r
3104 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3105 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3106 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3107 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3108 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3109 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3110 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3111 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3112 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3113 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3114 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3115 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3116 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3117 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3118 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3119 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3120 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3121 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3122 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3123 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3124 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3125 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3126 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3127 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3128 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3129 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3130 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3131 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3132 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3133 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3134 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3136 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3137 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3138 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3139 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3140 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3141 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3142 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3143 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3144 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3145 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3146 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3147 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3149 if(gameInfo.variant != VariantCrazyhouse && gameInfo.variant != VariantShogi) {
\r
3150 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3151 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3152 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3154 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3155 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3156 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3158 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3159 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3160 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3161 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3162 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3163 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3164 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3165 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3166 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3167 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3168 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3169 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3170 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3171 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3172 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3177 PieceBitmap(ChessSquare p, int kind)
\r
3179 if ((int) p >= (int) BlackPawn)
\r
3180 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3182 return pieceBitmap[kind][(int) p];
\r
3185 /***************************************************************/
\r
3187 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3188 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3190 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3191 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3195 SquareToPos(int row, int column, int * x, int * y)
\r
3198 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3199 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3201 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3202 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3207 DrawCoordsOnDC(HDC hdc)
\r
3209 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
3210 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
3211 char str[2] = { NULLCHAR, NULLCHAR };
\r
3212 int oldMode, oldAlign, x, y, start, i;
\r
3216 if (!appData.showCoords)
\r
3219 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3221 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3222 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3223 oldAlign = GetTextAlign(hdc);
\r
3224 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3226 y = boardRect.top + lineGap;
\r
3227 x = boardRect.left + lineGap;
\r
3229 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3230 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3231 str[0] = files[start + i];
\r
3232 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3233 y += squareSize + lineGap;
\r
3236 start = flipView ? 12-BOARD_WIDTH : 12;
\r
3238 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3239 for (i = 0; i < BOARD_WIDTH; i++) {
\r
3240 str[0] = ranks[start + i];
\r
3241 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3242 x += squareSize + lineGap;
\r
3245 SelectObject(hdc, oldBrush);
\r
3246 SetBkMode(hdc, oldMode);
\r
3247 SetTextAlign(hdc, oldAlign);
\r
3248 SelectObject(hdc, oldFont);
\r
3252 DrawGridOnDC(HDC hdc)
\r
3256 if (lineGap != 0) {
\r
3257 oldPen = SelectObject(hdc, gridPen);
\r
3258 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3259 SelectObject(hdc, oldPen);
\r
3263 #define HIGHLIGHT_PEN 0
\r
3264 #define PREMOVE_PEN 1
\r
3267 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3270 HPEN oldPen, hPen;
\r
3271 if (lineGap == 0) return;
\r
3273 x1 = boardRect.left +
\r
3274 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3275 y1 = boardRect.top +
\r
3276 lineGap/2 + y * (squareSize + lineGap);
\r
3278 x1 = boardRect.left +
\r
3279 lineGap/2 + x * (squareSize + lineGap);
\r
3280 y1 = boardRect.top +
\r
3281 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3283 hPen = pen ? premovePen : highlightPen;
\r
3284 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3285 MoveToEx(hdc, x1, y1, NULL);
\r
3286 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3287 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3288 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3289 LineTo(hdc, x1, y1);
\r
3290 SelectObject(hdc, oldPen);
\r
3294 DrawHighlightsOnDC(HDC hdc)
\r
3297 for (i=0; i<2; i++) {
\r
3298 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3299 DrawHighlightOnDC(hdc, TRUE,
\r
3300 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3303 for (i=0; i<2; i++) {
\r
3304 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3305 premoveHighlightInfo.sq[i].y >= 0) {
\r
3306 DrawHighlightOnDC(hdc, TRUE,
\r
3307 premoveHighlightInfo.sq[i].x,
\r
3308 premoveHighlightInfo.sq[i].y,
\r
3314 /* Note: sqcolor is used only in monoMode */
\r
3315 /* Note that this code is largely duplicated in woptions.c,
\r
3316 function DrawSampleSquare, so that needs to be updated too */
\r
3318 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3320 HBITMAP oldBitmap;
\r
3323 if (appData.blindfold) return;
\r
3325 /* [AS] Use font-based pieces if needed */
\r
3326 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3327 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3328 CreatePiecesFromFont();
\r
3330 if( fontBitmapSquareSize == squareSize ) {
\r
3331 int index = TranslatePieceToFontPiece( piece );
\r
3333 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3337 squareSize, squareSize,
\r
3342 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3346 squareSize, squareSize,
\r
3355 if (appData.monoMode) {
\r
3356 SelectObject(tmphdc, PieceBitmap(piece,
\r
3357 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3358 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3359 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3362 (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||
\r
3363 piece >= (int)BlackNightrider && piece <= BlackGrasshopper) ) {
\r
3364 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3365 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3366 x += (squareSize - minorSize)>>1;
\r
3367 y += squareSize - minorSize - 2;
\r
3369 if (color || appData.allWhite ) {
\r
3370 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3372 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3373 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3374 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3376 /* Use black piece color for outline of white pieces */
\r
3377 /* Not sure this looks really good (though xboard does it).
\r
3378 Maybe better to have another selectable color, default black */
\r
3379 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3380 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3381 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3383 /* Use black for outline of white pieces */
\r
3384 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3385 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
3389 /* Use white piece color for details of black pieces */
\r
3390 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3391 WHITE_PIECE ones aren't always the right shape. */
\r
3392 /* Not sure this looks really good (though xboard does it).
\r
3393 Maybe better to have another selectable color, default medium gray? */
\r
3394 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3395 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3396 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3397 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3398 SelectObject(hdc, blackPieceBrush);
\r
3399 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3401 /* Use square color for details of black pieces */
\r
3402 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3403 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3404 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3407 SelectObject(hdc, oldBrush);
\r
3408 SelectObject(tmphdc, oldBitmap);
\r
3412 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3413 int GetBackTextureMode( int algo )
\r
3415 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3419 case BACK_TEXTURE_MODE_PLAIN:
\r
3420 result = 1; /* Always use identity map */
\r
3422 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3423 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3431 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3432 to handle redraws cleanly (as random numbers would always be different).
\r
3434 VOID RebuildTextureSquareInfo()
\r
3444 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3446 if( liteBackTexture != NULL ) {
\r
3447 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3448 lite_w = bi.bmWidth;
\r
3449 lite_h = bi.bmHeight;
\r
3453 if( darkBackTexture != NULL ) {
\r
3454 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3455 dark_w = bi.bmWidth;
\r
3456 dark_h = bi.bmHeight;
\r
3460 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3461 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3462 if( (col + row) & 1 ) {
\r
3464 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3465 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_WIDTH;
\r
3466 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_HEIGHT;
\r
3467 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3472 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3473 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_WIDTH;
\r
3474 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_HEIGHT;
\r
3475 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3482 /* [AS] Arrow highlighting support */
\r
3484 static int A_WIDTH = 5; /* Width of arrow body */
\r
3486 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3487 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3489 static double Sqr( double x )
\r
3494 static int Round( double x )
\r
3496 return (int) (x + 0.5);
\r
3499 /* Draw an arrow between two points using current settings */
\r
3500 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3503 double dx, dy, j, k, x, y;
\r
3505 if( d_x == s_x ) {
\r
3506 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3508 arrow[0].x = s_x + A_WIDTH;
\r
3511 arrow[1].x = s_x + A_WIDTH;
\r
3512 arrow[1].y = d_y - h;
\r
3514 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3515 arrow[2].y = d_y - h;
\r
3520 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3521 arrow[4].y = d_y - h;
\r
3523 arrow[5].x = s_x - A_WIDTH;
\r
3524 arrow[5].y = d_y - h;
\r
3526 arrow[6].x = s_x - A_WIDTH;
\r
3529 else if( d_y == s_y ) {
\r
3530 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3533 arrow[0].y = s_y + A_WIDTH;
\r
3535 arrow[1].x = d_x - w;
\r
3536 arrow[1].y = s_y + A_WIDTH;
\r
3538 arrow[2].x = d_x - w;
\r
3539 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3544 arrow[4].x = d_x - w;
\r
3545 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3547 arrow[5].x = d_x - w;
\r
3548 arrow[5].y = s_y - A_WIDTH;
\r
3551 arrow[6].y = s_y - A_WIDTH;
\r
3554 /* [AS] Needed a lot of paper for this! :-) */
\r
3555 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3556 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3558 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3560 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3565 arrow[0].x = Round(x - j);
\r
3566 arrow[0].y = Round(y + j*dx);
\r
3568 arrow[1].x = Round(x + j);
\r
3569 arrow[1].y = Round(y - j*dx);
\r
3572 x = (double) d_x - k;
\r
3573 y = (double) d_y - k*dy;
\r
3576 x = (double) d_x + k;
\r
3577 y = (double) d_y + k*dy;
\r
3580 arrow[2].x = Round(x + j);
\r
3581 arrow[2].y = Round(y - j*dx);
\r
3583 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3584 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3589 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3590 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3592 arrow[6].x = Round(x - j);
\r
3593 arrow[6].y = Round(y + j*dx);
\r
3596 Polygon( hdc, arrow, 7 );
\r
3599 /* [AS] Draw an arrow between two squares */
\r
3600 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3602 int s_x, s_y, d_x, d_y;
\r
3609 if( s_col == d_col && s_row == d_row ) {
\r
3613 /* Get source and destination points */
\r
3614 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3615 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3618 d_y += squareSize / 4;
\r
3620 else if( d_y < s_y ) {
\r
3621 d_y += 3 * squareSize / 4;
\r
3624 d_y += squareSize / 2;
\r
3628 d_x += squareSize / 4;
\r
3630 else if( d_x < s_x ) {
\r
3631 d_x += 3 * squareSize / 4;
\r
3634 d_x += squareSize / 2;
\r
3637 s_x += squareSize / 2;
\r
3638 s_y += squareSize / 2;
\r
3640 /* Adjust width */
\r
3641 A_WIDTH = squareSize / 14;
\r
3644 stLB.lbStyle = BS_SOLID;
\r
3645 stLB.lbColor = appData.highlightArrowColor;
\r
3648 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3649 holdpen = SelectObject( hdc, hpen );
\r
3650 hbrush = CreateBrushIndirect( &stLB );
\r
3651 holdbrush = SelectObject( hdc, hbrush );
\r
3653 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3655 SelectObject( hdc, holdpen );
\r
3656 SelectObject( hdc, holdbrush );
\r
3657 DeleteObject( hpen );
\r
3658 DeleteObject( hbrush );
\r
3661 BOOL HasHighlightInfo()
\r
3663 BOOL result = FALSE;
\r
3665 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3666 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3674 BOOL IsDrawArrowEnabled()
\r
3676 BOOL result = FALSE;
\r
3678 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3685 VOID DrawArrowHighlight( HDC hdc )
\r
3687 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3688 DrawArrowBetweenSquares( hdc,
\r
3689 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3690 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3694 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3696 HRGN result = NULL;
\r
3698 if( HasHighlightInfo() ) {
\r
3699 int x1, y1, x2, y2;
\r
3700 int sx, sy, dx, dy;
\r
3702 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3703 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3705 sx = MIN( x1, x2 );
\r
3706 sy = MIN( y1, y2 );
\r
3707 dx = MAX( x1, x2 ) + squareSize;
\r
3708 dy = MAX( y1, y2 ) + squareSize;
\r
3710 result = CreateRectRgn( sx, sy, dx, dy );
\r
3717 Warning: this function modifies the behavior of several other functions.
\r
3719 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3720 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3721 repaint is scattered all over the place, which is not good for features such as
\r
3722 "arrow highlighting" that require a full repaint of the board.
\r
3724 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3725 user interaction, when speed is not so important) but especially to avoid errors
\r
3726 in the displayed graphics.
\r
3728 In such patched places, I always try refer to this function so there is a single
\r
3729 place to maintain knowledge.
\r
3731 To restore the original behavior, just return FALSE unconditionally.
\r
3733 BOOL IsFullRepaintPreferrable()
\r
3735 BOOL result = FALSE;
\r
3737 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3738 /* Arrow may appear on the board */
\r
3746 This function is called by DrawPosition to know whether a full repaint must
\r
3749 Only DrawPosition may directly call this function, which makes use of
\r
3750 some state information. Other function should call DrawPosition specifying
\r
3751 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3753 BOOL DrawPositionNeedsFullRepaint()
\r
3755 BOOL result = FALSE;
\r
3758 Probably a slightly better policy would be to trigger a full repaint
\r
3759 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3760 but animation is fast enough that it's difficult to notice.
\r
3762 if( animInfo.piece == EmptySquare ) {
\r
3763 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3772 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3774 int row, column, x, y, square_color, piece_color;
\r
3775 ChessSquare piece;
\r
3777 HDC texture_hdc = NULL;
\r
3779 /* [AS] Initialize background textures if needed */
\r
3780 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3781 if( backTextureSquareSize != squareSize ) {
\r
3782 backTextureSquareSize = squareSize;
\r
3783 RebuildTextureSquareInfo();
\r
3786 texture_hdc = CreateCompatibleDC( hdc );
\r
3789 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3790 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3792 SquareToPos(row, column, &x, &y);
\r
3794 piece = board[row][column];
\r
3796 square_color = ((column + row) % 2) == 1;
\r
3797 if(!strcmp(appData.variant, "xiangqi") ) {
\r
3798 square_color = !InPalace(row, column);
\r
3799 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3800 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3802 piece_color = (int) piece < (int) BlackPawn;
\r
3806 /* [HGM] holdings file: light square or black */
\r
3807 if(column == BOARD_LEFT-2) {
\r
3808 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3811 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3815 if(column == BOARD_RGHT + 1 ) {
\r
3816 if( row < gameInfo.holdingsSize )
\r
3819 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3823 if(column == BOARD_LEFT-1 ) /* left align */
\r
3824 DisplayHoldingsCount(hdc, x, y, 0, (int) board[row][column]);
\r
3825 else if( column == BOARD_RGHT) /* right align */
\r
3826 DisplayHoldingsCount(hdc, x, y, 1, (int) board[row][column]);
\r
3829 if (appData.monoMode) {
\r
3830 if (piece == EmptySquare) {
\r
3831 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3832 square_color ? WHITENESS : BLACKNESS);
\r
3834 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3837 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
3838 /* [AS] Draw the square using a texture bitmap */
\r
3839 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3842 squareSize, squareSize,
\r
3845 backTextureSquareInfo[row][column].mode,
\r
3846 backTextureSquareInfo[row][column].x,
\r
3847 backTextureSquareInfo[row][column].y );
\r
3849 SelectObject( texture_hdc, hbm );
\r
3851 if (piece != EmptySquare) {
\r
3852 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3856 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3858 oldBrush = SelectObject(hdc, brush );
\r
3859 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3860 SelectObject(hdc, oldBrush);
\r
3861 if (piece != EmptySquare)
\r
3862 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3867 if( texture_hdc != NULL ) {
\r
3868 DeleteDC( texture_hdc );
\r
3872 #define MAX_CLIPS 200 /* more than enough */
\r
3875 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3877 static Board lastReq, lastDrawn;
\r
3878 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3879 static int lastDrawnFlipView = 0;
\r
3880 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3881 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3884 HBITMAP bufferBitmap;
\r
3885 HBITMAP oldBitmap;
\r
3887 HRGN clips[MAX_CLIPS];
\r
3888 ChessSquare dragged_piece = EmptySquare;
\r
3890 /* I'm undecided on this - this function figures out whether a full
\r
3891 * repaint is necessary on its own, so there's no real reason to have the
\r
3892 * caller tell it that. I think this can safely be set to FALSE - but
\r
3893 * if we trust the callers not to request full repaints unnessesarily, then
\r
3894 * we could skip some clipping work. In other words, only request a full
\r
3895 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3896 * gamestart and similar) --Hawk
\r
3898 Boolean fullrepaint = repaint;
\r
3900 if( DrawPositionNeedsFullRepaint() ) {
\r
3901 fullrepaint = TRUE;
\r
3905 if( fullrepaint ) {
\r
3906 static int repaint_count = 0;
\r
3910 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
3911 OutputDebugString( buf );
\r
3915 if (board == NULL) {
\r
3916 if (!lastReqValid) {
\r
3921 CopyBoard(lastReq, board);
\r
3925 if (doingSizing) {
\r
3929 if (IsIconic(hwndMain)) {
\r
3933 if (hdc == NULL) {
\r
3934 hdc = GetDC(hwndMain);
\r
3935 if (!appData.monoMode) {
\r
3936 SelectPalette(hdc, hPal, FALSE);
\r
3937 RealizePalette(hdc);
\r
3941 releaseDC = FALSE;
\r
3945 fprintf(debugFP, "*******************************\n"
\r
3947 "dragInfo.from (%d,%d)\n"
\r
3948 "dragInfo.start (%d,%d)\n"
\r
3949 "dragInfo.pos (%d,%d)\n"
\r
3950 "dragInfo.lastpos (%d,%d)\n",
\r
3951 repaint ? "TRUE" : "FALSE",
\r
3952 dragInfo.from.x, dragInfo.from.y,
\r
3953 dragInfo.start.x, dragInfo.start.y,
\r
3954 dragInfo.pos.x, dragInfo.pos.y,
\r
3955 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
3956 fprintf(debugFP, "prev: ");
\r
3957 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3958 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3959 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
3962 fprintf(debugFP, "\n");
\r
3963 fprintf(debugFP, "board: ");
\r
3964 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3965 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3966 fprintf(debugFP, "%d ", board[row][column]);
\r
3969 fprintf(debugFP, "\n");
\r
3973 /* Create some work-DCs */
\r
3974 hdcmem = CreateCompatibleDC(hdc);
\r
3975 tmphdc = CreateCompatibleDC(hdc);
\r
3977 /* If dragging is in progress, we temporarely remove the piece */
\r
3978 /* [HGM] or temporarily decrease count if stacked */
\r
3979 /* !! Moved to before board compare !! */
\r
3980 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3981 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3982 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3983 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3984 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3986 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3987 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3988 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3990 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3993 /* Figure out which squares need updating by comparing the
\r
3994 * newest board with the last drawn board and checking if
\r
3995 * flipping has changed.
\r
3997 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3998 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3999 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4000 if (lastDrawn[row][column] != board[row][column]) {
\r
4001 SquareToPos(row, column, &x, &y);
\r
4002 clips[num_clips++] =
\r
4003 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4007 for (i=0; i<2; i++) {
\r
4008 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4009 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4010 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4011 lastDrawnHighlight.sq[i].y >= 0) {
\r
4012 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4013 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4014 clips[num_clips++] =
\r
4015 CreateRectRgn(x - lineGap, y - lineGap,
\r
4016 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4018 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4019 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4020 clips[num_clips++] =
\r
4021 CreateRectRgn(x - lineGap, y - lineGap,
\r
4022 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4026 for (i=0; i<2; i++) {
\r
4027 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4028 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4029 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4030 lastDrawnPremove.sq[i].y >= 0) {
\r
4031 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4032 lastDrawnPremove.sq[i].x, &x, &y);
\r
4033 clips[num_clips++] =
\r
4034 CreateRectRgn(x - lineGap, y - lineGap,
\r
4035 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4037 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4038 premoveHighlightInfo.sq[i].y >= 0) {
\r
4039 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4040 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4041 clips[num_clips++] =
\r
4042 CreateRectRgn(x - lineGap, y - lineGap,
\r
4043 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4048 fullrepaint = TRUE;
\r
4051 /* Create a buffer bitmap - this is the actual bitmap
\r
4052 * being written to. When all the work is done, we can
\r
4053 * copy it to the real DC (the screen). This avoids
\r
4054 * the problems with flickering.
\r
4056 GetClientRect(hwndMain, &Rect);
\r
4057 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4058 Rect.bottom-Rect.top+1);
\r
4059 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4060 if (!appData.monoMode) {
\r
4061 SelectPalette(hdcmem, hPal, FALSE);
\r
4064 /* Create clips for dragging */
\r
4065 if (!fullrepaint) {
\r
4066 if (dragInfo.from.x >= 0) {
\r
4067 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4068 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4070 if (dragInfo.start.x >= 0) {
\r
4071 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4072 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4074 if (dragInfo.pos.x >= 0) {
\r
4075 x = dragInfo.pos.x - squareSize / 2;
\r
4076 y = dragInfo.pos.y - squareSize / 2;
\r
4077 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4079 if (dragInfo.lastpos.x >= 0) {
\r
4080 x = dragInfo.lastpos.x - squareSize / 2;
\r
4081 y = dragInfo.lastpos.y - squareSize / 2;
\r
4082 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4086 /* Are we animating a move?
\r
4088 * - remove the piece from the board (temporarely)
\r
4089 * - calculate the clipping region
\r
4091 if (!fullrepaint) {
\r
4092 if (animInfo.piece != EmptySquare) {
\r
4093 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4094 x = boardRect.left + animInfo.lastpos.x;
\r
4095 y = boardRect.top + animInfo.lastpos.y;
\r
4096 x2 = boardRect.left + animInfo.pos.x;
\r
4097 y2 = boardRect.top + animInfo.pos.y;
\r
4098 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4099 /* Slight kludge. The real problem is that after AnimateMove is
\r
4100 done, the position on the screen does not match lastDrawn.
\r
4101 This currently causes trouble only on e.p. captures in
\r
4102 atomic, where the piece moves to an empty square and then
\r
4103 explodes. The old and new positions both had an empty square
\r
4104 at the destination, but animation has drawn a piece there and
\r
4105 we have to remember to erase it. */
\r
4106 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4110 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4111 if (num_clips == 0)
\r
4112 fullrepaint = TRUE;
\r
4114 /* Set clipping on the memory DC */
\r
4115 if (!fullrepaint) {
\r
4116 SelectClipRgn(hdcmem, clips[0]);
\r
4117 for (x = 1; x < num_clips; x++) {
\r
4118 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4119 abort(); // this should never ever happen!
\r
4123 /* Do all the drawing to the memory DC */
\r
4124 DrawGridOnDC(hdcmem);
\r
4125 DrawHighlightsOnDC(hdcmem);
\r
4126 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4128 if( appData.highlightMoveWithArrow ) {
\r
4129 DrawArrowHighlight(hdcmem);
\r
4132 DrawCoordsOnDC(hdcmem);
\r
4134 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4135 /* to make sure lastDrawn contains what is actually drawn */
\r
4137 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4138 if (dragged_piece != EmptySquare) {
\r
4139 /* [HGM] or restack */
\r
4140 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4141 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4143 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4144 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4145 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4146 x = dragInfo.pos.x - squareSize / 2;
\r
4147 y = dragInfo.pos.y - squareSize / 2;
\r
4148 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4149 ((int) dragged_piece < (int) BlackPawn),
\r
4150 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4153 /* Put the animated piece back into place and draw it */
\r
4154 if (animInfo.piece != EmptySquare) {
\r
4155 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4156 x = boardRect.left + animInfo.pos.x;
\r
4157 y = boardRect.top + animInfo.pos.y;
\r
4158 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4159 ((int) animInfo.piece < (int) BlackPawn),
\r
4160 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4163 /* Release the bufferBitmap by selecting in the old bitmap
\r
4164 * and delete the memory DC
\r
4166 SelectObject(hdcmem, oldBitmap);
\r
4169 /* Set clipping on the target DC */
\r
4170 if (!fullrepaint) {
\r
4171 SelectClipRgn(hdc, clips[0]);
\r
4172 for (x = 1; x < num_clips; x++) {
\r
4173 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4174 abort(); // this should never ever happen!
\r
4178 /* Copy the new bitmap onto the screen in one go.
\r
4179 * This way we avoid any flickering
\r
4181 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4182 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4183 boardRect.right - boardRect.left,
\r
4184 boardRect.bottom - boardRect.top,
\r
4185 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4186 SelectObject(tmphdc, oldBitmap);
\r
4188 /* Massive cleanup */
\r
4189 for (x = 0; x < num_clips; x++)
\r
4190 DeleteObject(clips[x]);
\r
4193 DeleteObject(bufferBitmap);
\r
4196 ReleaseDC(hwndMain, hdc);
\r
4198 if (lastDrawnFlipView != flipView) {
\r
4200 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4202 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4205 /* CopyBoard(lastDrawn, board);*/
\r
4206 lastDrawnHighlight = highlightInfo;
\r
4207 lastDrawnPremove = premoveHighlightInfo;
\r
4208 lastDrawnFlipView = flipView;
\r
4209 lastDrawnValid = 1;
\r
4213 /*---------------------------------------------------------------------------*\
\r
4214 | CLIENT PAINT PROCEDURE
\r
4215 | This is the main event-handler for the WM_PAINT message.
\r
4217 \*---------------------------------------------------------------------------*/
\r
4219 PaintProc(HWND hwnd)
\r
4225 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4226 if (IsIconic(hwnd)) {
\r
4227 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4229 if (!appData.monoMode) {
\r
4230 SelectPalette(hdc, hPal, FALSE);
\r
4231 RealizePalette(hdc);
\r
4233 HDCDrawPosition(hdc, 1, NULL);
\r
4235 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4236 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4237 ETO_CLIPPED|ETO_OPAQUE,
\r
4238 &messageRect, messageText, strlen(messageText), NULL);
\r
4239 SelectObject(hdc, oldFont);
\r
4240 DisplayBothClocks();
\r
4242 EndPaint(hwnd,&ps);
\r
4250 * If the user selects on a border boundary, return -1; if off the board,
\r
4251 * return -2. Otherwise map the event coordinate to the square.
\r
4252 * The offset boardRect.left or boardRect.top must already have been
\r
4253 * subtracted from x.
\r
4256 EventToSquare(int x)
\r
4263 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4265 x /= (squareSize + lineGap);
\r
4266 if (x >= BOARD_SIZE)
\r
4277 DropEnable dropEnables[] = {
\r
4278 { 'P', DP_Pawn, "Pawn" },
\r
4279 { 'N', DP_Knight, "Knight" },
\r
4280 { 'B', DP_Bishop, "Bishop" },
\r
4281 { 'R', DP_Rook, "Rook" },
\r
4282 { 'Q', DP_Queen, "Queen" },
\r
4286 SetupDropMenu(HMENU hmenu)
\r
4288 int i, count, enable;
\r
4290 extern char white_holding[], black_holding[];
\r
4291 char item[MSG_SIZ];
\r
4293 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4294 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4295 dropEnables[i].piece);
\r
4297 while (p && *p++ == dropEnables[i].piece) count++;
\r
4298 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4299 enable = count > 0 || !appData.testLegality
\r
4300 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4301 && !appData.icsActive);
\r
4302 ModifyMenu(hmenu, dropEnables[i].command,
\r
4303 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4304 dropEnables[i].command, item);
\r
4308 static int fromX = -1, fromY = -1, toX, toY;
\r
4310 /* Event handler for mouse messages */
\r
4312 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4316 static int recursive = 0;
\r
4318 BOOLEAN needsRedraw = FALSE;
\r
4319 BOOLEAN saveAnimate;
\r
4320 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4321 static BOOLEAN sameAgain = FALSE;
\r
4322 ChessMove moveType;
\r
4325 if (message == WM_MBUTTONUP) {
\r
4326 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4327 to the middle button: we simulate pressing the left button too!
\r
4329 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4330 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4336 pt.x = LOWORD(lParam);
\r
4337 pt.y = HIWORD(lParam);
\r
4338 x = EventToSquare(pt.x - boardRect.left);
\r
4339 y = EventToSquare(pt.y - boardRect.top);
\r
4340 if (!flipView && y >= 0) {
\r
4341 y = BOARD_HEIGHT - 1 - y;
\r
4343 if (flipView && x >= 0) {
\r
4344 x = BOARD_WIDTH - 1 - x;
\r
4347 switch (message) {
\r
4348 case WM_LBUTTONDOWN:
\r
4350 sameAgain = FALSE;
\r
4352 /* Downclick vertically off board; check if on clock */
\r
4353 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4354 if (gameMode == EditPosition) {
\r
4355 SetWhiteToPlayEvent();
\r
4356 } else if (gameMode == IcsPlayingBlack ||
\r
4357 gameMode == MachinePlaysWhite) {
\r
4359 } else if (gameMode == EditGame) {
\r
4360 AdjustClock(flipClock, -1);
\r
4362 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4363 if (gameMode == EditPosition) {
\r
4364 SetBlackToPlayEvent();
\r
4365 } else if (gameMode == IcsPlayingWhite ||
\r
4366 gameMode == MachinePlaysBlack) {
\r
4368 } else if (gameMode == EditGame) {
\r
4369 AdjustClock(!flipClock, -1);
\r
4372 if (!appData.highlightLastMove) {
\r
4373 ClearHighlights();
\r
4374 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4376 fromX = fromY = -1;
\r
4377 dragInfo.start.x = dragInfo.start.y = -1;
\r
4378 dragInfo.from = dragInfo.start;
\r
4380 } else if (x < 0 || y < 0
\r
4381 /* [HGM] block clicks between board and holdings */
\r
4382 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4383 || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
\r
4384 || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize
\r
4385 /* EditPosition, empty square, or different color piece;
\r
4386 click-click move is possible */
\r
4389 } else if (fromX == x && fromY == y) {
\r
4390 /* Downclick on same square again */
\r
4391 ClearHighlights();
\r
4392 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4393 sameAgain = TRUE;
\r
4394 } else if (fromX != -1 &&
\r
4395 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4397 /* Downclick on different square. */
\r
4398 /* [HGM] if on holdings file, should count as new first click ! */
\r
4399 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4402 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4403 to make sure move is legal before showing promotion popup */
\r
4404 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4405 if(moveType != ImpossibleMove) {
\r
4406 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4407 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4408 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4409 appData.alwaysPromoteToQueen) {
\r
4410 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4411 if (!appData.highlightLastMove) {
\r
4412 ClearHighlights();
\r
4413 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4416 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4417 SetHighlights(fromX, fromY, toX, toY);
\r
4418 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4419 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4420 If promotion to Q is legal, all are legal! */
\r
4421 PromotionPopup(hwnd);
\r
4422 } else { /* not a promotion */
\r
4423 if (appData.animate || appData.highlightLastMove) {
\r
4424 SetHighlights(fromX, fromY, toX, toY);
\r
4426 ClearHighlights();
\r
4428 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4429 if (appData.animate && !appData.highlightLastMove) {
\r
4430 ClearHighlights();
\r
4431 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4435 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4436 fromX = fromY = -1;
\r
4439 ClearHighlights();
\r
4440 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4442 /* First downclick, or restart on a square with same color piece */
\r
4443 if (!frozen && OKToStartUserMove(x, y)) {
\r
4446 dragInfo.lastpos = pt;
\r
4447 dragInfo.from.x = fromX;
\r
4448 dragInfo.from.y = fromY;
\r
4449 dragInfo.start = dragInfo.from;
\r
4450 SetCapture(hwndMain);
\r
4452 fromX = fromY = -1;
\r
4453 dragInfo.start.x = dragInfo.start.y = -1;
\r
4454 dragInfo.from = dragInfo.start;
\r
4455 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4459 case WM_LBUTTONUP:
\r
4461 if (fromX == -1) break;
\r
4462 if (x == fromX && y == fromY) {
\r
4463 /* Upclick on same square */
\r
4465 /* Clicked same square twice: abort click-click move */
\r
4466 fromX = fromY = -1;
\r
4468 ClearPremoveHighlights();
\r
4470 /* First square clicked: start click-click move */
\r
4471 SetHighlights(fromX, fromY, -1, -1);
\r
4473 dragInfo.from.x = dragInfo.from.y = -1;
\r
4474 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4475 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4476 /* Errant click; ignore */
\r
4479 /* Finish drag move. */
\r
4480 if (appData.debugMode) {
\r
4481 fprintf(debugFP, "release\n");
\r
4483 dragInfo.from.x = dragInfo.from.y = -1;
\r
4486 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4487 appData.animate = appData.animate && !appData.animateDragging;
\r
4488 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4489 if(moveType != ImpossibleMove) {
\r
4490 /* [HGM] use move type to determine if move is promotion.
\r
4491 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
4492 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4493 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4494 appData.alwaysPromoteToQueen)
\r
4495 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4497 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4498 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4499 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
4500 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4502 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4503 appData.animate = saveAnimate;
\r
4504 fromX = fromY = -1;
\r
4505 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
4506 ClearHighlights();
\r
4508 if (appData.animate || appData.animateDragging ||
\r
4509 appData.highlightDragging || gotPremove) {
\r
4510 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4513 dragInfo.start.x = dragInfo.start.y = -1;
\r
4514 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4517 case WM_MOUSEMOVE:
\r
4518 if ((appData.animateDragging || appData.highlightDragging)
\r
4519 && (wParam & MK_LBUTTON)
\r
4520 && dragInfo.from.x >= 0)
\r
4522 BOOL full_repaint = FALSE;
\r
4524 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
4525 if (appData.animateDragging) {
\r
4526 dragInfo.pos = pt;
\r
4528 if (appData.highlightDragging) {
\r
4529 SetHighlights(fromX, fromY, x, y);
\r
4530 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4531 full_repaint = TRUE;
\r
4535 DrawPosition( full_repaint, NULL);
\r
4537 dragInfo.lastpos = dragInfo.pos;
\r
4541 case WM_MBUTTONDOWN:
\r
4542 case WM_RBUTTONDOWN:
\r
4545 fromX = fromY = -1;
\r
4546 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4547 dragInfo.start.x = dragInfo.start.y = -1;
\r
4548 dragInfo.from = dragInfo.start;
\r
4549 dragInfo.lastpos = dragInfo.pos;
\r
4550 if (appData.highlightDragging) {
\r
4551 ClearHighlights();
\r
4554 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4555 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4556 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
4557 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4558 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
4561 DrawPosition(TRUE, NULL);
\r
4563 switch (gameMode) {
\r
4564 case EditPosition:
\r
4565 case IcsExamining:
\r
4566 if (x < 0 || y < 0) break;
\r
4569 if (message == WM_MBUTTONDOWN) {
\r
4570 buttonCount = 3; /* even if system didn't think so */
\r
4571 if (wParam & MK_SHIFT)
\r
4572 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4574 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4575 } else { /* message == WM_RBUTTONDOWN */
\r
4577 if (buttonCount == 3) {
\r
4578 if (wParam & MK_SHIFT)
\r
4579 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4581 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4583 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4586 /* Just have one menu, on the right button. Windows users don't
\r
4587 think to try the middle one, and sometimes other software steals
\r
4588 it, or it doesn't really exist. */
\r
4589 if(gameInfo.variant != VariantShogi)
\r
4590 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4592 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4596 case IcsPlayingWhite:
\r
4597 case IcsPlayingBlack:
\r
4599 case MachinePlaysWhite:
\r
4600 case MachinePlaysBlack:
\r
4601 if (appData.testLegality &&
\r
4602 gameInfo.variant != VariantBughouse &&
\r
4603 gameInfo.variant != VariantCrazyhouse) break;
\r
4604 if (x < 0 || y < 0) break;
\r
4607 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4608 SetupDropMenu(hmenu);
\r
4609 MenuPopup(hwnd, pt, hmenu, -1);
\r
4620 /* Preprocess messages for buttons in main window */
\r
4622 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4624 int id = GetWindowLong(hwnd, GWL_ID);
\r
4627 for (i=0; i<N_BUTTONS; i++) {
\r
4628 if (buttonDesc[i].id == id) break;
\r
4630 if (i == N_BUTTONS) return 0;
\r
4631 switch (message) {
\r
4636 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4637 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4644 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4647 if (appData.icsActive) {
\r
4648 if (GetKeyState(VK_SHIFT) < 0) {
\r
4650 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4651 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4655 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4656 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4663 if (appData.icsActive) {
\r
4664 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4665 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4667 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4669 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4670 PopUpMoveDialog((char)wParam);
\r
4676 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4679 /* Process messages for Promotion dialog box */
\r
4681 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4685 switch (message) {
\r
4686 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4687 /* Center the dialog over the application window */
\r
4688 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4689 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4690 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4691 gameInfo.variant == VariantGiveaway) ?
\r
4692 SW_SHOW : SW_HIDE);
\r
4693 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4694 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4695 (PieceToChar(WhiteCardinal) != '.' ||
\r
4696 PieceToChar(BlackCardinal) != '.' ) ?
\r
4697 SW_SHOW : SW_HIDE);
\r
4698 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4699 (PieceToChar(WhiteMarshall) != '.' ||
\r
4700 PieceToChar(BlackMarshall) != '.' ) ?
\r
4701 SW_SHOW : SW_HIDE);
\r
4702 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4703 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
4704 gameInfo.variant != VariantShogi ?
\r
4705 SW_SHOW : SW_HIDE);
\r
4706 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
4707 gameInfo.variant != VariantShogi ?
\r
4708 SW_SHOW : SW_HIDE);
\r
4711 case WM_COMMAND: /* message: received a command */
\r
4712 switch (LOWORD(wParam)) {
\r
4714 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4715 ClearHighlights();
\r
4716 DrawPosition(FALSE, NULL);
\r
4719 promoChar = PieceToChar(BlackKing);
\r
4722 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
4725 promoChar = PieceToChar(BlackRook);
\r
4728 promoChar = PieceToChar(BlackBishop);
\r
4730 case PB_Chancellor:
\r
4731 promoChar = PieceToChar(BlackMarshall);
\r
4733 case PB_Archbishop:
\r
4734 promoChar = PieceToChar(BlackCardinal);
\r
4737 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
4742 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4743 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
4744 only show the popup when we are already sure the move is valid or
\r
4745 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
4746 will figure out it is a promotion from the promoChar. */
\r
4747 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
4748 if (!appData.highlightLastMove) {
\r
4749 ClearHighlights();
\r
4750 DrawPosition(FALSE, NULL);
\r
4757 /* Pop up promotion dialog */
\r
4759 PromotionPopup(HWND hwnd)
\r
4763 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4764 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4765 hwnd, (DLGPROC)lpProc);
\r
4766 FreeProcInstance(lpProc);
\r
4769 /* Toggle ShowThinking */
\r
4771 ToggleShowThinking()
\r
4773 ShowThinkingEvent(!appData.showThinking);
\r
4777 LoadGameDialog(HWND hwnd, char* title)
\r
4781 char fileTitle[MSG_SIZ];
\r
4782 f = OpenFileDialog(hwnd, FALSE, "",
\r
4783 appData.oldSaveStyle ? "gam" : "pgn",
\r
4785 title, &number, fileTitle, NULL);
\r
4787 cmailMsgLoaded = FALSE;
\r
4788 if (number == 0) {
\r
4789 int error = GameListBuild(f);
\r
4791 DisplayError("Cannot build game list", error);
\r
4792 } else if (!ListEmpty(&gameList) &&
\r
4793 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4794 GameListPopUp(f, fileTitle);
\r
4797 GameListDestroy();
\r
4800 LoadGame(f, number, fileTitle, FALSE);
\r
4805 ChangedConsoleFont()
\r
4808 CHARRANGE tmpsel, sel;
\r
4809 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4810 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4811 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4814 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4815 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4816 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4817 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4818 * size. This was undocumented in the version of MSVC++ that I had
\r
4819 * when I wrote the code, but is apparently documented now.
\r
4821 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4822 cfmt.bCharSet = f->lf.lfCharSet;
\r
4823 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4824 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4825 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4826 /* Why are the following seemingly needed too? */
\r
4827 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4828 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4829 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4831 tmpsel.cpMax = -1; /*999999?*/
\r
4832 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4833 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4834 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4835 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4837 paraf.cbSize = sizeof(paraf);
\r
4838 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4839 paraf.dxStartIndent = 0;
\r
4840 paraf.dxOffset = WRAP_INDENT;
\r
4841 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4842 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4845 /*---------------------------------------------------------------------------*\
\r
4847 * Window Proc for main window
\r
4849 \*---------------------------------------------------------------------------*/
\r
4851 /* Process messages for main window, etc. */
\r
4853 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4856 int wmId, wmEvent;
\r
4860 char fileTitle[MSG_SIZ];
\r
4861 static SnapData sd;
\r
4863 switch (message) {
\r
4865 case WM_PAINT: /* message: repaint portion of window */
\r
4869 case WM_ERASEBKGND:
\r
4870 if (IsIconic(hwnd)) {
\r
4871 /* Cheat; change the message */
\r
4872 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4874 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4878 case WM_LBUTTONDOWN:
\r
4879 case WM_MBUTTONDOWN:
\r
4880 case WM_RBUTTONDOWN:
\r
4881 case WM_LBUTTONUP:
\r
4882 case WM_MBUTTONUP:
\r
4883 case WM_RBUTTONUP:
\r
4884 case WM_MOUSEMOVE:
\r
4885 MouseEvent(hwnd, message, wParam, lParam);
\r
4890 if (appData.icsActive) {
\r
4891 if (wParam == '\t') {
\r
4892 if (GetKeyState(VK_SHIFT) < 0) {
\r
4894 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4895 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4899 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4900 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4904 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4905 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4907 SendMessage(h, message, wParam, lParam);
\r
4909 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4910 PopUpMoveDialog((char)wParam);
\r
4914 case WM_PALETTECHANGED:
\r
4915 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4917 HDC hdc = GetDC(hwndMain);
\r
4918 SelectPalette(hdc, hPal, TRUE);
\r
4919 nnew = RealizePalette(hdc);
\r
4921 paletteChanged = TRUE;
\r
4923 UpdateColors(hdc);
\r
4925 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
4928 ReleaseDC(hwnd, hdc);
\r
4932 case WM_QUERYNEWPALETTE:
\r
4933 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4935 HDC hdc = GetDC(hwndMain);
\r
4936 paletteChanged = FALSE;
\r
4937 SelectPalette(hdc, hPal, FALSE);
\r
4938 nnew = RealizePalette(hdc);
\r
4940 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4942 ReleaseDC(hwnd, hdc);
\r
4947 case WM_COMMAND: /* message: command from application menu */
\r
4948 wmId = LOWORD(wParam);
\r
4949 wmEvent = HIWORD(wParam);
\r
4954 AnalysisPopDown();
\r
4957 case IDM_NewGameFRC:
\r
4958 if( NewGameFRC() == 0 ) {
\r
4960 AnalysisPopDown();
\r
4964 case IDM_NewVariant:
\r
4965 NewVariantPopup(hwnd);
\r
4968 case IDM_LoadGame:
\r
4969 LoadGameDialog(hwnd, "Load Game from File");
\r
4972 case IDM_LoadNextGame:
\r
4976 case IDM_LoadPrevGame:
\r
4980 case IDM_ReloadGame:
\r
4984 case IDM_LoadPosition:
\r
4985 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4986 Reset(FALSE, TRUE);
\r
4989 f = OpenFileDialog(hwnd, FALSE, "",
\r
4990 appData.oldSaveStyle ? "pos" : "fen",
\r
4992 "Load Position from File", &number, fileTitle, NULL);
\r
4994 LoadPosition(f, number, fileTitle);
\r
4998 case IDM_LoadNextPosition:
\r
4999 ReloadPosition(1);
\r
5002 case IDM_LoadPrevPosition:
\r
5003 ReloadPosition(-1);
\r
5006 case IDM_ReloadPosition:
\r
5007 ReloadPosition(0);
\r
5010 case IDM_SaveGame:
\r
5011 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5012 f = OpenFileDialog(hwnd, TRUE, defName,
\r
5013 appData.oldSaveStyle ? "gam" : "pgn",
\r
5015 "Save Game to File", NULL, fileTitle, NULL);
\r
5017 SaveGame(f, 0, "");
\r
5021 case IDM_SavePosition:
\r
5022 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5023 f = OpenFileDialog(hwnd, TRUE, defName,
\r
5024 appData.oldSaveStyle ? "pos" : "fen",
\r
5026 "Save Position to File", NULL, fileTitle, NULL);
\r
5028 SavePosition(f, 0, "");
\r
5032 case IDM_CopyGame:
\r
5033 CopyGameToClipboard();
\r
5036 case IDM_PasteGame:
\r
5037 PasteGameFromClipboard();
\r
5040 case IDM_CopyGameListToClipboard:
\r
5041 CopyGameListToClipboard();
\r
5044 /* [AS] Autodetect FEN or PGN data */
\r
5045 case IDM_PasteAny:
\r
5046 PasteGameOrFENFromClipboard();
\r
5049 /* [AS] Move history */
\r
5050 case IDM_ShowMoveHistory:
\r
5051 if( MoveHistoryIsUp() ) {
\r
5052 MoveHistoryPopDown();
\r
5055 MoveHistoryPopUp();
\r
5059 /* [AS] Eval graph */
\r
5060 case IDM_ShowEvalGraph:
\r
5061 if( EvalGraphIsUp() ) {
\r
5062 EvalGraphPopDown();
\r
5069 /* [AS] Engine output */
\r
5070 case IDM_ShowEngineOutput:
\r
5071 if( EngineOutputIsUp() ) {
\r
5072 EngineOutputPopDown();
\r
5075 EngineOutputPopUp();
\r
5079 /* [AS] User adjudication */
\r
5080 case IDM_UserAdjudication_White:
\r
5081 UserAdjudicationEvent( +1 );
\r
5084 case IDM_UserAdjudication_Black:
\r
5085 UserAdjudicationEvent( -1 );
\r
5088 case IDM_UserAdjudication_Draw:
\r
5089 UserAdjudicationEvent( 0 );
\r
5092 /* [AS] Game list options dialog */
\r
5093 case IDM_GameListOptions:
\r
5094 GameListOptions();
\r
5097 case IDM_CopyPosition:
\r
5098 CopyFENToClipboard();
\r
5101 case IDM_PastePosition:
\r
5102 PasteFENFromClipboard();
\r
5105 case IDM_MailMove:
\r
5109 case IDM_ReloadCMailMsg:
\r
5110 Reset(TRUE, TRUE);
\r
5111 ReloadCmailMsgEvent(FALSE);
\r
5114 case IDM_Minimize:
\r
5115 ShowWindow(hwnd, SW_MINIMIZE);
\r
5122 case IDM_MachineWhite:
\r
5123 MachineWhiteEvent();
\r
5125 * refresh the tags dialog only if it's visible
\r
5127 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5129 tags = PGNTags(&gameInfo);
\r
5130 TagsPopUp(tags, CmailMsg());
\r
5135 case IDM_MachineBlack:
\r
5136 MachineBlackEvent();
\r
5138 * refresh the tags dialog only if it's visible
\r
5140 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5142 tags = PGNTags(&gameInfo);
\r
5143 TagsPopUp(tags, CmailMsg());
\r
5148 case IDM_TwoMachines:
\r
5149 TwoMachinesEvent();
\r
5151 * refresh the tags dialog only if it's visible
\r
5153 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5155 tags = PGNTags(&gameInfo);
\r
5156 TagsPopUp(tags, CmailMsg());
\r
5161 case IDM_AnalysisMode:
\r
5162 if (!first.analysisSupport) {
\r
5163 char buf[MSG_SIZ];
\r
5164 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5165 DisplayError(buf, 0);
\r
5167 if (!appData.showThinking) ToggleShowThinking();
\r
5168 AnalyzeModeEvent();
\r
5172 case IDM_AnalyzeFile:
\r
5173 if (!first.analysisSupport) {
\r
5174 char buf[MSG_SIZ];
\r
5175 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5176 DisplayError(buf, 0);
\r
5178 if (!appData.showThinking) ToggleShowThinking();
\r
5179 AnalyzeFileEvent();
\r
5180 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5181 AnalysisPeriodicEvent(1);
\r
5185 case IDM_IcsClient:
\r
5189 case IDM_EditGame:
\r
5193 case IDM_EditPosition:
\r
5194 EditPositionEvent();
\r
5197 case IDM_Training:
\r
5201 case IDM_ShowGameList:
\r
5202 ShowGameListProc();
\r
5205 case IDM_EditTags:
\r
5209 case IDM_EditComment:
\r
5210 if (commentDialogUp && editComment) {
\r
5213 EditCommentEvent();
\r
5233 case IDM_CallFlag:
\r
5253 case IDM_StopObserving:
\r
5254 StopObservingEvent();
\r
5257 case IDM_StopExamining:
\r
5258 StopExaminingEvent();
\r
5261 case IDM_TypeInMove:
\r
5262 PopUpMoveDialog('\000');
\r
5265 case IDM_Backward:
\r
5267 SetFocus(hwndMain);
\r
5272 SetFocus(hwndMain);
\r
5277 SetFocus(hwndMain);
\r
5282 SetFocus(hwndMain);
\r
5289 case IDM_TruncateGame:
\r
5290 TruncateGameEvent();
\r
5297 case IDM_RetractMove:
\r
5298 RetractMoveEvent();
\r
5301 case IDM_FlipView:
\r
5302 flipView = !flipView;
\r
5303 DrawPosition(FALSE, NULL);
\r
5306 case IDM_FlipClock:
\r
5307 flipClock = !flipClock;
\r
5308 DisplayBothClocks();
\r
5311 case IDM_GeneralOptions:
\r
5312 GeneralOptionsPopup(hwnd);
\r
5313 DrawPosition(TRUE, NULL);
\r
5316 case IDM_BoardOptions:
\r
5317 BoardOptionsPopup(hwnd);
\r
5320 case IDM_EnginePlayOptions:
\r
5321 EnginePlayOptionsPopup(hwnd);
\r
5324 case IDM_OptionsUCI:
\r
5325 UciOptionsPopup(hwnd);
\r
5328 case IDM_IcsOptions:
\r
5329 IcsOptionsPopup(hwnd);
\r
5333 FontsOptionsPopup(hwnd);
\r
5337 SoundOptionsPopup(hwnd);
\r
5340 case IDM_CommPort:
\r
5341 CommPortOptionsPopup(hwnd);
\r
5344 case IDM_LoadOptions:
\r
5345 LoadOptionsPopup(hwnd);
\r
5348 case IDM_SaveOptions:
\r
5349 SaveOptionsPopup(hwnd);
\r
5352 case IDM_TimeControl:
\r
5353 TimeControlOptionsPopup(hwnd);
\r
5356 case IDM_SaveSettings:
\r
5357 SaveSettings(settingsFileName);
\r
5360 case IDM_SaveSettingsOnExit:
\r
5361 saveSettingsOnExit = !saveSettingsOnExit;
\r
5362 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5363 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5364 MF_CHECKED : MF_UNCHECKED));
\r
5375 case IDM_AboutGame:
\r
5380 appData.debugMode = !appData.debugMode;
\r
5381 if (appData.debugMode) {
\r
5382 char dir[MSG_SIZ];
\r
5383 GetCurrentDirectory(MSG_SIZ, dir);
\r
5384 SetCurrentDirectory(installDir);
\r
5385 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5386 SetCurrentDirectory(dir);
\r
5387 setbuf(debugFP, NULL);
\r
5394 case IDM_HELPCONTENTS:
\r
5395 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5396 MessageBox (GetFocus(),
\r
5397 "Unable to activate help",
\r
5398 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5402 case IDM_HELPSEARCH:
\r
5403 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5404 MessageBox (GetFocus(),
\r
5405 "Unable to activate help",
\r
5406 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5410 case IDM_HELPHELP:
\r
5411 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5412 MessageBox (GetFocus(),
\r
5413 "Unable to activate help",
\r
5414 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5419 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5421 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5422 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5423 FreeProcInstance(lpProc);
\r
5426 case IDM_DirectCommand1:
\r
5427 AskQuestionEvent("Direct Command",
\r
5428 "Send to chess program:", "", "1");
\r
5430 case IDM_DirectCommand2:
\r
5431 AskQuestionEvent("Direct Command",
\r
5432 "Send to second chess program:", "", "2");
\r
5435 case EP_WhitePawn:
\r
5436 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5437 fromX = fromY = -1;
\r
5440 case EP_WhiteKnight:
\r
5441 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5442 fromX = fromY = -1;
\r
5445 case EP_WhiteBishop:
\r
5446 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5447 fromX = fromY = -1;
\r
5450 case EP_WhiteRook:
\r
5451 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5452 fromX = fromY = -1;
\r
5455 case EP_WhiteQueen:
\r
5456 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5457 fromX = fromY = -1;
\r
5460 case EP_WhiteFerz:
\r
5461 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5462 fromX = fromY = -1;
\r
5465 case EP_WhiteWazir:
\r
5466 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5467 fromX = fromY = -1;
\r
5470 case EP_WhiteAlfil:
\r
5471 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5472 fromX = fromY = -1;
\r
5475 case EP_WhiteCannon:
\r
5476 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5477 fromX = fromY = -1;
\r
5480 case EP_WhiteCardinal:
\r
5481 EditPositionMenuEvent(WhiteCardinal, fromX, fromY);
\r
5482 fromX = fromY = -1;
\r
5485 case EP_WhiteMarshall:
\r
5486 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5487 fromX = fromY = -1;
\r
5490 case EP_WhiteKing:
\r
5491 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5492 fromX = fromY = -1;
\r
5495 case EP_BlackPawn:
\r
5496 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5497 fromX = fromY = -1;
\r
5500 case EP_BlackKnight:
\r
5501 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5502 fromX = fromY = -1;
\r
5505 case EP_BlackBishop:
\r
5506 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5507 fromX = fromY = -1;
\r
5510 case EP_BlackRook:
\r
5511 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5512 fromX = fromY = -1;
\r
5515 case EP_BlackQueen:
\r
5516 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5517 fromX = fromY = -1;
\r
5520 case EP_BlackFerz:
\r
5521 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5522 fromX = fromY = -1;
\r
5525 case EP_BlackWazir:
\r
5526 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5527 fromX = fromY = -1;
\r
5530 case EP_BlackAlfil:
\r
5531 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5532 fromX = fromY = -1;
\r
5535 case EP_BlackCannon:
\r
5536 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5537 fromX = fromY = -1;
\r
5540 case EP_BlackCardinal:
\r
5541 EditPositionMenuEvent(BlackCardinal, fromX, fromY);
\r
5542 fromX = fromY = -1;
\r
5545 case EP_BlackMarshall:
\r
5546 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5547 fromX = fromY = -1;
\r
5550 case EP_BlackKing:
\r
5551 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5552 fromX = fromY = -1;
\r
5555 case EP_EmptySquare:
\r
5556 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5557 fromX = fromY = -1;
\r
5560 case EP_ClearBoard:
\r
5561 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5562 fromX = fromY = -1;
\r
5566 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5567 fromX = fromY = -1;
\r
5571 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5572 fromX = fromY = -1;
\r
5576 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5577 fromX = fromY = -1;
\r
5581 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5582 fromX = fromY = -1;
\r
5586 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5587 fromX = fromY = -1;
\r
5591 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5592 fromX = fromY = -1;
\r
5596 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5597 fromX = fromY = -1;
\r
5601 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5602 fromX = fromY = -1;
\r
5606 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5607 fromX = fromY = -1;
\r
5611 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5617 case CLOCK_TIMER_ID:
\r
5618 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5619 clockTimerEvent = 0;
\r
5620 DecrementClocks(); /* call into back end */
\r
5622 case LOAD_GAME_TIMER_ID:
\r
5623 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5624 loadGameTimerEvent = 0;
\r
5625 AutoPlayGameLoop(); /* call into back end */
\r
5627 case ANALYSIS_TIMER_ID:
\r
5628 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
5629 appData.periodicUpdates) {
\r
5630 AnalysisPeriodicEvent(0);
\r
5632 KillTimer(hwnd, analysisTimerEvent);
\r
5633 analysisTimerEvent = 0;
\r
5636 case DELAYED_TIMER_ID:
\r
5637 KillTimer(hwnd, delayedTimerEvent);
\r
5638 delayedTimerEvent = 0;
\r
5639 delayedTimerCallback();
\r
5644 case WM_USER_Input:
\r
5645 InputEvent(hwnd, message, wParam, lParam);
\r
5648 /* [AS] Also move "attached" child windows */
\r
5649 case WM_WINDOWPOSCHANGING:
\r
5650 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5651 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5653 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
5654 /* Window is moving */
\r
5657 GetWindowRect( hwnd, &rcMain );
\r
5659 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5660 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5661 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5666 /* [AS] Snapping */
\r
5667 case WM_ENTERSIZEMOVE:
\r
5668 if (hwnd == hwndMain) {
\r
5669 doingSizing = TRUE;
\r
5672 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5676 if (hwnd == hwndMain) {
\r
5677 lastSizing = wParam;
\r
5682 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5684 case WM_EXITSIZEMOVE:
\r
5685 if (hwnd == hwndMain) {
\r
5687 doingSizing = FALSE;
\r
5688 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5689 GetClientRect(hwnd, &client);
\r
5690 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5693 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5696 case WM_DESTROY: /* message: window being destroyed */
\r
5697 PostQuitMessage(0);
\r
5701 if (hwnd == hwndMain) {
\r
5706 default: /* Passes it on if unprocessed */
\r
5707 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5712 /*---------------------------------------------------------------------------*\
\r
5714 * Misc utility routines
\r
5716 \*---------------------------------------------------------------------------*/
\r
5719 * Decent random number generator, at least not as bad as Windows
\r
5720 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5722 unsigned int randstate;
\r
5727 randstate = randstate * 1664525 + 1013904223;
\r
5728 return (int) randstate & 0x7fffffff;
\r
5732 mysrandom(unsigned int seed)
\r
5739 * returns TRUE if user selects a different color, FALSE otherwise
\r
5743 ChangeColor(HWND hwnd, COLORREF *which)
\r
5745 static BOOL firstTime = TRUE;
\r
5746 static DWORD customColors[16];
\r
5748 COLORREF newcolor;
\r
5753 /* Make initial colors in use available as custom colors */
\r
5754 /* Should we put the compiled-in defaults here instead? */
\r
5756 customColors[i++] = lightSquareColor & 0xffffff;
\r
5757 customColors[i++] = darkSquareColor & 0xffffff;
\r
5758 customColors[i++] = whitePieceColor & 0xffffff;
\r
5759 customColors[i++] = blackPieceColor & 0xffffff;
\r
5760 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5761 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5763 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5764 customColors[i++] = textAttribs[ccl].color;
\r
5766 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5767 firstTime = FALSE;
\r
5770 cc.lStructSize = sizeof(cc);
\r
5771 cc.hwndOwner = hwnd;
\r
5772 cc.hInstance = NULL;
\r
5773 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5774 cc.lpCustColors = (LPDWORD) customColors;
\r
5775 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5777 if (!ChooseColor(&cc)) return FALSE;
\r
5779 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5780 if (newcolor == *which) return FALSE;
\r
5781 *which = newcolor;
\r
5785 InitDrawingColors();
\r
5786 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5791 MyLoadSound(MySound *ms)
\r
5797 if (ms->data) free(ms->data);
\r
5800 switch (ms->name[0]) {
\r
5806 /* System sound from Control Panel. Don't preload here. */
\r
5810 if (ms->name[1] == NULLCHAR) {
\r
5811 /* "!" alone = silence */
\r
5814 /* Builtin wave resource. Error if not found. */
\r
5815 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5816 if (h == NULL) break;
\r
5817 ms->data = (void *)LoadResource(hInst, h);
\r
5818 if (h == NULL) break;
\r
5823 /* .wav file. Error if not found. */
\r
5824 f = fopen(ms->name, "rb");
\r
5825 if (f == NULL) break;
\r
5826 if (fstat(fileno(f), &st) < 0) break;
\r
5827 ms->data = malloc(st.st_size);
\r
5828 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5834 char buf[MSG_SIZ];
\r
5835 sprintf(buf, "Error loading sound %s", ms->name);
\r
5836 DisplayError(buf, GetLastError());
\r
5842 MyPlaySound(MySound *ms)
\r
5844 BOOLEAN ok = FALSE;
\r
5845 switch (ms->name[0]) {
\r
5851 /* System sound from Control Panel (deprecated feature).
\r
5852 "$" alone or an unset sound name gets default beep (still in use). */
\r
5853 if (ms->name[1]) {
\r
5854 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5856 if (!ok) ok = MessageBeep(MB_OK);
\r
5859 /* Builtin wave resource, or "!" alone for silence */
\r
5860 if (ms->name[1]) {
\r
5861 if (ms->data == NULL) return FALSE;
\r
5862 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5868 /* .wav file. Error if not found. */
\r
5869 if (ms->data == NULL) return FALSE;
\r
5870 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5873 /* Don't print an error: this can happen innocently if the sound driver
\r
5874 is busy; for instance, if another instance of WinBoard is playing
\r
5875 a sound at about the same time. */
\r
5878 char buf[MSG_SIZ];
\r
5879 sprintf(buf, "Error playing sound %s", ms->name);
\r
5880 DisplayError(buf, GetLastError());
\r
5888 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5891 OPENFILENAME *ofn;
\r
5892 static UINT *number; /* gross that this is static */
\r
5894 switch (message) {
\r
5895 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5896 /* Center the dialog over the application window */
\r
5897 ofn = (OPENFILENAME *) lParam;
\r
5898 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5899 number = (UINT *) ofn->lCustData;
\r
5900 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5904 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5905 return FALSE; /* Allow for further processing */
\r
5908 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5909 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5911 return FALSE; /* Allow for further processing */
\r
5917 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5919 static UINT *number;
\r
5920 OPENFILENAME *ofname;
\r
5923 case WM_INITDIALOG:
\r
5924 ofname = (OPENFILENAME *)lParam;
\r
5925 number = (UINT *)(ofname->lCustData);
\r
5928 ofnot = (OFNOTIFY *)lParam;
\r
5929 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5930 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5939 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
5940 char *nameFilt, char *dlgTitle, UINT *number,
\r
5941 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5943 OPENFILENAME openFileName;
\r
5944 char buf1[MSG_SIZ];
\r
5947 if (fileName == NULL) fileName = buf1;
\r
5948 if (defName == NULL) {
\r
5949 strcpy(fileName, "*.");
\r
5950 strcat(fileName, defExt);
\r
5952 strcpy(fileName, defName);
\r
5954 if (fileTitle) strcpy(fileTitle, "");
\r
5955 if (number) *number = 0;
\r
5957 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5958 openFileName.hwndOwner = hwnd;
\r
5959 openFileName.hInstance = (HANDLE) hInst;
\r
5960 openFileName.lpstrFilter = nameFilt;
\r
5961 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5962 openFileName.nMaxCustFilter = 0L;
\r
5963 openFileName.nFilterIndex = 1L;
\r
5964 openFileName.lpstrFile = fileName;
\r
5965 openFileName.nMaxFile = MSG_SIZ;
\r
5966 openFileName.lpstrFileTitle = fileTitle;
\r
5967 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5968 openFileName.lpstrInitialDir = NULL;
\r
5969 openFileName.lpstrTitle = dlgTitle;
\r
5970 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5971 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
5972 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5973 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5974 openFileName.nFileOffset = 0;
\r
5975 openFileName.nFileExtension = 0;
\r
5976 openFileName.lpstrDefExt = defExt;
\r
5977 openFileName.lCustData = (LONG) number;
\r
5978 openFileName.lpfnHook = oldDialog ?
\r
5979 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5980 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5982 if (write ? GetSaveFileName(&openFileName) :
\r
5983 GetOpenFileName(&openFileName)) {
\r
5984 /* open the file */
\r
5985 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
5987 MessageBox(hwnd, "File open failed", NULL,
\r
5988 MB_OK|MB_ICONEXCLAMATION);
\r
5992 int err = CommDlgExtendedError();
\r
5993 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6002 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6004 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6007 * Get the first pop-up menu in the menu template. This is the
\r
6008 * menu that TrackPopupMenu displays.
\r
6010 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6012 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6015 * TrackPopup uses screen coordinates, so convert the
\r
6016 * coordinates of the mouse click to screen coordinates.
\r
6018 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6020 /* Draw and track the floating pop-up menu. */
\r
6021 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6022 pt.x, pt.y, 0, hwnd, NULL);
\r
6024 /* Destroy the menu.*/
\r
6025 DestroyMenu(hmenu);
\r
6030 int sizeX, sizeY, newSizeX, newSizeY;
\r
6032 } ResizeEditPlusButtonsClosure;
\r
6035 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6037 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6041 if (hChild == cl->hText) return TRUE;
\r
6042 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6043 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6044 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6045 ScreenToClient(cl->hDlg, &pt);
\r
6046 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6047 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6051 /* Resize a dialog that has a (rich) edit field filling most of
\r
6052 the top, with a row of buttons below */
\r
6054 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6057 int newTextHeight, newTextWidth;
\r
6058 ResizeEditPlusButtonsClosure cl;
\r
6060 /*if (IsIconic(hDlg)) return;*/
\r
6061 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6063 cl.hdwp = BeginDeferWindowPos(8);
\r
6065 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6066 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6067 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6068 if (newTextHeight < 0) {
\r
6069 newSizeY += -newTextHeight;
\r
6070 newTextHeight = 0;
\r
6072 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6073 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6079 cl.newSizeX = newSizeX;
\r
6080 cl.newSizeY = newSizeY;
\r
6081 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6083 EndDeferWindowPos(cl.hdwp);
\r
6086 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6088 RECT rChild, rParent;
\r
6089 int wChild, hChild, wParent, hParent;
\r
6090 int wScreen, hScreen, xNew, yNew;
\r
6093 /* Get the Height and Width of the child window */
\r
6094 GetWindowRect (hwndChild, &rChild);
\r
6095 wChild = rChild.right - rChild.left;
\r
6096 hChild = rChild.bottom - rChild.top;
\r
6098 /* Get the Height and Width of the parent window */
\r
6099 GetWindowRect (hwndParent, &rParent);
\r
6100 wParent = rParent.right - rParent.left;
\r
6101 hParent = rParent.bottom - rParent.top;
\r
6103 /* Get the display limits */
\r
6104 hdc = GetDC (hwndChild);
\r
6105 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6106 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6107 ReleaseDC(hwndChild, hdc);
\r
6109 /* Calculate new X position, then adjust for screen */
\r
6110 xNew = rParent.left + ((wParent - wChild) /2);
\r
6113 } else if ((xNew+wChild) > wScreen) {
\r
6114 xNew = wScreen - wChild;
\r
6117 /* Calculate new Y position, then adjust for screen */
\r
6119 yNew = rParent.top + ((hParent - hChild) /2);
\r
6122 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6127 } else if ((yNew+hChild) > hScreen) {
\r
6128 yNew = hScreen - hChild;
\r
6131 /* Set it, and return */
\r
6132 return SetWindowPos (hwndChild, NULL,
\r
6133 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6136 /* Center one window over another */
\r
6137 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6139 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6142 /*---------------------------------------------------------------------------*\
\r
6144 * Startup Dialog functions
\r
6146 \*---------------------------------------------------------------------------*/
\r
6148 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6150 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6152 while (*cd != NULL) {
\r
6153 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6159 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6161 char buf1[ARG_MAX];
\r
6164 if (str[0] == '@') {
\r
6165 FILE* f = fopen(str + 1, "r");
\r
6167 DisplayFatalError(str + 1, errno, 2);
\r
6170 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6172 buf1[len] = NULLCHAR;
\r
6176 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6179 char buf[MSG_SIZ];
\r
6180 char *end = strchr(str, '\n');
\r
6181 if (end == NULL) return;
\r
6182 memcpy(buf, str, end - str);
\r
6183 buf[end - str] = NULLCHAR;
\r
6184 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6190 SetStartupDialogEnables(HWND hDlg)
\r
6192 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6193 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6194 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6195 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6196 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6197 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6198 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6199 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6200 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6201 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6202 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6203 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6204 IsDlgButtonChecked(hDlg, OPT_View));
\r
6208 QuoteForFilename(char *filename)
\r
6210 int dquote, space;
\r
6211 dquote = strchr(filename, '"') != NULL;
\r
6212 space = strchr(filename, ' ') != NULL;
\r
6213 if (dquote || space) {
\r
6225 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6227 char buf[MSG_SIZ];
\r
6230 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6231 q = QuoteForFilename(nthcp);
\r
6232 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6233 if (*nthdir != NULLCHAR) {
\r
6234 q = QuoteForFilename(nthdir);
\r
6235 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6237 if (*nthcp == NULLCHAR) {
\r
6238 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6239 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6240 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6241 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6246 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6248 char buf[MSG_SIZ];
\r
6252 switch (message) {
\r
6253 case WM_INITDIALOG:
\r
6254 /* Center the dialog */
\r
6255 CenterWindow (hDlg, GetDesktopWindow());
\r
6256 /* Initialize the dialog items */
\r
6257 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6258 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6259 firstChessProgramNames);
\r
6260 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6261 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6262 secondChessProgramNames);
\r
6263 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6264 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6265 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6266 if (*appData.icsHelper != NULLCHAR) {
\r
6267 char *q = QuoteForFilename(appData.icsHelper);
\r
6268 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6270 if (*appData.icsHost == NULLCHAR) {
\r
6271 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6272 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6273 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6274 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6275 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6278 if (appData.icsActive) {
\r
6279 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6281 else if (appData.noChessProgram) {
\r
6282 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6285 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6288 SetStartupDialogEnables(hDlg);
\r
6292 switch (LOWORD(wParam)) {
\r
6294 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6295 strcpy(buf, "/fcp=");
\r
6296 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6298 ParseArgs(StringGet, &p);
\r
6299 strcpy(buf, "/scp=");
\r
6300 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6302 ParseArgs(StringGet, &p);
\r
6303 appData.noChessProgram = FALSE;
\r
6304 appData.icsActive = FALSE;
\r
6305 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6306 strcpy(buf, "/ics /icshost=");
\r
6307 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6309 ParseArgs(StringGet, &p);
\r
6310 if (appData.zippyPlay) {
\r
6311 strcpy(buf, "/fcp=");
\r
6312 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6314 ParseArgs(StringGet, &p);
\r
6316 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6317 appData.noChessProgram = TRUE;
\r
6318 appData.icsActive = FALSE;
\r
6320 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6321 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6324 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6325 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6327 ParseArgs(StringGet, &p);
\r
6329 EndDialog(hDlg, TRUE);
\r
6336 case IDM_HELPCONTENTS:
\r
6337 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6338 MessageBox (GetFocus(),
\r
6339 "Unable to activate help",
\r
6340 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6345 SetStartupDialogEnables(hDlg);
\r
6353 /*---------------------------------------------------------------------------*\
\r
6355 * About box dialog functions
\r
6357 \*---------------------------------------------------------------------------*/
\r
6359 /* Process messages for "About" dialog box */
\r
6361 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6363 switch (message) {
\r
6364 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6365 /* Center the dialog over the application window */
\r
6366 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6367 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6370 case WM_COMMAND: /* message: received a command */
\r
6371 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6372 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6373 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6381 /*---------------------------------------------------------------------------*\
\r
6383 * Comment Dialog functions
\r
6385 \*---------------------------------------------------------------------------*/
\r
6388 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6390 static HANDLE hwndText = NULL;
\r
6391 int len, newSizeX, newSizeY, flags;
\r
6392 static int sizeX, sizeY;
\r
6397 switch (message) {
\r
6398 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6399 /* Initialize the dialog items */
\r
6400 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6401 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6402 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6403 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6404 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6405 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6406 SetWindowText(hDlg, commentTitle);
\r
6407 if (editComment) {
\r
6408 SetFocus(hwndText);
\r
6410 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6412 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6413 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6414 MAKELPARAM(FALSE, 0));
\r
6415 /* Size and position the dialog */
\r
6416 if (!commentDialog) {
\r
6417 commentDialog = hDlg;
\r
6418 flags = SWP_NOZORDER;
\r
6419 GetClientRect(hDlg, &rect);
\r
6420 sizeX = rect.right;
\r
6421 sizeY = rect.bottom;
\r
6422 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
6423 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
6424 WINDOWPLACEMENT wp;
\r
6425 EnsureOnScreen(&commentX, &commentY);
\r
6426 wp.length = sizeof(WINDOWPLACEMENT);
\r
6428 wp.showCmd = SW_SHOW;
\r
6429 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6430 wp.rcNormalPosition.left = commentX;
\r
6431 wp.rcNormalPosition.right = commentX + commentW;
\r
6432 wp.rcNormalPosition.top = commentY;
\r
6433 wp.rcNormalPosition.bottom = commentY + commentH;
\r
6434 SetWindowPlacement(hDlg, &wp);
\r
6436 GetClientRect(hDlg, &rect);
\r
6437 newSizeX = rect.right;
\r
6438 newSizeY = rect.bottom;
\r
6439 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6440 newSizeX, newSizeY);
\r
6447 case WM_COMMAND: /* message: received a command */
\r
6448 switch (LOWORD(wParam)) {
\r
6450 if (editComment) {
\r
6452 /* Read changed options from the dialog box */
\r
6453 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6454 len = GetWindowTextLength(hwndText);
\r
6455 str = (char *) malloc(len + 1);
\r
6456 GetWindowText(hwndText, str, len + 1);
\r
6465 ReplaceComment(commentIndex, str);
\r
6472 case OPT_CancelComment:
\r
6476 case OPT_ClearComment:
\r
6477 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6480 case OPT_EditComment:
\r
6481 EditCommentEvent();
\r
6490 newSizeX = LOWORD(lParam);
\r
6491 newSizeY = HIWORD(lParam);
\r
6492 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6497 case WM_GETMINMAXINFO:
\r
6498 /* Prevent resizing window too small */
\r
6499 mmi = (MINMAXINFO *) lParam;
\r
6500 mmi->ptMinTrackSize.x = 100;
\r
6501 mmi->ptMinTrackSize.y = 100;
\r
6508 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6513 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6515 if (str == NULL) str = "";
\r
6516 p = (char *) malloc(2 * strlen(str) + 2);
\r
6519 if (*str == '\n') *q++ = '\r';
\r
6523 if (commentText != NULL) free(commentText);
\r
6525 commentIndex = index;
\r
6526 commentTitle = title;
\r
6528 editComment = edit;
\r
6530 if (commentDialog) {
\r
6531 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6532 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
6534 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6535 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6536 hwndMain, (DLGPROC)lpProc);
\r
6537 FreeProcInstance(lpProc);
\r
6539 commentDialogUp = TRUE;
\r
6543 /*---------------------------------------------------------------------------*\
\r
6545 * Type-in move dialog functions
\r
6547 \*---------------------------------------------------------------------------*/
\r
6550 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6552 char move[MSG_SIZ];
\r
6554 ChessMove moveType;
\r
6555 int fromX, fromY, toX, toY;
\r
6558 switch (message) {
\r
6559 case WM_INITDIALOG:
\r
6560 move[0] = (char) lParam;
\r
6561 move[1] = NULLCHAR;
\r
6562 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6563 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6564 SetWindowText(hInput, move);
\r
6566 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6570 switch (LOWORD(wParam)) {
\r
6572 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
6573 gameMode != Training) {
\r
6574 DisplayMoveError("Displayed move is not current");
\r
6576 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6577 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6578 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
6579 if (gameMode != Training)
\r
6580 forwardMostMove = currentMove;
\r
6581 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
6583 DisplayMoveError("Could not parse move");
\r
6586 EndDialog(hDlg, TRUE);
\r
6589 EndDialog(hDlg, FALSE);
\r
6600 PopUpMoveDialog(char firstchar)
\r
6604 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
6605 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
6606 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
6607 gameMode == EditPosition || gameMode == IcsExamining ||
\r
6608 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
6609 gameMode == Training) {
\r
6610 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6611 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6612 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6613 FreeProcInstance(lpProc);
\r
6617 /*---------------------------------------------------------------------------*\
\r
6621 \*---------------------------------------------------------------------------*/
\r
6623 /* Nonmodal error box */
\r
6624 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6625 WPARAM wParam, LPARAM lParam);
\r
6628 ErrorPopUp(char *title, char *content)
\r
6632 BOOLEAN modal = hwndMain == NULL;
\r
6650 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6651 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6654 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6656 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6657 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6658 hwndMain, (DLGPROC)lpProc);
\r
6659 FreeProcInstance(lpProc);
\r
6666 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6667 if (errorDialog == NULL) return;
\r
6668 DestroyWindow(errorDialog);
\r
6669 errorDialog = NULL;
\r
6673 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6678 switch (message) {
\r
6679 case WM_INITDIALOG:
\r
6680 GetWindowRect(hDlg, &rChild);
\r
6683 SetWindowPos(hDlg, NULL, rChild.left,
\r
6684 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6685 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6689 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6690 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6691 and it doesn't work when you resize the dialog.
\r
6692 For now, just give it a default position.
\r
6694 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6696 errorDialog = hDlg;
\r
6697 SetWindowText(hDlg, errorTitle);
\r
6698 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6699 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6703 switch (LOWORD(wParam)) {
\r
6706 if (errorDialog == hDlg) errorDialog = NULL;
\r
6707 DestroyWindow(hDlg);
\r
6719 HWND gothicDialog = NULL;
\r
6722 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6726 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6728 switch (message) {
\r
6729 case WM_INITDIALOG:
\r
6730 GetWindowRect(hDlg, &rChild);
\r
6732 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
6736 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6737 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6738 and it doesn't work when you resize the dialog.
\r
6739 For now, just give it a default position.
\r
6741 gothicDialog = hDlg;
\r
6742 SetWindowText(hDlg, errorTitle);
\r
6743 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6744 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6748 switch (LOWORD(wParam)) {
\r
6751 if (errorDialog == hDlg) errorDialog = NULL;
\r
6752 DestroyWindow(hDlg);
\r
6764 GothicPopUp(char *title, char up)
\r
6768 BOOLEAN modal = hwndMain == NULL;
\r
6770 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6771 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6773 if(up && gothicDialog == NULL) {
\r
6774 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6775 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6776 hwndMain, (DLGPROC)lpProc);
\r
6777 FreeProcInstance(lpProc);
\r
6778 } else if(!up && gothicDialog != NULL) {
\r
6779 DestroyWindow(gothicDialog);
\r
6780 gothicDialog = NULL;
\r
6785 /*---------------------------------------------------------------------------*\
\r
6787 * Ics Interaction console functions
\r
6789 \*---------------------------------------------------------------------------*/
\r
6791 #define HISTORY_SIZE 64
\r
6792 static char *history[HISTORY_SIZE];
\r
6793 int histIn = 0, histP = 0;
\r
6796 SaveInHistory(char *cmd)
\r
6798 if (history[histIn] != NULL) {
\r
6799 free(history[histIn]);
\r
6800 history[histIn] = NULL;
\r
6802 if (*cmd == NULLCHAR) return;
\r
6803 history[histIn] = StrSave(cmd);
\r
6804 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6805 if (history[histIn] != NULL) {
\r
6806 free(history[histIn]);
\r
6807 history[histIn] = NULL;
\r
6813 PrevInHistory(char *cmd)
\r
6816 if (histP == histIn) {
\r
6817 if (history[histIn] != NULL) free(history[histIn]);
\r
6818 history[histIn] = StrSave(cmd);
\r
6820 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6821 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6823 return history[histP];
\r
6829 if (histP == histIn) return NULL;
\r
6830 histP = (histP + 1) % HISTORY_SIZE;
\r
6831 return history[histP];
\r
6838 BOOLEAN immediate;
\r
6839 } IcsTextMenuEntry;
\r
6840 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
6841 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
6844 ParseIcsTextMenu(char *icsTextMenuString)
\r
6847 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
6848 char *p = icsTextMenuString;
\r
6849 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6852 if (e->command != NULL) {
\r
6854 e->command = NULL;
\r
6858 e = icsTextMenuEntry;
\r
6859 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6860 if (*p == ';' || *p == '\n') {
\r
6861 e->item = strdup("-");
\r
6862 e->command = NULL;
\r
6864 } else if (*p == '-') {
\r
6865 e->item = strdup("-");
\r
6866 e->command = NULL;
\r
6870 char *q, *r, *s, *t;
\r
6872 q = strchr(p, ',');
\r
6873 if (q == NULL) break;
\r
6875 r = strchr(q + 1, ',');
\r
6876 if (r == NULL) break;
\r
6878 s = strchr(r + 1, ',');
\r
6879 if (s == NULL) break;
\r
6882 t = strchr(s + 1, c);
\r
6885 t = strchr(s + 1, c);
\r
6887 if (t != NULL) *t = NULLCHAR;
\r
6888 e->item = strdup(p);
\r
6889 e->command = strdup(q + 1);
\r
6890 e->getname = *(r + 1) != '0';
\r
6891 e->immediate = *(s + 1) != '0';
\r
6895 if (t == NULL) break;
\r
6904 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6908 hmenu = LoadMenu(hInst, "TextMenu");
\r
6909 h = GetSubMenu(hmenu, 0);
\r
6911 if (strcmp(e->item, "-") == 0) {
\r
6912 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6914 if (e->item[0] == '|') {
\r
6915 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6916 IDM_CommandX + i, &e->item[1]);
\r
6918 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
6927 WNDPROC consoleTextWindowProc;
\r
6930 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6932 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6933 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6937 SetWindowText(hInput, command);
\r
6939 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6941 sel.cpMin = 999999;
\r
6942 sel.cpMax = 999999;
\r
6943 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6948 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6949 if (sel.cpMin == sel.cpMax) {
\r
6950 /* Expand to surrounding word */
\r
6953 tr.chrg.cpMax = sel.cpMin;
\r
6954 tr.chrg.cpMin = --sel.cpMin;
\r
6955 if (sel.cpMin < 0) break;
\r
6956 tr.lpstrText = name;
\r
6957 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6958 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6962 tr.chrg.cpMin = sel.cpMax;
\r
6963 tr.chrg.cpMax = ++sel.cpMax;
\r
6964 tr.lpstrText = name;
\r
6965 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6966 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6969 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6970 MessageBeep(MB_ICONEXCLAMATION);
\r
6974 tr.lpstrText = name;
\r
6975 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6977 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6978 MessageBeep(MB_ICONEXCLAMATION);
\r
6981 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6984 sprintf(buf, "%s %s", command, name);
\r
6985 SetWindowText(hInput, buf);
\r
6986 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6988 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
6989 SetWindowText(hInput, buf);
\r
6990 sel.cpMin = 999999;
\r
6991 sel.cpMax = 999999;
\r
6992 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6998 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7003 switch (message) {
\r
7005 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7008 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7011 sel.cpMin = 999999;
\r
7012 sel.cpMax = 999999;
\r
7013 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7014 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7019 if (wParam == '\t') {
\r
7020 if (GetKeyState(VK_SHIFT) < 0) {
\r
7022 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7023 if (buttonDesc[0].hwnd) {
\r
7024 SetFocus(buttonDesc[0].hwnd);
\r
7026 SetFocus(hwndMain);
\r
7030 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7033 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7035 SendMessage(hInput, message, wParam, lParam);
\r
7039 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7041 return SendMessage(hInput, message, wParam, lParam);
\r
7042 case WM_MBUTTONDOWN:
\r
7043 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7044 case WM_RBUTTONDOWN:
\r
7045 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7046 /* Move selection here if it was empty */
\r
7048 pt.x = LOWORD(lParam);
\r
7049 pt.y = HIWORD(lParam);
\r
7050 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7051 if (sel.cpMin == sel.cpMax) {
\r
7052 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7053 sel.cpMax = sel.cpMin;
\r
7054 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7056 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7059 case WM_RBUTTONUP:
\r
7060 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7061 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7062 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7065 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7066 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7067 if (sel.cpMin == sel.cpMax) {
\r
7068 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7069 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7071 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7072 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7074 pt.x = LOWORD(lParam);
\r
7075 pt.y = HIWORD(lParam);
\r
7076 MenuPopup(hwnd, pt, hmenu, -1);
\r
7080 switch (LOWORD(wParam)) {
\r
7081 case IDM_QuickPaste:
\r
7083 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7084 if (sel.cpMin == sel.cpMax) {
\r
7085 MessageBeep(MB_ICONEXCLAMATION);
\r
7088 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7089 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7090 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7095 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7098 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7101 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7105 int i = LOWORD(wParam) - IDM_CommandX;
\r
7106 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7107 icsTextMenuEntry[i].command != NULL) {
\r
7108 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7109 icsTextMenuEntry[i].getname,
\r
7110 icsTextMenuEntry[i].immediate);
\r
7118 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7121 WNDPROC consoleInputWindowProc;
\r
7124 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7126 char buf[MSG_SIZ];
\r
7128 static BOOL sendNextChar = FALSE;
\r
7129 static BOOL quoteNextChar = FALSE;
\r
7130 InputSource *is = consoleInputSource;
\r
7134 switch (message) {
\r
7136 if (!appData.localLineEditing || sendNextChar) {
\r
7137 is->buf[0] = (CHAR) wParam;
\r
7139 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7140 sendNextChar = FALSE;
\r
7143 if (quoteNextChar) {
\r
7144 buf[0] = (char) wParam;
\r
7145 buf[1] = NULLCHAR;
\r
7146 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7147 quoteNextChar = FALSE;
\r
7151 case '\r': /* Enter key */
\r
7152 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7153 if (consoleEcho) SaveInHistory(is->buf);
\r
7154 is->buf[is->count++] = '\n';
\r
7155 is->buf[is->count] = NULLCHAR;
\r
7156 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7157 if (consoleEcho) {
\r
7158 ConsoleOutput(is->buf, is->count, TRUE);
\r
7159 } else if (appData.localLineEditing) {
\r
7160 ConsoleOutput("\n", 1, TRUE);
\r
7163 case '\033': /* Escape key */
\r
7164 SetWindowText(hwnd, "");
\r
7165 cf.cbSize = sizeof(CHARFORMAT);
\r
7166 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7167 if (consoleEcho) {
\r
7168 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7170 cf.crTextColor = COLOR_ECHOOFF;
\r
7172 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7173 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7175 case '\t': /* Tab key */
\r
7176 if (GetKeyState(VK_SHIFT) < 0) {
\r
7178 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7181 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7182 if (buttonDesc[0].hwnd) {
\r
7183 SetFocus(buttonDesc[0].hwnd);
\r
7185 SetFocus(hwndMain);
\r
7189 case '\023': /* Ctrl+S */
\r
7190 sendNextChar = TRUE;
\r
7192 case '\021': /* Ctrl+Q */
\r
7193 quoteNextChar = TRUE;
\r
7202 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7203 p = PrevInHistory(buf);
\r
7205 SetWindowText(hwnd, p);
\r
7206 sel.cpMin = 999999;
\r
7207 sel.cpMax = 999999;
\r
7208 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7213 p = NextInHistory();
\r
7215 SetWindowText(hwnd, p);
\r
7216 sel.cpMin = 999999;
\r
7217 sel.cpMax = 999999;
\r
7218 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7224 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7228 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7232 case WM_MBUTTONDOWN:
\r
7233 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7234 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7236 case WM_RBUTTONUP:
\r
7237 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7238 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7239 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7243 hmenu = LoadMenu(hInst, "InputMenu");
\r
7244 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7245 if (sel.cpMin == sel.cpMax) {
\r
7246 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7247 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7249 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7250 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7252 pt.x = LOWORD(lParam);
\r
7253 pt.y = HIWORD(lParam);
\r
7254 MenuPopup(hwnd, pt, hmenu, -1);
\r
7258 switch (LOWORD(wParam)) {
\r
7260 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7262 case IDM_SelectAll:
\r
7264 sel.cpMax = -1; /*999999?*/
\r
7265 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7268 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7271 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7274 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7279 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7282 #define CO_MAX 100000
\r
7283 #define CO_TRIM 1000
\r
7286 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7288 static SnapData sd;
\r
7289 static HWND hText, hInput, hFocus;
\r
7290 InputSource *is = consoleInputSource;
\r
7292 static int sizeX, sizeY;
\r
7293 int newSizeX, newSizeY;
\r
7296 switch (message) {
\r
7297 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7298 hwndConsole = hDlg;
\r
7299 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7300 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7302 consoleTextWindowProc = (WNDPROC)
\r
7303 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7304 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7305 consoleInputWindowProc = (WNDPROC)
\r
7306 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7307 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7308 Colorize(ColorNormal, TRUE);
\r
7309 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7310 ChangedConsoleFont();
\r
7311 GetClientRect(hDlg, &rect);
\r
7312 sizeX = rect.right;
\r
7313 sizeY = rect.bottom;
\r
7314 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7315 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7316 WINDOWPLACEMENT wp;
\r
7317 EnsureOnScreen(&consoleX, &consoleY);
\r
7318 wp.length = sizeof(WINDOWPLACEMENT);
\r
7320 wp.showCmd = SW_SHOW;
\r
7321 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7322 wp.rcNormalPosition.left = consoleX;
\r
7323 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7324 wp.rcNormalPosition.top = consoleY;
\r
7325 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7326 SetWindowPlacement(hDlg, &wp);
\r
7340 if (IsIconic(hDlg)) break;
\r
7341 newSizeX = LOWORD(lParam);
\r
7342 newSizeY = HIWORD(lParam);
\r
7343 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7344 RECT rectText, rectInput;
\r
7346 int newTextHeight, newTextWidth;
\r
7347 GetWindowRect(hText, &rectText);
\r
7348 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7349 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7350 if (newTextHeight < 0) {
\r
7351 newSizeY += -newTextHeight;
\r
7352 newTextHeight = 0;
\r
7354 SetWindowPos(hText, NULL, 0, 0,
\r
7355 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7356 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7357 pt.x = rectInput.left;
\r
7358 pt.y = rectInput.top + newSizeY - sizeY;
\r
7359 ScreenToClient(hDlg, &pt);
\r
7360 SetWindowPos(hInput, NULL,
\r
7361 pt.x, pt.y, /* needs client coords */
\r
7362 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7363 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7369 case WM_GETMINMAXINFO:
\r
7370 /* Prevent resizing window too small */
\r
7371 mmi = (MINMAXINFO *) lParam;
\r
7372 mmi->ptMinTrackSize.x = 100;
\r
7373 mmi->ptMinTrackSize.y = 100;
\r
7376 /* [AS] Snapping */
\r
7377 case WM_ENTERSIZEMOVE:
\r
7378 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7381 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7384 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7386 case WM_EXITSIZEMOVE:
\r
7387 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7390 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7398 if (hwndConsole) return;
\r
7399 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7400 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7405 ConsoleOutput(char* data, int length, int forceVisible)
\r
7410 char buf[CO_MAX+1];
\r
7413 static int delayLF = 0;
\r
7414 CHARRANGE savesel, sel;
\r
7416 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7424 while (length--) {
\r
7432 } else if (*p == '\007') {
\r
7433 MyPlaySound(&sounds[(int)SoundBell]);
\r
7440 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7441 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7442 /* Save current selection */
\r
7443 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7444 exlen = GetWindowTextLength(hText);
\r
7445 /* Find out whether current end of text is visible */
\r
7446 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7447 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7448 /* Trim existing text if it's too long */
\r
7449 if (exlen + (q - buf) > CO_MAX) {
\r
7450 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7453 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7454 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7456 savesel.cpMin -= trim;
\r
7457 savesel.cpMax -= trim;
\r
7458 if (exlen < 0) exlen = 0;
\r
7459 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7460 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7462 /* Append the new text */
\r
7463 sel.cpMin = exlen;
\r
7464 sel.cpMax = exlen;
\r
7465 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7466 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7467 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7468 if (forceVisible || exlen == 0 ||
\r
7469 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7470 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7471 /* Scroll to make new end of text visible if old end of text
\r
7472 was visible or new text is an echo of user typein */
\r
7473 sel.cpMin = 9999999;
\r
7474 sel.cpMax = 9999999;
\r
7475 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7476 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7477 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7478 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7480 if (savesel.cpMax == exlen || forceVisible) {
\r
7481 /* Move insert point to new end of text if it was at the old
\r
7482 end of text or if the new text is an echo of user typein */
\r
7483 sel.cpMin = 9999999;
\r
7484 sel.cpMax = 9999999;
\r
7485 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7487 /* Restore previous selection */
\r
7488 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7490 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7497 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7501 COLORREF oldFg, oldBg;
\r
7505 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
7507 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7508 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7509 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7512 rect.right = x + squareSize;
\r
7514 rect.bottom = y + squareSize;
\r
7517 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7518 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7519 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7520 &rect, str, strlen(str), NULL);
\r
7522 (void) SetTextColor(hdc, oldFg);
\r
7523 (void) SetBkColor(hdc, oldBg);
\r
7524 (void) SelectObject(hdc, oldFont);
\r
7528 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7529 RECT *rect, char *color, char *flagFell)
\r
7533 COLORREF oldFg, oldBg;
\r
7536 if (appData.clockMode) {
\r
7538 sprintf(buf, "%c %s %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7540 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
7547 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7548 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7550 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7551 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7553 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7555 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7556 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7557 rect, str, strlen(str), NULL);
\r
7559 (void) SetTextColor(hdc, oldFg);
\r
7560 (void) SetBkColor(hdc, oldBg);
\r
7561 (void) SelectObject(hdc, oldFont);
\r
7566 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7572 if( count <= 0 ) {
\r
7573 if (appData.debugMode) {
\r
7574 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7577 return ERROR_INVALID_USER_BUFFER;
\r
7580 ResetEvent(ovl->hEvent);
\r
7581 ovl->Offset = ovl->OffsetHigh = 0;
\r
7582 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7586 err = GetLastError();
\r
7587 if (err == ERROR_IO_PENDING) {
\r
7588 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7592 err = GetLastError();
\r
7599 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7604 ResetEvent(ovl->hEvent);
\r
7605 ovl->Offset = ovl->OffsetHigh = 0;
\r
7606 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7610 err = GetLastError();
\r
7611 if (err == ERROR_IO_PENDING) {
\r
7612 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7616 err = GetLastError();
\r
7622 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7623 void CheckForInputBufferFull( InputSource * is )
\r
7625 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7626 /* Look for end of line */
\r
7627 char * p = is->buf;
\r
7629 while( p < is->next && *p != '\n' ) {
\r
7633 if( p >= is->next ) {
\r
7634 if (appData.debugMode) {
\r
7635 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
7638 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7639 is->count = (DWORD) -1;
\r
7640 is->next = is->buf;
\r
7646 InputThread(LPVOID arg)
\r
7651 is = (InputSource *) arg;
\r
7652 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7653 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7654 while (is->hThread != NULL) {
\r
7655 is->error = DoReadFile(is->hFile, is->next,
\r
7656 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7657 &is->count, &ovl);
\r
7658 if (is->error == NO_ERROR) {
\r
7659 is->next += is->count;
\r
7661 if (is->error == ERROR_BROKEN_PIPE) {
\r
7662 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7665 is->count = (DWORD) -1;
\r
7666 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7671 CheckForInputBufferFull( is );
\r
7673 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7675 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7677 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7680 CloseHandle(ovl.hEvent);
\r
7681 CloseHandle(is->hFile);
\r
7683 if (appData.debugMode) {
\r
7684 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
7691 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7693 NonOvlInputThread(LPVOID arg)
\r
7700 is = (InputSource *) arg;
\r
7701 while (is->hThread != NULL) {
\r
7702 is->error = ReadFile(is->hFile, is->next,
\r
7703 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7704 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7705 if (is->error == NO_ERROR) {
\r
7706 /* Change CRLF to LF */
\r
7707 if (is->next > is->buf) {
\r
7709 i = is->count + 1;
\r
7717 if (prev == '\r' && *p == '\n') {
\r
7729 if (is->error == ERROR_BROKEN_PIPE) {
\r
7730 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7733 is->count = (DWORD) -1;
\r
7737 CheckForInputBufferFull( is );
\r
7739 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7741 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7743 if (is->count < 0) break; /* Quit on error */
\r
7745 CloseHandle(is->hFile);
\r
7750 SocketInputThread(LPVOID arg)
\r
7754 is = (InputSource *) arg;
\r
7755 while (is->hThread != NULL) {
\r
7756 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7757 if ((int)is->count == SOCKET_ERROR) {
\r
7758 is->count = (DWORD) -1;
\r
7759 is->error = WSAGetLastError();
\r
7761 is->error = NO_ERROR;
\r
7762 is->next += is->count;
\r
7763 if (is->count == 0 && is->second == is) {
\r
7764 /* End of file on stderr; quit with no message */
\r
7768 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7770 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7772 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7778 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7782 is = (InputSource *) lParam;
\r
7783 if (is->lineByLine) {
\r
7784 /* Feed in lines one by one */
\r
7785 char *p = is->buf;
\r
7787 while (q < is->next) {
\r
7788 if (*q++ == '\n') {
\r
7789 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7794 /* Move any partial line to the start of the buffer */
\r
7796 while (p < is->next) {
\r
7801 if (is->error != NO_ERROR || is->count == 0) {
\r
7802 /* Notify backend of the error. Note: If there was a partial
\r
7803 line at the end, it is not flushed through. */
\r
7804 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7807 /* Feed in the whole chunk of input at once */
\r
7808 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7809 is->next = is->buf;
\r
7813 /*---------------------------------------------------------------------------*\
\r
7815 * Menu enables. Used when setting various modes.
\r
7817 \*---------------------------------------------------------------------------*/
\r
7825 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7827 while (enab->item > 0) {
\r
7828 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7833 Enables gnuEnables[] = {
\r
7834 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7835 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7836 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7837 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7838 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7839 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7840 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7841 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7842 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7843 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7847 Enables icsEnables[] = {
\r
7848 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7849 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7850 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7851 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7852 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7853 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7854 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7855 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7856 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7857 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7858 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7859 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7864 Enables zippyEnables[] = {
\r
7865 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7866 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7867 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7872 Enables ncpEnables[] = {
\r
7873 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7874 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7875 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7876 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7877 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7878 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7879 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7880 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7881 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7882 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7883 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7884 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7885 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7886 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7887 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7891 Enables trainingOnEnables[] = {
\r
7892 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7893 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7894 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7895 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7896 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7897 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7898 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7899 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7903 Enables trainingOffEnables[] = {
\r
7904 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7905 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7906 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7907 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7908 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7909 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7910 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7911 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7915 /* These modify either ncpEnables or gnuEnables */
\r
7916 Enables cmailEnables[] = {
\r
7917 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7918 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7919 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7920 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7921 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7922 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7923 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7927 Enables machineThinkingEnables[] = {
\r
7928 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7929 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7930 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7931 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7932 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7933 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7934 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7935 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7936 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7937 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7938 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7939 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7940 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7941 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7942 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7946 Enables userThinkingEnables[] = {
\r
7947 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7948 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7949 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7950 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7951 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7952 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7953 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7954 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7955 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7956 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7957 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7958 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7959 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7960 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7961 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7965 /*---------------------------------------------------------------------------*\
\r
7967 * Front-end interface functions exported by XBoard.
\r
7968 * Functions appear in same order as prototypes in frontend.h.
\r
7970 \*---------------------------------------------------------------------------*/
\r
7974 static UINT prevChecked = 0;
\r
7975 static int prevPausing = 0;
\r
7978 if (pausing != prevPausing) {
\r
7979 prevPausing = pausing;
\r
7980 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7981 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
7982 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
7985 switch (gameMode) {
\r
7986 case BeginningOfGame:
\r
7987 if (appData.icsActive)
\r
7988 nowChecked = IDM_IcsClient;
\r
7989 else if (appData.noChessProgram)
\r
7990 nowChecked = IDM_EditGame;
\r
7992 nowChecked = IDM_MachineBlack;
\r
7994 case MachinePlaysBlack:
\r
7995 nowChecked = IDM_MachineBlack;
\r
7997 case MachinePlaysWhite:
\r
7998 nowChecked = IDM_MachineWhite;
\r
8000 case TwoMachinesPlay:
\r
8001 nowChecked = IDM_TwoMachines;
\r
8004 nowChecked = IDM_AnalysisMode;
\r
8007 nowChecked = IDM_AnalyzeFile;
\r
8010 nowChecked = IDM_EditGame;
\r
8012 case PlayFromGameFile:
\r
8013 nowChecked = IDM_LoadGame;
\r
8015 case EditPosition:
\r
8016 nowChecked = IDM_EditPosition;
\r
8019 nowChecked = IDM_Training;
\r
8021 case IcsPlayingWhite:
\r
8022 case IcsPlayingBlack:
\r
8023 case IcsObserving:
\r
8025 nowChecked = IDM_IcsClient;
\r
8032 if (prevChecked != 0)
\r
8033 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8034 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8035 if (nowChecked != 0)
\r
8036 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8037 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8039 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8040 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8041 MF_BYCOMMAND|MF_ENABLED);
\r
8043 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8044 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8047 prevChecked = nowChecked;
\r
8053 HMENU hmenu = GetMenu(hwndMain);
\r
8054 SetMenuEnables(hmenu, icsEnables);
\r
8055 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8056 MF_BYPOSITION|MF_ENABLED);
\r
8058 if (appData.zippyPlay) {
\r
8059 SetMenuEnables(hmenu, zippyEnables);
\r
8067 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8073 HMENU hmenu = GetMenu(hwndMain);
\r
8074 SetMenuEnables(hmenu, ncpEnables);
\r
8075 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8076 MF_BYPOSITION|MF_GRAYED);
\r
8077 DrawMenuBar(hwndMain);
\r
8083 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8087 SetTrainingModeOn()
\r
8090 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8091 for (i = 0; i < N_BUTTONS; i++) {
\r
8092 if (buttonDesc[i].hwnd != NULL)
\r
8093 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8098 VOID SetTrainingModeOff()
\r
8101 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8102 for (i = 0; i < N_BUTTONS; i++) {
\r
8103 if (buttonDesc[i].hwnd != NULL)
\r
8104 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8110 SetUserThinkingEnables()
\r
8112 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8116 SetMachineThinkingEnables()
\r
8118 HMENU hMenu = GetMenu(hwndMain);
\r
8119 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8121 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8123 if (gameMode == MachinePlaysBlack) {
\r
8124 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8125 } else if (gameMode == MachinePlaysWhite) {
\r
8126 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8127 } else if (gameMode == TwoMachinesPlay) {
\r
8128 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8134 DisplayTitle(char *str)
\r
8136 char title[MSG_SIZ], *host;
\r
8137 if (str[0] != NULLCHAR) {
\r
8138 strcpy(title, str);
\r
8139 } else if (appData.icsActive) {
\r
8140 if (appData.icsCommPort[0] != NULLCHAR)
\r
8143 host = appData.icsHost;
\r
8144 sprintf(title, "%s: %s", szTitle, host);
\r
8145 } else if (appData.noChessProgram) {
\r
8146 strcpy(title, szTitle);
\r
8148 strcpy(title, szTitle);
\r
8149 strcat(title, ": ");
\r
8150 strcat(title, first.tidy);
\r
8152 SetWindowText(hwndMain, title);
\r
8157 DisplayMessage(char *str1, char *str2)
\r
8161 int remain = MESSAGE_TEXT_MAX - 1;
\r
8164 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8165 messageText[0] = NULLCHAR;
\r
8167 len = strlen(str1);
\r
8168 if (len > remain) len = remain;
\r
8169 strncpy(messageText, str1, len);
\r
8170 messageText[len] = NULLCHAR;
\r
8173 if (*str2 && remain >= 2) {
\r
8175 strcat(messageText, " ");
\r
8178 len = strlen(str2);
\r
8179 if (len > remain) len = remain;
\r
8180 strncat(messageText, str2, len);
\r
8182 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8184 if (IsIconic(hwndMain)) return;
\r
8185 hdc = GetDC(hwndMain);
\r
8186 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8187 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8188 &messageRect, messageText, strlen(messageText), NULL);
\r
8189 (void) SelectObject(hdc, oldFont);
\r
8190 (void) ReleaseDC(hwndMain, hdc);
\r
8194 DisplayError(char *str, int error)
\r
8196 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8202 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8203 NULL, error, LANG_NEUTRAL,
\r
8204 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8206 sprintf(buf, "%s:\n%s", str, buf2);
\r
8208 ErrorMap *em = errmap;
\r
8209 while (em->err != 0 && em->err != error) em++;
\r
8210 if (em->err != 0) {
\r
8211 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8213 sprintf(buf, "%s:\nError code %d", str, error);
\r
8218 ErrorPopUp("Error", buf);
\r
8223 DisplayMoveError(char *str)
\r
8225 fromX = fromY = -1;
\r
8226 ClearHighlights();
\r
8227 DrawPosition(FALSE, NULL);
\r
8228 if (appData.popupMoveErrors) {
\r
8229 ErrorPopUp("Error", str);
\r
8231 DisplayMessage(str, "");
\r
8232 moveErrorMessageUp = TRUE;
\r
8237 DisplayFatalError(char *str, int error, int exitStatus)
\r
8239 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8241 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8244 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8245 NULL, error, LANG_NEUTRAL,
\r
8246 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8248 sprintf(buf, "%s:\n%s", str, buf2);
\r
8250 ErrorMap *em = errmap;
\r
8251 while (em->err != 0 && em->err != error) em++;
\r
8252 if (em->err != 0) {
\r
8253 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8255 sprintf(buf, "%s:\nError code %d", str, error);
\r
8260 if (appData.debugMode) {
\r
8261 fprintf(debugFP, "%s: %s\n", label, str);
\r
8263 if (appData.popupExitMessage) {
\r
8264 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8265 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8267 ExitEvent(exitStatus);
\r
8272 DisplayInformation(char *str)
\r
8274 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8279 DisplayNote(char *str)
\r
8281 ErrorPopUp("Note", str);
\r
8286 char *title, *question, *replyPrefix;
\r
8291 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8293 static QuestionParams *qp;
\r
8294 char reply[MSG_SIZ];
\r
8297 switch (message) {
\r
8298 case WM_INITDIALOG:
\r
8299 qp = (QuestionParams *) lParam;
\r
8300 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8301 SetWindowText(hDlg, qp->title);
\r
8302 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8303 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8307 switch (LOWORD(wParam)) {
\r
8309 strcpy(reply, qp->replyPrefix);
\r
8310 if (*reply) strcat(reply, " ");
\r
8311 len = strlen(reply);
\r
8312 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8313 strcat(reply, "\n");
\r
8314 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8315 EndDialog(hDlg, TRUE);
\r
8316 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8319 EndDialog(hDlg, FALSE);
\r
8330 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8332 QuestionParams qp;
\r
8336 qp.question = question;
\r
8337 qp.replyPrefix = replyPrefix;
\r
8339 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8340 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8341 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8342 FreeProcInstance(lpProc);
\r
8345 /* [AS] Pick FRC position */
\r
8346 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8348 static int * lpIndexFRC;
\r
8354 case WM_INITDIALOG:
\r
8355 lpIndexFRC = (int *) lParam;
\r
8357 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8359 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8360 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8361 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8362 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8367 switch( LOWORD(wParam) ) {
\r
8369 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8370 EndDialog( hDlg, 0 );
\r
8373 EndDialog( hDlg, 1 );
\r
8375 case IDC_NFG_Edit:
\r
8376 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8377 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8379 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8382 case IDC_NFG_Random:
\r
8383 sprintf( buf, "%d", myrandom() % 960 );
\r
8384 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8397 int index = appData.defaultFrcPosition;
\r
8398 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8400 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8402 if( result == 0 ) {
\r
8403 appData.defaultFrcPosition = index;
\r
8409 /* [AS] Game list options */
\r
8415 static GLT_Item GLT_ItemInfo[] = {
\r
8416 { GLT_EVENT, "Event" },
\r
8417 { GLT_SITE, "Site" },
\r
8418 { GLT_DATE, "Date" },
\r
8419 { GLT_ROUND, "Round" },
\r
8420 { GLT_PLAYERS, "Players" },
\r
8421 { GLT_RESULT, "Result" },
\r
8422 { GLT_WHITE_ELO, "White Rating" },
\r
8423 { GLT_BLACK_ELO, "Black Rating" },
\r
8424 { GLT_TIME_CONTROL,"Time Control" },
\r
8425 { GLT_VARIANT, "Variant" },
\r
8426 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
8430 const char * GLT_FindItem( char id )
\r
8432 const char * result = 0;
\r
8434 GLT_Item * list = GLT_ItemInfo;
\r
8436 while( list->id != 0 ) {
\r
8437 if( list->id == id ) {
\r
8438 result = list->name;
\r
8448 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
8450 const char * name = GLT_FindItem( id );
\r
8453 if( index >= 0 ) {
\r
8454 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
8457 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
8462 void GLT_TagsToList( HWND hDlg, char * tags )
\r
8466 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8469 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8473 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
8475 pc = GLT_ALL_TAGS;
\r
8478 if( strchr( tags, *pc ) == 0 ) {
\r
8479 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8484 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8487 char GLT_ListItemToTag( HWND hDlg, int index )
\r
8489 char result = '\0';
\r
8492 GLT_Item * list = GLT_ItemInfo;
\r
8494 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
8495 while( list->id != 0 ) {
\r
8496 if( strcmp( list->name, name ) == 0 ) {
\r
8497 result = list->id;
\r
8508 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8510 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8511 int idx2 = idx1 + delta;
\r
8512 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8514 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8517 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8518 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8519 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8520 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8524 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8526 static char glt[64];
\r
8527 static char * lpUserGLT;
\r
8531 case WM_INITDIALOG:
\r
8532 lpUserGLT = (char *) lParam;
\r
8534 strcpy( glt, lpUserGLT );
\r
8536 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8538 /* Initialize list */
\r
8539 GLT_TagsToList( hDlg, glt );
\r
8541 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8546 switch( LOWORD(wParam) ) {
\r
8549 char * pc = lpUserGLT;
\r
8551 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8555 id = GLT_ListItemToTag( hDlg, idx );
\r
8559 } while( id != '\0' );
\r
8561 EndDialog( hDlg, 0 );
\r
8564 EndDialog( hDlg, 1 );
\r
8567 case IDC_GLT_Default:
\r
8568 strcpy( glt, GLT_DEFAULT_TAGS );
\r
8569 GLT_TagsToList( hDlg, glt );
\r
8572 case IDC_GLT_Restore:
\r
8573 strcpy( glt, lpUserGLT );
\r
8574 GLT_TagsToList( hDlg, glt );
\r
8578 GLT_MoveSelection( hDlg, -1 );
\r
8581 case IDC_GLT_Down:
\r
8582 GLT_MoveSelection( hDlg, +1 );
\r
8592 int GameListOptions()
\r
8596 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8598 strcpy( glt, appData.gameListTags );
\r
8600 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
8602 if( result == 0 ) {
\r
8603 /* [AS] Memory leak here! */
\r
8604 appData.gameListTags = strdup( glt );
\r
8612 DisplayIcsInteractionTitle(char *str)
\r
8614 char consoleTitle[MSG_SIZ];
\r
8616 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8617 SetWindowText(hwndConsole, consoleTitle);
\r
8621 DrawPosition(int fullRedraw, Board board)
\r
8623 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8630 fromX = fromY = -1;
\r
8631 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8632 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8633 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8634 dragInfo.lastpos = dragInfo.pos;
\r
8635 dragInfo.start.x = dragInfo.start.y = -1;
\r
8636 dragInfo.from = dragInfo.start;
\r
8638 DrawPosition(TRUE, NULL);
\r
8644 CommentPopUp(char *title, char *str)
\r
8646 HWND hwnd = GetActiveWindow();
\r
8647 EitherCommentPopUp(0, title, str, FALSE);
\r
8648 SetActiveWindow(hwnd);
\r
8652 CommentPopDown(void)
\r
8654 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8655 if (commentDialog) {
\r
8656 ShowWindow(commentDialog, SW_HIDE);
\r
8658 commentDialogUp = FALSE;
\r
8662 EditCommentPopUp(int index, char *title, char *str)
\r
8664 EitherCommentPopUp(index, title, str, TRUE);
\r
8671 MyPlaySound(&sounds[(int)SoundMove]);
\r
8674 VOID PlayIcsWinSound()
\r
8676 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8679 VOID PlayIcsLossSound()
\r
8681 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8684 VOID PlayIcsDrawSound()
\r
8686 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8689 VOID PlayIcsUnfinishedSound()
\r
8691 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8697 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8705 consoleEcho = TRUE;
\r
8706 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8707 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8708 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8717 consoleEcho = FALSE;
\r
8718 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8719 /* This works OK: set text and background both to the same color */
\r
8721 cf.crTextColor = COLOR_ECHOOFF;
\r
8722 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8723 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8726 /* No Raw()...? */
\r
8728 void Colorize(ColorClass cc, int continuation)
\r
8730 currentColorClass = cc;
\r
8731 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8732 consoleCF.crTextColor = textAttribs[cc].color;
\r
8733 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8734 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8740 static char buf[MSG_SIZ];
\r
8741 DWORD bufsiz = MSG_SIZ;
\r
8743 if (!GetUserName(buf, &bufsiz)) {
\r
8744 /*DisplayError("Error getting user name", GetLastError());*/
\r
8745 strcpy(buf, "User");
\r
8753 static char buf[MSG_SIZ];
\r
8754 DWORD bufsiz = MSG_SIZ;
\r
8756 if (!GetComputerName(buf, &bufsiz)) {
\r
8757 /*DisplayError("Error getting host name", GetLastError());*/
\r
8758 strcpy(buf, "Unknown");
\r
8765 ClockTimerRunning()
\r
8767 return clockTimerEvent != 0;
\r
8773 if (clockTimerEvent == 0) return FALSE;
\r
8774 KillTimer(hwndMain, clockTimerEvent);
\r
8775 clockTimerEvent = 0;
\r
8780 StartClockTimer(long millisec)
\r
8782 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8783 (UINT) millisec, NULL);
\r
8787 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8790 hdc = GetDC(hwndMain);
\r
8791 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8793 if (!IsIconic(hwndMain)) {
\r
8794 DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &blackRect : &whiteRect, "White", flag);
\r
8796 if (highlight && iconCurrent == iconBlack) {
\r
8797 iconCurrent = iconWhite;
\r
8798 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8799 if (IsIconic(hwndMain)) {
\r
8800 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8803 (void) ReleaseDC(hwndMain, hdc);
\r
8805 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8809 DisplayBlackClock(long timeRemaining, int highlight)
\r
8812 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8814 hdc = GetDC(hwndMain);
\r
8815 if (!IsIconic(hwndMain)) {
\r
8816 DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
8818 if (highlight && iconCurrent == iconWhite) {
\r
8819 iconCurrent = iconBlack;
\r
8820 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8821 if (IsIconic(hwndMain)) {
\r
8822 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8825 (void) ReleaseDC(hwndMain, hdc);
\r
8827 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8832 LoadGameTimerRunning()
\r
8834 return loadGameTimerEvent != 0;
\r
8838 StopLoadGameTimer()
\r
8840 if (loadGameTimerEvent == 0) return FALSE;
\r
8841 KillTimer(hwndMain, loadGameTimerEvent);
\r
8842 loadGameTimerEvent = 0;
\r
8847 StartLoadGameTimer(long millisec)
\r
8849 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8850 (UINT) millisec, NULL);
\r
8858 char fileTitle[MSG_SIZ];
\r
8860 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8861 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
8862 appData.oldSaveStyle ? "gam" : "pgn",
\r
8864 "Save Game to File", NULL, fileTitle, NULL);
\r
8866 SaveGame(f, 0, "");
\r
8873 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8875 if (delayedTimerEvent != 0) {
\r
8876 if (appData.debugMode) {
\r
8877 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8879 KillTimer(hwndMain, delayedTimerEvent);
\r
8880 delayedTimerEvent = 0;
\r
8881 delayedTimerCallback();
\r
8883 delayedTimerCallback = cb;
\r
8884 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8885 (UINT) millisec, NULL);
\r
8888 DelayedEventCallback
\r
8891 if (delayedTimerEvent) {
\r
8892 return delayedTimerCallback;
\r
8899 CancelDelayedEvent()
\r
8901 if (delayedTimerEvent) {
\r
8902 KillTimer(hwndMain, delayedTimerEvent);
\r
8903 delayedTimerEvent = 0;
\r
8907 /* Start a child process running the given program.
\r
8908 The process's standard output can be read from "from", and its
\r
8909 standard input can be written to "to".
\r
8910 Exit with fatal error if anything goes wrong.
\r
8911 Returns an opaque pointer that can be used to destroy the process
\r
8915 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8917 #define BUFSIZE 4096
\r
8919 HANDLE hChildStdinRd, hChildStdinWr,
\r
8920 hChildStdoutRd, hChildStdoutWr;
\r
8921 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8922 SECURITY_ATTRIBUTES saAttr;
\r
8924 PROCESS_INFORMATION piProcInfo;
\r
8925 STARTUPINFO siStartInfo;
\r
8927 char buf[MSG_SIZ];
\r
8930 if (appData.debugMode) {
\r
8931 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8936 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8937 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8938 saAttr.bInheritHandle = TRUE;
\r
8939 saAttr.lpSecurityDescriptor = NULL;
\r
8942 * The steps for redirecting child's STDOUT:
\r
8943 * 1. Create anonymous pipe to be STDOUT for child.
\r
8944 * 2. Create a noninheritable duplicate of read handle,
\r
8945 * and close the inheritable read handle.
\r
8948 /* Create a pipe for the child's STDOUT. */
\r
8949 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8950 return GetLastError();
\r
8953 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8954 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8955 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8956 FALSE, /* not inherited */
\r
8957 DUPLICATE_SAME_ACCESS);
\r
8959 return GetLastError();
\r
8961 CloseHandle(hChildStdoutRd);
\r
8964 * The steps for redirecting child's STDIN:
\r
8965 * 1. Create anonymous pipe to be STDIN for child.
\r
8966 * 2. Create a noninheritable duplicate of write handle,
\r
8967 * and close the inheritable write handle.
\r
8970 /* Create a pipe for the child's STDIN. */
\r
8971 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8972 return GetLastError();
\r
8975 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8976 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8977 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8978 FALSE, /* not inherited */
\r
8979 DUPLICATE_SAME_ACCESS);
\r
8981 return GetLastError();
\r
8983 CloseHandle(hChildStdinWr);
\r
8985 /* Arrange to (1) look in dir for the child .exe file, and
\r
8986 * (2) have dir be the child's working directory. Interpret
\r
8987 * dir relative to the directory WinBoard loaded from. */
\r
8988 GetCurrentDirectory(MSG_SIZ, buf);
\r
8989 SetCurrentDirectory(installDir);
\r
8990 SetCurrentDirectory(dir);
\r
8992 /* Now create the child process. */
\r
8994 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8995 siStartInfo.lpReserved = NULL;
\r
8996 siStartInfo.lpDesktop = NULL;
\r
8997 siStartInfo.lpTitle = NULL;
\r
8998 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8999 siStartInfo.cbReserved2 = 0;
\r
9000 siStartInfo.lpReserved2 = NULL;
\r
9001 siStartInfo.hStdInput = hChildStdinRd;
\r
9002 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9003 siStartInfo.hStdError = hChildStdoutWr;
\r
9005 fSuccess = CreateProcess(NULL,
\r
9006 cmdLine, /* command line */
\r
9007 NULL, /* process security attributes */
\r
9008 NULL, /* primary thread security attrs */
\r
9009 TRUE, /* handles are inherited */
\r
9010 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9011 NULL, /* use parent's environment */
\r
9013 &siStartInfo, /* STARTUPINFO pointer */
\r
9014 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9016 err = GetLastError();
\r
9017 SetCurrentDirectory(buf); /* return to prev directory */
\r
9022 /* Close the handles we don't need in the parent */
\r
9023 CloseHandle(piProcInfo.hThread);
\r
9024 CloseHandle(hChildStdinRd);
\r
9025 CloseHandle(hChildStdoutWr);
\r
9027 /* Prepare return value */
\r
9028 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9029 cp->kind = CPReal;
\r
9030 cp->hProcess = piProcInfo.hProcess;
\r
9031 cp->pid = piProcInfo.dwProcessId;
\r
9032 cp->hFrom = hChildStdoutRdDup;
\r
9033 cp->hTo = hChildStdinWrDup;
\r
9035 *pr = (void *) cp;
\r
9037 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9038 2000 where engines sometimes don't see the initial command(s)
\r
9039 from WinBoard and hang. I don't understand how that can happen,
\r
9040 but the Sleep is harmless, so I've put it in. Others have also
\r
9041 reported what may be the same problem, so hopefully this will fix
\r
9042 it for them too. */
\r
9050 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9054 cp = (ChildProc *) pr;
\r
9055 if (cp == NULL) return;
\r
9057 switch (cp->kind) {
\r
9059 /* TerminateProcess is considered harmful, so... */
\r
9060 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9061 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9062 /* The following doesn't work because the chess program
\r
9063 doesn't "have the same console" as WinBoard. Maybe
\r
9064 we could arrange for this even though neither WinBoard
\r
9065 nor the chess program uses a console for stdio? */
\r
9066 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9068 /* [AS] Special termination modes for misbehaving programs... */
\r
9069 if( signal == 9 ) {
\r
9070 if ( appData.debugMode) {
\r
9071 fprintf( debugFP, "Terminating process %u\n", cp->pid );
\r
9074 TerminateProcess( cp->hProcess, 0 );
\r
9076 else if( signal == 10 ) {
\r
9077 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9079 if( dw != WAIT_OBJECT_0 ) {
\r
9080 if ( appData.debugMode) {
\r
9081 fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
\r
9084 TerminateProcess( cp->hProcess, 0 );
\r
9088 CloseHandle(cp->hProcess);
\r
9092 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9096 closesocket(cp->sock);
\r
9101 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9102 closesocket(cp->sock);
\r
9103 closesocket(cp->sock2);
\r
9111 InterruptChildProcess(ProcRef pr)
\r
9115 cp = (ChildProc *) pr;
\r
9116 if (cp == NULL) return;
\r
9117 switch (cp->kind) {
\r
9119 /* The following doesn't work because the chess program
\r
9120 doesn't "have the same console" as WinBoard. Maybe
\r
9121 we could arrange for this even though neither WinBoard
\r
9122 nor the chess program uses a console for stdio */
\r
9123 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9128 /* Can't interrupt */
\r
9132 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9139 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9141 char cmdLine[MSG_SIZ];
\r
9143 if (port[0] == NULLCHAR) {
\r
9144 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9146 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9148 return StartChildProcess(cmdLine, "", pr);
\r
9152 /* Code to open TCP sockets */
\r
9155 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9160 struct sockaddr_in sa, mysa;
\r
9161 struct hostent FAR *hp;
\r
9162 unsigned short uport;
\r
9163 WORD wVersionRequested;
\r
9166 /* Initialize socket DLL */
\r
9167 wVersionRequested = MAKEWORD(1, 1);
\r
9168 err = WSAStartup(wVersionRequested, &wsaData);
\r
9169 if (err != 0) return err;
\r
9172 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9173 err = WSAGetLastError();
\r
9178 /* Bind local address using (mostly) don't-care values.
\r
9180 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9181 mysa.sin_family = AF_INET;
\r
9182 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9183 uport = (unsigned short) 0;
\r
9184 mysa.sin_port = htons(uport);
\r
9185 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9186 == SOCKET_ERROR) {
\r
9187 err = WSAGetLastError();
\r
9192 /* Resolve remote host name */
\r
9193 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9194 if (!(hp = gethostbyname(host))) {
\r
9195 unsigned int b0, b1, b2, b3;
\r
9197 err = WSAGetLastError();
\r
9199 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9200 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9201 hp->h_addrtype = AF_INET;
\r
9203 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9204 hp->h_addr_list[0] = (char *) malloc(4);
\r
9205 hp->h_addr_list[0][0] = (char) b0;
\r
9206 hp->h_addr_list[0][1] = (char) b1;
\r
9207 hp->h_addr_list[0][2] = (char) b2;
\r
9208 hp->h_addr_list[0][3] = (char) b3;
\r
9214 sa.sin_family = hp->h_addrtype;
\r
9215 uport = (unsigned short) atoi(port);
\r
9216 sa.sin_port = htons(uport);
\r
9217 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9219 /* Make connection */
\r
9220 if (connect(s, (struct sockaddr *) &sa,
\r
9221 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9222 err = WSAGetLastError();
\r
9227 /* Prepare return value */
\r
9228 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9229 cp->kind = CPSock;
\r
9231 *pr = (ProcRef *) cp;
\r
9237 OpenCommPort(char *name, ProcRef *pr)
\r
9242 char fullname[MSG_SIZ];
\r
9244 if (*name != '\\')
\r
9245 sprintf(fullname, "\\\\.\\%s", name);
\r
9247 strcpy(fullname, name);
\r
9249 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9250 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9251 if (h == (HANDLE) -1) {
\r
9252 return GetLastError();
\r
9256 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9258 /* Accumulate characters until a 100ms pause, then parse */
\r
9259 ct.ReadIntervalTimeout = 100;
\r
9260 ct.ReadTotalTimeoutMultiplier = 0;
\r
9261 ct.ReadTotalTimeoutConstant = 0;
\r
9262 ct.WriteTotalTimeoutMultiplier = 0;
\r
9263 ct.WriteTotalTimeoutConstant = 0;
\r
9264 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9266 /* Prepare return value */
\r
9267 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9268 cp->kind = CPComm;
\r
9271 *pr = (ProcRef *) cp;
\r
9277 OpenLoopback(ProcRef *pr)
\r
9279 DisplayFatalError("Not implemented", 0, 1);
\r
9285 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9290 struct sockaddr_in sa, mysa;
\r
9291 struct hostent FAR *hp;
\r
9292 unsigned short uport;
\r
9293 WORD wVersionRequested;
\r
9296 char stderrPortStr[MSG_SIZ];
\r
9298 /* Initialize socket DLL */
\r
9299 wVersionRequested = MAKEWORD(1, 1);
\r
9300 err = WSAStartup(wVersionRequested, &wsaData);
\r
9301 if (err != 0) return err;
\r
9303 /* Resolve remote host name */
\r
9304 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9305 if (!(hp = gethostbyname(host))) {
\r
9306 unsigned int b0, b1, b2, b3;
\r
9308 err = WSAGetLastError();
\r
9310 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9311 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9312 hp->h_addrtype = AF_INET;
\r
9314 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9315 hp->h_addr_list[0] = (char *) malloc(4);
\r
9316 hp->h_addr_list[0][0] = (char) b0;
\r
9317 hp->h_addr_list[0][1] = (char) b1;
\r
9318 hp->h_addr_list[0][2] = (char) b2;
\r
9319 hp->h_addr_list[0][3] = (char) b3;
\r
9325 sa.sin_family = hp->h_addrtype;
\r
9326 uport = (unsigned short) 514;
\r
9327 sa.sin_port = htons(uport);
\r
9328 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9330 /* Bind local socket to unused "privileged" port address
\r
9332 s = INVALID_SOCKET;
\r
9333 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9334 mysa.sin_family = AF_INET;
\r
9335 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9336 for (fromPort = 1023;; fromPort--) {
\r
9337 if (fromPort < 0) {
\r
9339 return WSAEADDRINUSE;
\r
9341 if (s == INVALID_SOCKET) {
\r
9342 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9343 err = WSAGetLastError();
\r
9348 uport = (unsigned short) fromPort;
\r
9349 mysa.sin_port = htons(uport);
\r
9350 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9351 == SOCKET_ERROR) {
\r
9352 err = WSAGetLastError();
\r
9353 if (err == WSAEADDRINUSE) continue;
\r
9357 if (connect(s, (struct sockaddr *) &sa,
\r
9358 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9359 err = WSAGetLastError();
\r
9360 if (err == WSAEADDRINUSE) {
\r
9371 /* Bind stderr local socket to unused "privileged" port address
\r
9373 s2 = INVALID_SOCKET;
\r
9374 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9375 mysa.sin_family = AF_INET;
\r
9376 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9377 for (fromPort = 1023;; fromPort--) {
\r
9378 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9379 if (fromPort < 0) {
\r
9380 (void) closesocket(s);
\r
9382 return WSAEADDRINUSE;
\r
9384 if (s2 == INVALID_SOCKET) {
\r
9385 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9386 err = WSAGetLastError();
\r
9392 uport = (unsigned short) fromPort;
\r
9393 mysa.sin_port = htons(uport);
\r
9394 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9395 == SOCKET_ERROR) {
\r
9396 err = WSAGetLastError();
\r
9397 if (err == WSAEADDRINUSE) continue;
\r
9398 (void) closesocket(s);
\r
9402 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9403 err = WSAGetLastError();
\r
9404 if (err == WSAEADDRINUSE) {
\r
9406 s2 = INVALID_SOCKET;
\r
9409 (void) closesocket(s);
\r
9410 (void) closesocket(s2);
\r
9416 prevStderrPort = fromPort; // remember port used
\r
9417 sprintf(stderrPortStr, "%d", fromPort);
\r
9419 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9420 err = WSAGetLastError();
\r
9421 (void) closesocket(s);
\r
9422 (void) closesocket(s2);
\r
9427 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9428 err = WSAGetLastError();
\r
9429 (void) closesocket(s);
\r
9430 (void) closesocket(s2);
\r
9434 if (*user == NULLCHAR) user = UserName();
\r
9435 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9436 err = WSAGetLastError();
\r
9437 (void) closesocket(s);
\r
9438 (void) closesocket(s2);
\r
9442 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9443 err = WSAGetLastError();
\r
9444 (void) closesocket(s);
\r
9445 (void) closesocket(s2);
\r
9450 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9451 err = WSAGetLastError();
\r
9452 (void) closesocket(s);
\r
9453 (void) closesocket(s2);
\r
9457 (void) closesocket(s2); /* Stop listening */
\r
9459 /* Prepare return value */
\r
9460 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9461 cp->kind = CPRcmd;
\r
9464 *pr = (ProcRef *) cp;
\r
9471 AddInputSource(ProcRef pr, int lineByLine,
\r
9472 InputCallback func, VOIDSTAR closure)
\r
9474 InputSource *is, *is2 = NULL;
\r
9475 ChildProc *cp = (ChildProc *) pr;
\r
9477 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9478 is->lineByLine = lineByLine;
\r
9480 is->closure = closure;
\r
9481 is->second = NULL;
\r
9482 is->next = is->buf;
\r
9483 if (pr == NoProc) {
\r
9484 is->kind = CPReal;
\r
9485 consoleInputSource = is;
\r
9487 is->kind = cp->kind;
\r
9489 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9490 we create all threads suspended so that the is->hThread variable can be
\r
9491 safely assigned, then let the threads start with ResumeThread.
\r
9493 switch (cp->kind) {
\r
9495 is->hFile = cp->hFrom;
\r
9496 cp->hFrom = NULL; /* now owned by InputThread */
\r
9498 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9499 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9503 is->hFile = cp->hFrom;
\r
9504 cp->hFrom = NULL; /* now owned by InputThread */
\r
9506 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9507 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9511 is->sock = cp->sock;
\r
9513 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9514 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9518 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9520 is->sock = cp->sock;
\r
9522 is2->sock = cp->sock2;
\r
9523 is2->second = is2;
\r
9525 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9526 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9528 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9529 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9533 if( is->hThread != NULL ) {
\r
9534 ResumeThread( is->hThread );
\r
9537 if( is2 != NULL && is2->hThread != NULL ) {
\r
9538 ResumeThread( is2->hThread );
\r
9542 return (InputSourceRef) is;
\r
9546 RemoveInputSource(InputSourceRef isr)
\r
9550 is = (InputSource *) isr;
\r
9551 is->hThread = NULL; /* tell thread to stop */
\r
9552 CloseHandle(is->hThread);
\r
9553 if (is->second != NULL) {
\r
9554 is->second->hThread = NULL;
\r
9555 CloseHandle(is->second->hThread);
\r
9561 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9564 int outCount = SOCKET_ERROR;
\r
9565 ChildProc *cp = (ChildProc *) pr;
\r
9566 static OVERLAPPED ovl;
\r
9568 if (pr == NoProc) {
\r
9569 ConsoleOutput(message, count, FALSE);
\r
9573 if (ovl.hEvent == NULL) {
\r
9574 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9576 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9578 switch (cp->kind) {
\r
9581 outCount = send(cp->sock, message, count, 0);
\r
9582 if (outCount == SOCKET_ERROR) {
\r
9583 *outError = WSAGetLastError();
\r
9585 *outError = NO_ERROR;
\r
9590 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9591 &dOutCount, NULL)) {
\r
9592 *outError = NO_ERROR;
\r
9593 outCount = (int) dOutCount;
\r
9595 *outError = GetLastError();
\r
9600 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9601 &dOutCount, &ovl);
\r
9602 if (*outError == NO_ERROR) {
\r
9603 outCount = (int) dOutCount;
\r
9611 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9614 /* Ignore delay, not implemented for WinBoard */
\r
9615 return OutputToProcess(pr, message, count, outError);
\r
9620 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9621 char *buf, int count, int error)
\r
9623 DisplayFatalError("Not implemented", 0, 1);
\r
9626 /* see wgamelist.c for Game List functions */
\r
9627 /* see wedittags.c for Edit Tags functions */
\r
9634 char buf[MSG_SIZ];
\r
9637 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9638 f = fopen(buf, "r");
\r
9640 ProcessICSInitScript(f);
\r
9648 StartAnalysisClock()
\r
9650 if (analysisTimerEvent) return;
\r
9651 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9652 (UINT) 2000, NULL);
\r
9656 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9658 static HANDLE hwndText;
\r
9660 static int sizeX, sizeY;
\r
9661 int newSizeX, newSizeY, flags;
\r
9664 switch (message) {
\r
9665 case WM_INITDIALOG: /* message: initialize dialog box */
\r
9666 /* Initialize the dialog items */
\r
9667 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
9668 SetWindowText(hDlg, analysisTitle);
\r
9669 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
9670 /* Size and position the dialog */
\r
9671 if (!analysisDialog) {
\r
9672 analysisDialog = hDlg;
\r
9673 flags = SWP_NOZORDER;
\r
9674 GetClientRect(hDlg, &rect);
\r
9675 sizeX = rect.right;
\r
9676 sizeY = rect.bottom;
\r
9677 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
9678 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
9679 WINDOWPLACEMENT wp;
\r
9680 EnsureOnScreen(&analysisX, &analysisY);
\r
9681 wp.length = sizeof(WINDOWPLACEMENT);
\r
9683 wp.showCmd = SW_SHOW;
\r
9684 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
9685 wp.rcNormalPosition.left = analysisX;
\r
9686 wp.rcNormalPosition.right = analysisX + analysisW;
\r
9687 wp.rcNormalPosition.top = analysisY;
\r
9688 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
9689 SetWindowPlacement(hDlg, &wp);
\r
9691 GetClientRect(hDlg, &rect);
\r
9692 newSizeX = rect.right;
\r
9693 newSizeY = rect.bottom;
\r
9694 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
9695 newSizeX, newSizeY);
\r
9702 case WM_COMMAND: /* message: received a command */
\r
9703 switch (LOWORD(wParam)) {
\r
9713 newSizeX = LOWORD(lParam);
\r
9714 newSizeY = HIWORD(lParam);
\r
9715 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
9720 case WM_GETMINMAXINFO:
\r
9721 /* Prevent resizing window too small */
\r
9722 mmi = (MINMAXINFO *) lParam;
\r
9723 mmi->ptMinTrackSize.x = 100;
\r
9724 mmi->ptMinTrackSize.y = 100;
\r
9731 AnalysisPopUp(char* title, char* str)
\r
9737 EngineOutputPopUp();
\r
9740 if (str == NULL) str = "";
\r
9741 p = (char *) malloc(2 * strlen(str) + 2);
\r
9744 if (*str == '\n') *q++ = '\r';
\r
9748 if (analysisText != NULL) free(analysisText);
\r
9751 if (analysisDialog) {
\r
9752 SetWindowText(analysisDialog, title);
\r
9753 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
9754 ShowWindow(analysisDialog, SW_SHOW);
\r
9756 analysisTitle = title;
\r
9757 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
9758 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
9759 hwndMain, (DLGPROC)lpProc);
\r
9760 FreeProcInstance(lpProc);
\r
9762 analysisDialogUp = TRUE;
\r
9768 if (analysisDialog) {
\r
9769 ShowWindow(analysisDialog, SW_HIDE);
\r
9771 analysisDialogUp = FALSE;
\r
9776 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9778 highlightInfo.sq[0].x = fromX;
\r
9779 highlightInfo.sq[0].y = fromY;
\r
9780 highlightInfo.sq[1].x = toX;
\r
9781 highlightInfo.sq[1].y = toY;
\r
9787 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9788 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9792 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9794 premoveHighlightInfo.sq[0].x = fromX;
\r
9795 premoveHighlightInfo.sq[0].y = fromY;
\r
9796 premoveHighlightInfo.sq[1].x = toX;
\r
9797 premoveHighlightInfo.sq[1].y = toY;
\r
9801 ClearPremoveHighlights()
\r
9803 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9804 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9808 ShutDownFrontEnd()
\r
9810 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9811 DeleteClipboardTempFiles();
\r
9817 if (IsIconic(hwndMain))
\r
9818 ShowWindow(hwndMain, SW_RESTORE);
\r
9820 SetActiveWindow(hwndMain);
\r
9824 * Prototypes for animation support routines
\r
9826 static void ScreenSquare(int column, int row, POINT * pt);
\r
9827 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9828 POINT frames[], int * nFrames);
\r
9834 AnimateMove(board, fromX, fromY, toX, toY)
\r
9841 ChessSquare piece;
\r
9842 POINT start, finish, mid;
\r
9843 POINT frames[kFactor * 2 + 1];
\r
9846 if (!appData.animate) return;
\r
9847 if (doingSizing) return;
\r
9848 if (fromY < 0 || fromX < 0) return;
\r
9849 piece = board[fromY][fromX];
\r
9850 if (piece >= EmptySquare) return;
\r
9852 ScreenSquare(fromX, fromY, &start);
\r
9853 ScreenSquare(toX, toY, &finish);
\r
9855 /* All pieces except knights move in straight line */
\r
9856 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9857 mid.x = start.x + (finish.x - start.x) / 2;
\r
9858 mid.y = start.y + (finish.y - start.y) / 2;
\r
9860 /* Knight: make diagonal movement then straight */
\r
9861 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9862 mid.x = start.x + (finish.x - start.x) / 2;
\r
9866 mid.y = start.y + (finish.y - start.y) / 2;
\r
9870 /* Don't use as many frames for very short moves */
\r
9871 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9872 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9874 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9876 animInfo.from.x = fromX;
\r
9877 animInfo.from.y = fromY;
\r
9878 animInfo.to.x = toX;
\r
9879 animInfo.to.y = toY;
\r
9880 animInfo.lastpos = start;
\r
9881 animInfo.piece = piece;
\r
9882 for (n = 0; n < nFrames; n++) {
\r
9883 animInfo.pos = frames[n];
\r
9884 DrawPosition(FALSE, NULL);
\r
9885 animInfo.lastpos = animInfo.pos;
\r
9886 Sleep(appData.animSpeed);
\r
9888 animInfo.pos = finish;
\r
9889 DrawPosition(FALSE, NULL);
\r
9890 animInfo.piece = EmptySquare;
\r
9893 /* Convert board position to corner of screen rect and color */
\r
9896 ScreenSquare(column, row, pt)
\r
9897 int column; int row; POINT * pt;
\r
9900 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
9901 pt->y = lineGap + row * (squareSize + lineGap);
\r
9903 pt->x = lineGap + column * (squareSize + lineGap);
\r
9904 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
9908 /* Generate a series of frame coords from start->mid->finish.
\r
9909 The movement rate doubles until the half way point is
\r
9910 reached, then halves back down to the final destination,
\r
9911 which gives a nice slow in/out effect. The algorithmn
\r
9912 may seem to generate too many intermediates for short
\r
9913 moves, but remember that the purpose is to attract the
\r
9914 viewers attention to the piece about to be moved and
\r
9915 then to where it ends up. Too few frames would be less
\r
9919 Tween(start, mid, finish, factor, frames, nFrames)
\r
9920 POINT * start; POINT * mid;
\r
9921 POINT * finish; int factor;
\r
9922 POINT frames[]; int * nFrames;
\r
9924 int n, fraction = 1, count = 0;
\r
9926 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9927 for (n = 0; n < factor; n++)
\r
9929 for (n = 0; n < factor; n++) {
\r
9930 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9931 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9933 fraction = fraction / 2;
\r
9937 frames[count] = *mid;
\r
9940 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9942 for (n = 0; n < factor; n++) {
\r
9943 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9944 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9946 fraction = fraction * 2;
\r
9952 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
9957 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
9958 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
9960 OutputDebugString( buf );
\r
9963 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
9965 EvalGraphSet( first, last, current, pvInfoList );
\r
9968 void SetProgramStats( FrontEndProgramStats * stats )
\r
9973 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
9974 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
9976 OutputDebugString( buf );
\r
9979 EngineOutputUpdate( stats );
\r