2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
145 #include <X11/Intrinsic.h>
146 #include <X11/StringDefs.h>
147 #include <X11/Shell.h>
148 #include <X11/cursorfont.h>
149 #include <X11/Xatom.h>
150 #include <X11/Xmu/Atoms.h>
152 #include <X11/Xaw3d/Dialog.h>
153 #include <X11/Xaw3d/Form.h>
154 #include <X11/Xaw3d/List.h>
155 #include <X11/Xaw3d/Label.h>
156 #include <X11/Xaw3d/SimpleMenu.h>
157 #include <X11/Xaw3d/SmeBSB.h>
158 #include <X11/Xaw3d/SmeLine.h>
159 #include <X11/Xaw3d/Box.h>
160 #include <X11/Xaw3d/MenuButton.h>
161 #include <X11/Xaw3d/Text.h>
162 #include <X11/Xaw3d/AsciiText.h>
164 #include <X11/Xaw/Dialog.h>
165 #include <X11/Xaw/Form.h>
166 #include <X11/Xaw/List.h>
167 #include <X11/Xaw/Label.h>
168 #include <X11/Xaw/SimpleMenu.h>
169 #include <X11/Xaw/SmeBSB.h>
170 #include <X11/Xaw/SmeLine.h>
171 #include <X11/Xaw/Box.h>
172 #include <X11/Xaw/MenuButton.h>
173 #include <X11/Xaw/Text.h>
174 #include <X11/Xaw/AsciiText.h>
177 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
182 #include "pixmaps/pixmaps.h"
183 #define IMAGE_EXT "xpm"
185 #define IMAGE_EXT "xim"
186 #include "bitmaps/bitmaps.h"
189 #include "bitmaps/icon_white.bm"
190 #include "bitmaps/icon_black.bm"
191 #include "bitmaps/checkmark.bm"
193 #include "frontend.h"
195 #include "backendz.h"
199 #include "xgamelist.h"
200 #include "xhistory.h"
201 #include "xedittags.h"
204 // must be moved to xengineoutput.h
206 void EngineOutputProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
208 void EvalGraphProc P((Widget w, XEvent *event,
209 String *prms, Cardinal *nprms));
216 #define usleep(t) _sleep2(((t)+500)/1000)
220 # define _(s) gettext (s)
221 # define N_(s) gettext_noop (s)
239 int main P((int argc, char **argv));
240 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
241 char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
242 RETSIGTYPE CmailSigHandler P((int sig));
243 RETSIGTYPE IntSigHandler P((int sig));
244 RETSIGTYPE TermSizeSigHandler P((int sig));
245 void CreateGCs P((int redo));
246 void CreateXIMPieces P((void));
247 void CreateXPMPieces P((void));
248 void CreateXPMBoard P((char *s, int n));
249 void CreatePieces P((void));
250 void CreatePieceMenus P((void));
251 Widget CreateMenuBar P((Menu *mb));
252 Widget CreateButtonBar P ((MenuItem *mi));
253 char *FindFont P((char *pattern, int targetPxlSize));
254 void PieceMenuPopup P((Widget w, XEvent *event,
255 String *params, Cardinal *num_params));
256 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
258 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
259 u_int wreq, u_int hreq));
260 void CreateGrid P((void));
261 int EventToSquare P((int x, int limit));
262 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
263 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
264 void HandleUserMove P((Widget w, XEvent *event,
265 String *prms, Cardinal *nprms));
266 void AnimateUserMove P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void HandlePV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void SelectPV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void StopPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void WhiteClock P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void BlackClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void DrawPositionProc P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
282 void CommentClick P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void CommentPopUp P((char *title, char *label));
285 void CommentPopDown P((void));
286 void ICSInputBoxPopUp P((void));
287 void ICSInputBoxPopDown P((void));
288 void FileNamePopUp P((char *label, char *def, char *filter,
289 FileProc proc, char *openMode));
290 void FileNamePopDown P((void));
291 void FileNameCallback P((Widget w, XtPointer client_data,
292 XtPointer call_data));
293 void FileNameAction P((Widget w, XEvent *event,
294 String *prms, Cardinal *nprms));
295 void AskQuestionReplyAction P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionProc P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionPopDown P((void));
300 void PromotionPopDown P((void));
301 void PromotionCallback P((Widget w, XtPointer client_data,
302 XtPointer call_data));
303 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
304 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
305 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
306 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
308 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
310 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
312 void LoadPositionProc P((Widget w, XEvent *event,
313 String *prms, Cardinal *nprms));
314 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
316 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
318 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
320 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
322 void PastePositionProc P((Widget w, XEvent *event, String *prms,
324 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void SavePositionProc P((Widget w, XEvent *event,
328 String *prms, Cardinal *nprms));
329 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
332 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
336 void MachineWhiteProc P((Widget w, XEvent *event,
337 String *prms, Cardinal *nprms));
338 void AnalyzeModeProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AnalyzeFileProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
344 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void IcsClientProc P((Widget w, XEvent *event, String *prms,
348 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void EditPositionProc P((Widget w, XEvent *event,
350 String *prms, Cardinal *nprms));
351 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void EditCommentProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void IcsInputBoxProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void StopObservingProc P((Widget w, XEvent *event, String *prms,
372 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
374 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
383 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
385 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
388 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
390 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
392 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
397 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
400 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
402 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
404 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
409 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
411 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
413 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
415 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
418 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
420 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
422 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
424 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void DisplayMove P((int moveNumber));
436 void DisplayTitle P((char *title));
437 void ICSInitScript P((void));
438 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
439 void ErrorPopUp P((char *title, char *text, int modal));
440 void ErrorPopDown P((void));
441 static char *ExpandPathName P((char *path));
442 static void CreateAnimVars P((void));
443 static void DragPieceMove P((int x, int y));
444 static void DrawDragPiece P((void));
445 char *ModeToWidgetName P((GameMode mode));
446 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void GameListOptionsPopDown P(());
462 void ShufflePopDown P(());
463 void TimeControlPopDown P(());
464 void GenericPopDown P(());
465 void update_ics_width P(());
466 int get_term_width P(());
467 int CopyMemoProc P(());
468 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
469 Boolean IsDrawArrowEnabled P(());
472 * XBoard depends on Xt R4 or higher
474 int xtVersion = XtSpecificationRelease;
479 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
480 jailSquareColor, highlightSquareColor, premoveHighlightColor;
481 Pixel lowTimeWarningColor;
482 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
483 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
484 wjPieceGC, bjPieceGC, prelineGC, countGC;
485 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
486 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
487 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
488 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
489 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
490 ICSInputShell, fileNameShell, askQuestionShell;
491 Widget historyShell, evalGraphShell, gameListShell;
492 int hOffset; // [HGM] dual
493 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
494 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
495 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
496 Font clockFontID, coordFontID, countFontID;
497 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
498 XtAppContext appContext;
500 char *oldICSInteractionTitle;
504 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
506 Position commentX = -1, commentY = -1;
507 Dimension commentW, commentH;
508 typedef unsigned int BoardSize;
510 Boolean chessProgram;
512 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
513 int squareSize, smallLayout = 0, tinyLayout = 0,
514 marginW, marginH, // [HGM] for run-time resizing
515 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
516 ICSInputBoxUp = False, askQuestionUp = False,
517 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
518 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
519 Pixel timerForegroundPixel, timerBackgroundPixel;
520 Pixel buttonForegroundPixel, buttonBackgroundPixel;
521 char *chessDir, *programName, *programVersion,
522 *gameCopyFilename, *gamePasteFilename;
523 Boolean alwaysOnTop = False;
524 Boolean saveSettingsOnExit;
525 char *settingsFileName;
526 char *icsTextMenuString;
528 char *firstChessProgramNames;
529 char *secondChessProgramNames;
531 WindowPlacement wpMain;
532 WindowPlacement wpConsole;
533 WindowPlacement wpComment;
534 WindowPlacement wpMoveHistory;
535 WindowPlacement wpEvalGraph;
536 WindowPlacement wpEngineOutput;
537 WindowPlacement wpGameList;
538 WindowPlacement wpTags;
540 extern Widget shells[];
541 extern Boolean shellUp[];
545 Pixmap pieceBitmap[2][(int)BlackPawn];
546 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
547 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
548 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
549 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
550 Pixmap xpmBoardBitmap[2];
551 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
552 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
553 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
554 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
555 XImage *ximLightSquare, *ximDarkSquare;
558 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
559 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
561 #define White(piece) ((int)(piece) < (int)BlackPawn)
563 /* Variables for doing smooth animation. This whole thing
564 would be much easier if the board was double-buffered,
565 but that would require a fairly major rewrite. */
570 GC blitGC, pieceGC, outlineGC;
571 XPoint startSquare, prevFrame, mouseDelta;
575 int startBoardX, startBoardY;
578 /* There can be two pieces being animated at once: a player
579 can begin dragging a piece before the remote opponent has moved. */
581 static AnimState game, player;
583 /* Bitmaps for use as masks when drawing XPM pieces.
584 Need one for each black and white piece. */
585 static Pixmap xpmMask[BlackKing + 1];
587 /* This magic number is the number of intermediate frames used
588 in each half of the animation. For short moves it's reduced
589 by 1. The total number of frames will be factor * 2 + 1. */
592 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
594 MenuItem fileMenu[] = {
595 {N_("New Game Ctrl+N"), "New Game", ResetProc},
596 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
597 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
598 {"----", NULL, NothingProc},
599 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
600 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
601 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
602 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
603 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
604 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
605 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
606 {"----", NULL, NothingProc},
607 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
608 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
609 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
610 {"----", NULL, NothingProc},
611 {N_("Mail Move"), "Mail Move", MailMoveProc},
612 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
613 {"----", NULL, NothingProc},
614 {N_("Quit Ctr+Q"), "Exit", QuitProc},
618 MenuItem editMenu[] = {
619 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
620 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
621 {"----", NULL, NothingProc},
622 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
623 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
624 {"----", NULL, NothingProc},
625 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
626 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
627 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
628 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
629 {"----", NULL, NothingProc},
630 {N_("Revert Home"), "Revert", RevertProc},
631 {N_("Annotate"), "Annotate", AnnotateProc},
632 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
633 {"----", NULL, NothingProc},
634 {N_("Backward Alt+Left"), "Backward", BackwardProc},
635 {N_("Forward Alt+Right"), "Forward", ForwardProc},
636 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
637 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
641 MenuItem viewMenu[] = {
642 {N_("Flip View F2"), "Flip View", FlipViewProc},
643 {"----", NULL, NothingProc},
644 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
645 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
646 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
647 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
648 {N_("ICS text menu"), "ICStex", IcsTextProc},
649 {"----", NULL, NothingProc},
650 {N_("Tags"), "Show Tags", EditTagsProc},
651 {N_("Comments"), "Show Comments", EditCommentProc},
652 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
653 {"----", NULL, NothingProc},
654 {N_("Board..."), "Board Options", BoardOptionsProc},
655 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
659 MenuItem modeMenu[] = {
660 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
661 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
662 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
663 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
664 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
665 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
666 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
667 {N_("Training"), "Training", TrainingProc},
668 {N_("ICS Client"), "ICS Client", IcsClientProc},
669 {"----", NULL, NothingProc},
670 {N_("Machine Match"), "Machine Match", MatchProc},
671 {N_("Pause Pause"), "Pause", PauseProc},
675 MenuItem actionMenu[] = {
676 {N_("Accept F3"), "Accept", AcceptProc},
677 {N_("Decline F4"), "Decline", DeclineProc},
678 {N_("Rematch F12"), "Rematch", RematchProc},
679 {"----", NULL, NothingProc},
680 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
681 {N_("Draw F6"), "Draw", DrawProc},
682 {N_("Adjourn F7"), "Adjourn", AdjournProc},
683 {N_("Abort F8"),"Abort", AbortProc},
684 {N_("Resign F9"), "Resign", ResignProc},
685 {"----", NULL, NothingProc},
686 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
687 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
688 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
689 {"----", NULL, NothingProc},
690 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
691 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
692 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
696 MenuItem engineMenu[] = {
697 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
698 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
699 {"----", NULL, NothingProc},
700 {N_("Hint"), "Hint", HintProc},
701 {N_("Book"), "Book", BookProc},
702 {"----", NULL, NothingProc},
703 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
704 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
708 MenuItem optionsMenu[] = {
709 #define OPTIONSDIALOG
711 {N_("General ..."), "General", OptionsProc},
713 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
714 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
715 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
716 {N_("ICS ..."), "ICS", IcsOptionsProc},
717 {N_("Match ..."), "Match", MatchOptionsProc},
718 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
719 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
720 // {N_(" ..."), "", OptionsProc},
721 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
722 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
723 {"----", NULL, NothingProc},
724 #ifndef OPTIONSDIALOG
725 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
726 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
727 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
728 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
729 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
730 {N_("Blindfold"), "Blindfold", BlindfoldProc},
731 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
733 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
735 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
736 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
737 {N_("Move Sound"), "Move Sound", MoveSoundProc},
738 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
739 {N_("One-Click Moving"), "OneClick", OneClickProc},
740 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
741 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
742 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
743 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
744 // {N_("Premove"), "Premove", PremoveProc},
745 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
746 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
747 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
748 {"----", NULL, NothingProc},
750 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
751 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
755 MenuItem helpMenu[] = {
756 {N_("Info XBoard"), "Info XBoard", InfoProc},
757 {N_("Man XBoard F1"), "Man XBoard", ManProc},
758 {"----", NULL, NothingProc},
759 {N_("About XBoard"), "About XBoard", AboutProc},
764 {N_("File"), "File", fileMenu},
765 {N_("Edit"), "Edit", editMenu},
766 {N_("View"), "View", viewMenu},
767 {N_("Mode"), "Mode", modeMenu},
768 {N_("Action"), "Action", actionMenu},
769 {N_("Engine"), "Engine", engineMenu},
770 {N_("Options"), "Options", optionsMenu},
771 {N_("Help"), "Help", helpMenu},
775 #define PAUSE_BUTTON "P"
776 MenuItem buttonBar[] = {
777 {"<<", "<<", ToStartProc},
778 {"<", "<", BackwardProc},
779 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
780 {">", ">", ForwardProc},
781 {">>", ">>", ToEndProc},
785 #define PIECE_MENU_SIZE 18
786 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
787 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
788 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
789 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
790 N_("Empty square"), N_("Clear board") },
791 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
792 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
793 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
794 N_("Empty square"), N_("Clear board") }
796 /* must be in same order as PieceMenuStrings! */
797 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
798 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
799 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
800 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
801 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
802 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
803 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
804 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
805 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
808 #define DROP_MENU_SIZE 6
809 String dropMenuStrings[DROP_MENU_SIZE] = {
810 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
812 /* must be in same order as PieceMenuStrings! */
813 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
814 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
815 WhiteRook, WhiteQueen
823 DropMenuEnables dmEnables[] = {
841 { XtNborderWidth, 0 },
842 { XtNdefaultDistance, 0 },
846 { XtNborderWidth, 0 },
847 { XtNresizable, (XtArgVal) True },
851 { XtNborderWidth, 0 },
857 { XtNjustify, (XtArgVal) XtJustifyRight },
858 { XtNlabel, (XtArgVal) "..." },
859 { XtNresizable, (XtArgVal) True },
860 { XtNresize, (XtArgVal) False }
863 Arg messageArgs[] = {
864 { XtNjustify, (XtArgVal) XtJustifyLeft },
865 { XtNlabel, (XtArgVal) "..." },
866 { XtNresizable, (XtArgVal) True },
867 { XtNresize, (XtArgVal) False }
871 { XtNborderWidth, 0 },
872 { XtNjustify, (XtArgVal) XtJustifyLeft }
875 XtResource clientResources[] = {
876 { "flashCount", "flashCount", XtRInt, sizeof(int),
877 XtOffset(AppDataPtr, flashCount), XtRImmediate,
878 (XtPointer) FLASH_COUNT },
881 XrmOptionDescRec shellOptions[] = {
882 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
883 { "-flash", "flashCount", XrmoptionNoArg, "3" },
884 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
887 XtActionsRec boardActions[] = {
888 { "DrawPosition", DrawPositionProc },
889 { "HandleUserMove", HandleUserMove },
890 { "AnimateUserMove", AnimateUserMove },
891 { "HandlePV", HandlePV },
892 { "SelectPV", SelectPV },
893 { "StopPV", StopPV },
894 { "FileNameAction", FileNameAction },
895 { "AskQuestionProc", AskQuestionProc },
896 { "AskQuestionReplyAction", AskQuestionReplyAction },
897 { "PieceMenuPopup", PieceMenuPopup },
898 { "WhiteClock", WhiteClock },
899 { "BlackClock", BlackClock },
900 { "Iconify", Iconify },
901 { "ResetProc", ResetProc },
902 { "NewVariantProc", NewVariantProc },
903 { "LoadGameProc", LoadGameProc },
904 { "LoadNextGameProc", LoadNextGameProc },
905 { "LoadPrevGameProc", LoadPrevGameProc },
906 { "LoadSelectedProc", LoadSelectedProc },
907 { "SetFilterProc", SetFilterProc },
908 { "ReloadGameProc", ReloadGameProc },
909 { "LoadPositionProc", LoadPositionProc },
910 { "LoadNextPositionProc", LoadNextPositionProc },
911 { "LoadPrevPositionProc", LoadPrevPositionProc },
912 { "ReloadPositionProc", ReloadPositionProc },
913 { "CopyPositionProc", CopyPositionProc },
914 { "PastePositionProc", PastePositionProc },
915 { "CopyGameProc", CopyGameProc },
916 { "PasteGameProc", PasteGameProc },
917 { "SaveGameProc", SaveGameProc },
918 { "SavePositionProc", SavePositionProc },
919 { "MailMoveProc", MailMoveProc },
920 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
921 { "QuitProc", QuitProc },
922 { "MachineWhiteProc", MachineWhiteProc },
923 { "MachineBlackProc", MachineBlackProc },
924 { "AnalysisModeProc", AnalyzeModeProc },
925 { "AnalyzeFileProc", AnalyzeFileProc },
926 { "TwoMachinesProc", TwoMachinesProc },
927 { "IcsClientProc", IcsClientProc },
928 { "EditGameProc", EditGameProc },
929 { "EditPositionProc", EditPositionProc },
930 { "TrainingProc", EditPositionProc },
931 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
932 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
933 { "ShowGameListProc", ShowGameListProc },
934 { "ShowMoveListProc", HistoryShowProc},
935 { "EditTagsProc", EditCommentProc },
936 { "EditCommentProc", EditCommentProc },
937 { "IcsInputBoxProc", IcsInputBoxProc },
938 { "PauseProc", PauseProc },
939 { "AcceptProc", AcceptProc },
940 { "DeclineProc", DeclineProc },
941 { "RematchProc", RematchProc },
942 { "CallFlagProc", CallFlagProc },
943 { "DrawProc", DrawProc },
944 { "AdjournProc", AdjournProc },
945 { "AbortProc", AbortProc },
946 { "ResignProc", ResignProc },
947 { "AdjuWhiteProc", AdjuWhiteProc },
948 { "AdjuBlackProc", AdjuBlackProc },
949 { "AdjuDrawProc", AdjuDrawProc },
950 { "EnterKeyProc", EnterKeyProc },
951 { "UpKeyProc", UpKeyProc },
952 { "DownKeyProc", DownKeyProc },
953 { "StopObservingProc", StopObservingProc },
954 { "StopExaminingProc", StopExaminingProc },
955 { "UploadProc", UploadProc },
956 { "BackwardProc", BackwardProc },
957 { "ForwardProc", ForwardProc },
958 { "ToStartProc", ToStartProc },
959 { "ToEndProc", ToEndProc },
960 { "RevertProc", RevertProc },
961 { "AnnotateProc", AnnotateProc },
962 { "TruncateGameProc", TruncateGameProc },
963 { "MoveNowProc", MoveNowProc },
964 { "RetractMoveProc", RetractMoveProc },
965 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
966 { "UciMenuProc", (XtActionProc) UciMenuProc },
967 { "TimeControlProc", (XtActionProc) TimeControlProc },
968 { "FlipViewProc", FlipViewProc },
969 { "PonderNextMoveProc", PonderNextMoveProc },
970 #ifndef OPTIONSDIALOG
971 { "AlwaysQueenProc", AlwaysQueenProc },
972 { "AnimateDraggingProc", AnimateDraggingProc },
973 { "AnimateMovingProc", AnimateMovingProc },
974 { "AutoflagProc", AutoflagProc },
975 { "AutoflipProc", AutoflipProc },
976 { "BlindfoldProc", BlindfoldProc },
977 { "FlashMovesProc", FlashMovesProc },
979 { "HighlightDraggingProc", HighlightDraggingProc },
981 { "HighlightLastMoveProc", HighlightLastMoveProc },
982 // { "IcsAlarmProc", IcsAlarmProc },
983 { "MoveSoundProc", MoveSoundProc },
984 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
985 { "PopupExitMessageProc", PopupExitMessageProc },
986 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
987 // { "PremoveProc", PremoveProc },
988 { "ShowCoordsProc", ShowCoordsProc },
989 { "ShowThinkingProc", ShowThinkingProc },
990 { "HideThinkingProc", HideThinkingProc },
991 { "TestLegalityProc", TestLegalityProc },
993 { "SaveSettingsProc", SaveSettingsProc },
994 { "SaveOnExitProc", SaveOnExitProc },
995 { "InfoProc", InfoProc },
996 { "ManProc", ManProc },
997 { "HintProc", HintProc },
998 { "BookProc", BookProc },
999 { "AboutGameProc", AboutGameProc },
1000 { "AboutProc", AboutProc },
1001 { "DebugProc", DebugProc },
1002 { "NothingProc", NothingProc },
1003 { "CommentClick", (XtActionProc) CommentClick },
1004 { "CommentPopDown", (XtActionProc) CommentPopDown },
1005 { "TagsPopDown", (XtActionProc) TagsPopDown },
1006 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1007 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1008 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1009 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1010 { "GameListPopDown", (XtActionProc) GameListPopDown },
1011 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1012 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1013 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1014 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1015 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1016 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1017 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1018 { "GenericPopDown", (XtActionProc) GenericPopDown },
1019 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1022 char globalTranslations[] =
1023 ":<Key>F9: ResignProc() \n \
1024 :Ctrl<Key>n: ResetProc() \n \
1025 :Meta<Key>V: NewVariantProc() \n \
1026 :Ctrl<Key>o: LoadGameProc() \n \
1027 :Meta<Key>Next: LoadNextGameProc() \n \
1028 :Meta<Key>Prior: LoadPrevGameProc() \n \
1029 :Ctrl<Key>s: SaveGameProc() \n \
1030 :Ctrl<Key>c: CopyGameProc() \n \
1031 :Ctrl<Key>v: PasteGameProc() \n \
1032 :Ctrl<Key>O: LoadPositionProc() \n \
1033 :Shift<Key>Next: LoadNextPositionProc() \n \
1034 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1035 :Ctrl<Key>S: SavePositionProc() \n \
1036 :Ctrl<Key>C: CopyPositionProc() \n \
1037 :Ctrl<Key>V: PastePositionProc() \n \
1038 :Ctrl<Key>q: QuitProc() \n \
1039 :Ctrl<Key>w: MachineWhiteProc() \n \
1040 :Ctrl<Key>b: MachineBlackProc() \n \
1041 :Ctrl<Key>t: TwoMachinesProc() \n \
1042 :Ctrl<Key>a: AnalysisModeProc() \n \
1043 :Ctrl<Key>f: AnalyzeFileProc() \n \
1044 :Ctrl<Key>e: EditGameProc() \n \
1045 :Ctrl<Key>E: EditPositionProc() \n \
1046 :Meta<Key>O: EngineOutputProc() \n \
1047 :Meta<Key>E: EvalGraphProc() \n \
1048 :Meta<Key>G: ShowGameListProc() \n \
1049 :Meta<Key>H: ShowMoveListProc() \n \
1050 :<Key>Pause: PauseProc() \n \
1051 :<Key>F3: AcceptProc() \n \
1052 :<Key>F4: DeclineProc() \n \
1053 :<Key>F12: RematchProc() \n \
1054 :<Key>F5: CallFlagProc() \n \
1055 :<Key>F6: DrawProc() \n \
1056 :<Key>F7: AdjournProc() \n \
1057 :<Key>F8: AbortProc() \n \
1058 :<Key>F10: StopObservingProc() \n \
1059 :<Key>F11: StopExaminingProc() \n \
1060 :Meta Ctrl<Key>F12: DebugProc() \n \
1061 :Meta<Key>End: ToEndProc() \n \
1062 :Meta<Key>Right: ForwardProc() \n \
1063 :Meta<Key>Home: ToStartProc() \n \
1064 :Meta<Key>Left: BackwardProc() \n \
1065 :<Key>Home: RevertProc() \n \
1066 :<Key>End: TruncateGameProc() \n \
1067 :Ctrl<Key>m: MoveNowProc() \n \
1068 :Ctrl<Key>x: RetractMoveProc() \n \
1069 :Meta<Key>J: EngineMenuProc() \n \
1070 :Meta<Key>U: UciMenuProc() \n \
1071 :Meta<Key>T: TimeControlProc() \n \
1072 :Ctrl<Key>P: PonderNextMoveProc() \n "
1073 #ifndef OPTIONSDIALOG
1075 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1076 :Ctrl<Key>F: AutoflagProc() \n \
1077 :Ctrl<Key>A: AnimateMovingProc() \n \
1078 :Ctrl<Key>L: TestLegalityProc() \n \
1079 :Ctrl<Key>H: HideThinkingProc() \n "
1082 :<Key>-: Iconify() \n \
1083 :<Key>F1: ManProc() \n \
1084 :<Key>F2: FlipViewProc() \n \
1085 <KeyDown>.: BackwardProc() \n \
1086 <KeyUp>.: ForwardProc() \n \
1087 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1088 \"Send to chess program:\",,1) \n \
1089 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1090 \"Send to second chess program:\",,2) \n";
1092 char boardTranslations[] =
1093 "<Btn1Down>: HandleUserMove(0) \n \
1094 Shift<Btn1Up>: HandleUserMove(1) \n \
1095 <Btn1Up>: HandleUserMove(0) \n \
1096 <Btn1Motion>: AnimateUserMove() \n \
1097 <Btn3Motion>: HandlePV() \n \
1098 <Btn3Up>: PieceMenuPopup(menuB) \n \
1099 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1100 PieceMenuPopup(menuB) \n \
1101 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1102 PieceMenuPopup(menuW) \n \
1103 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1104 PieceMenuPopup(menuW) \n \
1105 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1106 PieceMenuPopup(menuB) \n";
1108 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1109 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1111 char ICSInputTranslations[] =
1112 "<Key>Up: UpKeyProc() \n "
1113 "<Key>Down: DownKeyProc() \n "
1114 "<Key>Return: EnterKeyProc() \n";
1116 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1117 // as the widget is destroyed before the up-click can call extend-end
1118 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1120 String xboardResources[] = {
1121 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1122 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1123 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1128 /* Max possible square size */
1129 #define MAXSQSIZE 256
1131 static int xpm_avail[MAXSQSIZE];
1133 #ifdef HAVE_DIR_STRUCT
1135 /* Extract piece size from filename */
1137 xpm_getsize(name, len, ext)
1148 if ((p=strchr(name, '.')) == NULL ||
1149 StrCaseCmp(p+1, ext) != 0)
1155 while (*p && isdigit(*p))
1162 /* Setup xpm_avail */
1164 xpm_getavail(dirname, ext)
1172 for (i=0; i<MAXSQSIZE; ++i)
1175 if (appData.debugMode)
1176 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1178 dir = opendir(dirname);
1181 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1182 programName, dirname);
1186 while ((ent=readdir(dir)) != NULL) {
1187 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1188 if (i > 0 && i < MAXSQSIZE)
1198 xpm_print_avail(fp, ext)
1204 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1205 for (i=1; i<MAXSQSIZE; ++i) {
1211 /* Return XPM piecesize closest to size */
1213 xpm_closest_to(dirname, size, ext)
1219 int sm_diff = MAXSQSIZE;
1223 xpm_getavail(dirname, ext);
1225 if (appData.debugMode)
1226 xpm_print_avail(stderr, ext);
1228 for (i=1; i<MAXSQSIZE; ++i) {
1231 diff = (diff<0) ? -diff : diff;
1232 if (diff < sm_diff) {
1240 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1246 #else /* !HAVE_DIR_STRUCT */
1247 /* If we are on a system without a DIR struct, we can't
1248 read the directory, so we can't collect a list of
1249 filenames, etc., so we can't do any size-fitting. */
1251 xpm_closest_to(dirname, size, ext)
1256 fprintf(stderr, _("\
1257 Warning: No DIR structure found on this system --\n\
1258 Unable to autosize for XPM/XIM pieces.\n\
1259 Please report this error to frankm@hiwaay.net.\n\
1260 Include system type & operating system in message.\n"));
1263 #endif /* HAVE_DIR_STRUCT */
1265 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1266 "magenta", "cyan", "white" };
1270 TextColors textColors[(int)NColorClasses];
1272 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1274 parse_color(str, which)
1278 char *p, buf[100], *d;
1281 if (strlen(str) > 99) /* watch bounds on buf */
1286 for (i=0; i<which; ++i) {
1293 /* Could be looking at something like:
1295 .. in which case we want to stop on a comma also */
1296 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1300 return -1; /* Use default for empty field */
1303 if (which == 2 || isdigit(*p))
1306 while (*p && isalpha(*p))
1311 for (i=0; i<8; ++i) {
1312 if (!StrCaseCmp(buf, cnames[i]))
1313 return which? (i+40) : (i+30);
1315 if (!StrCaseCmp(buf, "default")) return -1;
1317 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1322 parse_cpair(cc, str)
1326 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1327 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1332 /* bg and attr are optional */
1333 textColors[(int)cc].bg = parse_color(str, 1);
1334 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1335 textColors[(int)cc].attr = 0;
1341 /* Arrange to catch delete-window events */
1342 Atom wm_delete_window;
1344 CatchDeleteWindow(Widget w, String procname)
1347 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1348 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1349 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1356 XtSetArg(args[0], XtNiconic, False);
1357 XtSetValues(shellWidget, args, 1);
1359 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1362 //---------------------------------------------------------------------------------------------------------
1363 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1366 #define CW_USEDEFAULT (1<<31)
1367 #define ICS_TEXT_MENU_SIZE 90
1368 #define DEBUG_FILE "xboard.debug"
1369 #define SetCurrentDirectory chdir
1370 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1374 // these two must some day move to frontend.h, when they are implemented
1375 Boolean GameListIsUp();
1377 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1380 // front-end part of option handling
1382 // [HGM] This platform-dependent table provides the location for storing the color info
1383 extern char *crWhite, * crBlack;
1387 &appData.whitePieceColor,
1388 &appData.blackPieceColor,
1389 &appData.lightSquareColor,
1390 &appData.darkSquareColor,
1391 &appData.highlightSquareColor,
1392 &appData.premoveHighlightColor,
1393 &appData.lowTimeWarningColor,
1404 // [HGM] font: keep a font for each square size, even non-stndard ones
1405 #define NUM_SIZES 18
1406 #define MAX_SIZE 130
1407 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1408 char *fontTable[NUM_FONTS][MAX_SIZE];
1411 ParseFont(char *name, int number)
1412 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1414 if(sscanf(name, "size%d:", &size)) {
1415 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1416 // defer processing it until we know if it matches our board size
1417 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1418 fontTable[number][size] = strdup(strchr(name, ':')+1);
1419 fontValid[number][size] = True;
1424 case 0: // CLOCK_FONT
1425 appData.clockFont = strdup(name);
1427 case 1: // MESSAGE_FONT
1428 appData.font = strdup(name);
1430 case 2: // COORD_FONT
1431 appData.coordFont = strdup(name);
1436 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1441 { // only 2 fonts currently
1442 appData.clockFont = CLOCK_FONT_NAME;
1443 appData.coordFont = COORD_FONT_NAME;
1444 appData.font = DEFAULT_FONT_NAME;
1449 { // no-op, until we identify the code for this already in XBoard and move it here
1453 ParseColor(int n, char *name)
1454 { // in XBoard, just copy the color-name string
1455 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1459 ParseTextAttribs(ColorClass cc, char *s)
1461 (&appData.colorShout)[cc] = strdup(s);
1465 ParseBoardSize(void *addr, char *name)
1467 appData.boardSize = strdup(name);
1472 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1476 SetCommPortDefaults()
1477 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1480 // [HGM] args: these three cases taken out to stay in front-end
1482 SaveFontArg(FILE *f, ArgDescriptor *ad)
1485 int i, n = (int)(intptr_t)ad->argLoc;
1487 case 0: // CLOCK_FONT
1488 name = appData.clockFont;
1490 case 1: // MESSAGE_FONT
1491 name = appData.font;
1493 case 2: // COORD_FONT
1494 name = appData.coordFont;
1499 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1500 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1501 fontTable[n][squareSize] = strdup(name);
1502 fontValid[n][squareSize] = True;
1505 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1506 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1511 { // nothing to do, as the sounds are at all times represented by their text-string names already
1515 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1516 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1517 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1521 SaveColor(FILE *f, ArgDescriptor *ad)
1522 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1523 if(colorVariable[(int)(intptr_t)ad->argLoc])
1524 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1528 SaveBoardSize(FILE *f, char *name, void *addr)
1529 { // wrapper to shield back-end from BoardSize & sizeInfo
1530 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1534 ParseCommPortSettings(char *s)
1535 { // no such option in XBoard (yet)
1538 extern Widget engineOutputShell;
1541 GetActualPlacement(Widget wg, WindowPlacement *wp)
1551 XtSetArg(args[i], XtNx, &x); i++;
1552 XtSetArg(args[i], XtNy, &y); i++;
1553 XtSetArg(args[i], XtNwidth, &w); i++;
1554 XtSetArg(args[i], XtNheight, &h); i++;
1555 XtGetValues(wg, args, i);
1564 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1565 // In XBoard this will have to wait until awareness of window parameters is implemented
1566 GetActualPlacement(shellWidget, &wpMain);
1567 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1568 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1569 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1570 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1571 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1572 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1576 PrintCommPortSettings(FILE *f, char *name)
1577 { // This option does not exist in XBoard
1581 MySearchPath(char *installDir, char *name, char *fullname)
1582 { // just append installDir and name. Perhaps ExpandPath should be used here?
1583 name = ExpandPathName(name);
1584 if(name && name[0] == '/')
1585 safeStrCpy(fullname, name, MSG_SIZ );
1587 sprintf(fullname, "%s%c%s", installDir, '/', name);
1593 MyGetFullPathName(char *name, char *fullname)
1594 { // should use ExpandPath?
1595 name = ExpandPathName(name);
1596 safeStrCpy(fullname, name, MSG_SIZ );
1601 EnsureOnScreen(int *x, int *y, int minX, int minY)
1608 { // [HGM] args: allows testing if main window is realized from back-end
1609 return xBoardWindow != 0;
1613 PopUpStartupDialog()
1614 { // start menu not implemented in XBoard
1618 ConvertToLine(int argc, char **argv)
1620 static char line[128*1024], buf[1024];
1624 for(i=1; i<argc; i++)
1626 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1627 && argv[i][0] != '{' )
1628 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1630 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1631 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1634 line[strlen(line)-1] = NULLCHAR;
1638 //--------------------------------------------------------------------------------------------
1640 extern Boolean twoBoards, partnerUp;
1643 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1645 #define BoardSize int
1646 void InitDrawingSizes(BoardSize boardSize, int flags)
1647 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1648 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1650 XtGeometryResult gres;
1653 if(!formWidget) return;
1656 * Enable shell resizing.
1658 shellArgs[0].value = (XtArgVal) &w;
1659 shellArgs[1].value = (XtArgVal) &h;
1660 XtGetValues(shellWidget, shellArgs, 2);
1662 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1663 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1664 XtSetValues(shellWidget, &shellArgs[2], 4);
1666 XtSetArg(args[0], XtNdefaultDistance, &sep);
1667 XtGetValues(formWidget, args, 1);
1669 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1670 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1671 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1673 hOffset = boardWidth + 10;
1674 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1675 secondSegments[i] = gridSegments[i];
1676 secondSegments[i].x1 += hOffset;
1677 secondSegments[i].x2 += hOffset;
1680 XtSetArg(args[0], XtNwidth, boardWidth);
1681 XtSetArg(args[1], XtNheight, boardHeight);
1682 XtSetValues(boardWidget, args, 2);
1684 timerWidth = (boardWidth - sep) / 2;
1685 XtSetArg(args[0], XtNwidth, timerWidth);
1686 XtSetValues(whiteTimerWidget, args, 1);
1687 XtSetValues(blackTimerWidget, args, 1);
1689 XawFormDoLayout(formWidget, False);
1691 if (appData.titleInWindow) {
1693 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1694 XtSetArg(args[i], XtNheight, &h); i++;
1695 XtGetValues(titleWidget, args, i);
1697 w = boardWidth - 2*bor;
1699 XtSetArg(args[0], XtNwidth, &w);
1700 XtGetValues(menuBarWidget, args, 1);
1701 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1704 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1705 if (gres != XtGeometryYes && appData.debugMode) {
1707 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1708 programName, gres, w, h, wr, hr);
1712 XawFormDoLayout(formWidget, True);
1715 * Inhibit shell resizing.
1717 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1718 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1719 shellArgs[4].value = shellArgs[2].value = w;
1720 shellArgs[5].value = shellArgs[3].value = h;
1721 XtSetValues(shellWidget, &shellArgs[0], 6);
1723 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1726 for(i=0; i<4; i++) {
1728 for(p=0; p<=(int)WhiteKing; p++)
1729 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1730 if(gameInfo.variant == VariantShogi) {
1731 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1732 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1733 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1734 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1735 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1738 if(gameInfo.variant == VariantGothic) {
1739 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1742 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1743 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1744 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1747 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1748 for(p=0; p<=(int)WhiteKing; p++)
1749 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1750 if(gameInfo.variant == VariantShogi) {
1751 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1752 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1753 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1754 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1755 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1758 if(gameInfo.variant == VariantGothic) {
1759 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1762 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1763 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1764 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1769 for(i=0; i<2; i++) {
1771 for(p=0; p<=(int)WhiteKing; p++)
1772 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1773 if(gameInfo.variant == VariantShogi) {
1774 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1775 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1776 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1777 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1778 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1781 if(gameInfo.variant == VariantGothic) {
1782 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1785 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1786 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1787 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1797 void ParseIcsTextColors()
1798 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1799 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1800 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1801 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1802 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1803 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1804 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1805 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1806 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1807 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1808 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1810 if (appData.colorize) {
1812 _("%s: can't parse color names; disabling colorization\n"),
1815 appData.colorize = FALSE;
1820 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1821 XrmValue vFrom, vTo;
1822 int forceMono = False;
1824 if (!appData.monoMode) {
1825 vFrom.addr = (caddr_t) appData.lightSquareColor;
1826 vFrom.size = strlen(appData.lightSquareColor);
1827 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1828 if (vTo.addr == NULL) {
1829 appData.monoMode = True;
1832 lightSquareColor = *(Pixel *) vTo.addr;
1835 if (!appData.monoMode) {
1836 vFrom.addr = (caddr_t) appData.darkSquareColor;
1837 vFrom.size = strlen(appData.darkSquareColor);
1838 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1839 if (vTo.addr == NULL) {
1840 appData.monoMode = True;
1843 darkSquareColor = *(Pixel *) vTo.addr;
1846 if (!appData.monoMode) {
1847 vFrom.addr = (caddr_t) appData.whitePieceColor;
1848 vFrom.size = strlen(appData.whitePieceColor);
1849 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1850 if (vTo.addr == NULL) {
1851 appData.monoMode = True;
1854 whitePieceColor = *(Pixel *) vTo.addr;
1857 if (!appData.monoMode) {
1858 vFrom.addr = (caddr_t) appData.blackPieceColor;
1859 vFrom.size = strlen(appData.blackPieceColor);
1860 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1861 if (vTo.addr == NULL) {
1862 appData.monoMode = True;
1865 blackPieceColor = *(Pixel *) vTo.addr;
1869 if (!appData.monoMode) {
1870 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1871 vFrom.size = strlen(appData.highlightSquareColor);
1872 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1873 if (vTo.addr == NULL) {
1874 appData.monoMode = True;
1877 highlightSquareColor = *(Pixel *) vTo.addr;
1881 if (!appData.monoMode) {
1882 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1883 vFrom.size = strlen(appData.premoveHighlightColor);
1884 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1885 if (vTo.addr == NULL) {
1886 appData.monoMode = True;
1889 premoveHighlightColor = *(Pixel *) vTo.addr;
1900 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1901 XSetWindowAttributes window_attributes;
1903 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1904 XrmValue vFrom, vTo;
1905 XtGeometryResult gres;
1908 int forceMono = False;
1910 srandom(time(0)); // [HGM] book: make random truly random
1912 setbuf(stdout, NULL);
1913 setbuf(stderr, NULL);
1916 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1917 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1921 programName = strrchr(argv[0], '/');
1922 if (programName == NULL)
1923 programName = argv[0];
1928 XtSetLanguageProc(NULL, NULL, NULL);
1929 bindtextdomain(PACKAGE, LOCALEDIR);
1930 textdomain(PACKAGE);
1934 XtAppInitialize(&appContext, "XBoard", shellOptions,
1935 XtNumber(shellOptions),
1936 &argc, argv, xboardResources, NULL, 0);
1937 appData.boardSize = "";
1938 InitAppData(ConvertToLine(argc, argv));
1940 if (p == NULL) p = "/tmp";
1941 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1942 gameCopyFilename = (char*) malloc(i);
1943 gamePasteFilename = (char*) malloc(i);
1944 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1945 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1947 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1948 clientResources, XtNumber(clientResources),
1951 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1952 static char buf[MSG_SIZ];
1953 EscapeExpand(buf, appData.initString);
1954 appData.initString = strdup(buf);
1955 EscapeExpand(buf, appData.secondInitString);
1956 appData.secondInitString = strdup(buf);
1957 EscapeExpand(buf, appData.firstComputerString);
1958 appData.firstComputerString = strdup(buf);
1959 EscapeExpand(buf, appData.secondComputerString);
1960 appData.secondComputerString = strdup(buf);
1963 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1966 if (chdir(chessDir) != 0) {
1967 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1973 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1974 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1975 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1976 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1979 setbuf(debugFP, NULL);
1982 /* [HGM,HR] make sure board size is acceptable */
1983 if(appData.NrFiles > BOARD_FILES ||
1984 appData.NrRanks > BOARD_RANKS )
1985 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1988 /* This feature does not work; animation needs a rewrite */
1989 appData.highlightDragging = FALSE;
1993 xDisplay = XtDisplay(shellWidget);
1994 xScreen = DefaultScreen(xDisplay);
1995 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1997 gameInfo.variant = StringToVariant(appData.variant);
1998 InitPosition(FALSE);
2001 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2003 if (isdigit(appData.boardSize[0])) {
2004 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2005 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2006 &fontPxlSize, &smallLayout, &tinyLayout);
2008 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2009 programName, appData.boardSize);
2013 /* Find some defaults; use the nearest known size */
2014 SizeDefaults *szd, *nearest;
2015 int distance = 99999;
2016 nearest = szd = sizeDefaults;
2017 while (szd->name != NULL) {
2018 if (abs(szd->squareSize - squareSize) < distance) {
2020 distance = abs(szd->squareSize - squareSize);
2021 if (distance == 0) break;
2025 if (i < 2) lineGap = nearest->lineGap;
2026 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2027 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2028 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2029 if (i < 6) smallLayout = nearest->smallLayout;
2030 if (i < 7) tinyLayout = nearest->tinyLayout;
2033 SizeDefaults *szd = sizeDefaults;
2034 if (*appData.boardSize == NULLCHAR) {
2035 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2036 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2039 if (szd->name == NULL) szd--;
2040 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2042 while (szd->name != NULL &&
2043 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2044 if (szd->name == NULL) {
2045 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2046 programName, appData.boardSize);
2050 squareSize = szd->squareSize;
2051 lineGap = szd->lineGap;
2052 clockFontPxlSize = szd->clockFontPxlSize;
2053 coordFontPxlSize = szd->coordFontPxlSize;
2054 fontPxlSize = szd->fontPxlSize;
2055 smallLayout = szd->smallLayout;
2056 tinyLayout = szd->tinyLayout;
2057 // [HGM] font: use defaults from settings file if available and not overruled
2059 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2060 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2061 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2062 appData.font = fontTable[MESSAGE_FONT][squareSize];
2063 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2064 appData.coordFont = fontTable[COORD_FONT][squareSize];
2066 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2067 if (strlen(appData.pixmapDirectory) > 0) {
2068 p = ExpandPathName(appData.pixmapDirectory);
2070 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2071 appData.pixmapDirectory);
2074 if (appData.debugMode) {
2075 fprintf(stderr, _("\
2076 XBoard square size (hint): %d\n\
2077 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2079 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2080 if (appData.debugMode) {
2081 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2084 defaultLineGap = lineGap;
2085 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2087 /* [HR] height treated separately (hacked) */
2088 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2089 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2090 if (appData.showJail == 1) {
2091 /* Jail on top and bottom */
2092 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2093 XtSetArg(boardArgs[2], XtNheight,
2094 boardHeight + 2*(lineGap + squareSize));
2095 } else if (appData.showJail == 2) {
2097 XtSetArg(boardArgs[1], XtNwidth,
2098 boardWidth + 2*(lineGap + squareSize));
2099 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2102 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2103 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2107 * Determine what fonts to use.
2109 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2110 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2111 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2112 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2113 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2114 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2115 appData.font = FindFont(appData.font, fontPxlSize);
2116 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2117 countFontStruct = XQueryFont(xDisplay, countFontID);
2118 // appData.font = FindFont(appData.font, fontPxlSize);
2120 xdb = XtDatabase(xDisplay);
2121 XrmPutStringResource(&xdb, "*font", appData.font);
2124 * Detect if there are not enough colors available and adapt.
2126 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2127 appData.monoMode = True;
2130 forceMono = MakeColors();
2133 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2136 if (appData.bitmapDirectory == NULL ||
2137 appData.bitmapDirectory[0] == NULLCHAR)
2138 appData.bitmapDirectory = DEF_BITMAP_DIR;
2141 if (appData.lowTimeWarning && !appData.monoMode) {
2142 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2143 vFrom.size = strlen(appData.lowTimeWarningColor);
2144 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2145 if (vTo.addr == NULL)
2146 appData.monoMode = True;
2148 lowTimeWarningColor = *(Pixel *) vTo.addr;
2151 if (appData.monoMode && appData.debugMode) {
2152 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2153 (unsigned long) XWhitePixel(xDisplay, xScreen),
2154 (unsigned long) XBlackPixel(xDisplay, xScreen));
2157 ParseIcsTextColors();
2158 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2159 textColors[ColorNone].attr = 0;
2161 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2167 layoutName = "tinyLayout";
2168 } else if (smallLayout) {
2169 layoutName = "smallLayout";
2171 layoutName = "normalLayout";
2173 /* Outer layoutWidget is there only to provide a name for use in
2174 resources that depend on the layout style */
2176 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2177 layoutArgs, XtNumber(layoutArgs));
2179 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2180 formArgs, XtNumber(formArgs));
2181 XtSetArg(args[0], XtNdefaultDistance, &sep);
2182 XtGetValues(formWidget, args, 1);
2185 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2186 XtSetArg(args[0], XtNtop, XtChainTop);
2187 XtSetArg(args[1], XtNbottom, XtChainTop);
2188 XtSetArg(args[2], XtNright, XtChainLeft);
2189 XtSetValues(menuBarWidget, args, 3);
2191 widgetList[j++] = whiteTimerWidget =
2192 XtCreateWidget("whiteTime", labelWidgetClass,
2193 formWidget, timerArgs, XtNumber(timerArgs));
2194 XtSetArg(args[0], XtNfont, clockFontStruct);
2195 XtSetArg(args[1], XtNtop, XtChainTop);
2196 XtSetArg(args[2], XtNbottom, XtChainTop);
2197 XtSetValues(whiteTimerWidget, args, 3);
2199 widgetList[j++] = blackTimerWidget =
2200 XtCreateWidget("blackTime", labelWidgetClass,
2201 formWidget, timerArgs, XtNumber(timerArgs));
2202 XtSetArg(args[0], XtNfont, clockFontStruct);
2203 XtSetArg(args[1], XtNtop, XtChainTop);
2204 XtSetArg(args[2], XtNbottom, XtChainTop);
2205 XtSetValues(blackTimerWidget, args, 3);
2207 if (appData.titleInWindow) {
2208 widgetList[j++] = titleWidget =
2209 XtCreateWidget("title", labelWidgetClass, formWidget,
2210 titleArgs, XtNumber(titleArgs));
2211 XtSetArg(args[0], XtNtop, XtChainTop);
2212 XtSetArg(args[1], XtNbottom, XtChainTop);
2213 XtSetValues(titleWidget, args, 2);
2216 if (appData.showButtonBar) {
2217 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2218 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2219 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2220 XtSetArg(args[2], XtNtop, XtChainTop);
2221 XtSetArg(args[3], XtNbottom, XtChainTop);
2222 XtSetValues(buttonBarWidget, args, 4);
2225 widgetList[j++] = messageWidget =
2226 XtCreateWidget("message", labelWidgetClass, formWidget,
2227 messageArgs, XtNumber(messageArgs));
2228 XtSetArg(args[0], XtNtop, XtChainTop);
2229 XtSetArg(args[1], XtNbottom, XtChainTop);
2230 XtSetValues(messageWidget, args, 2);
2232 widgetList[j++] = boardWidget =
2233 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2234 XtNumber(boardArgs));
2236 XtManageChildren(widgetList, j);
2238 timerWidth = (boardWidth - sep) / 2;
2239 XtSetArg(args[0], XtNwidth, timerWidth);
2240 XtSetValues(whiteTimerWidget, args, 1);
2241 XtSetValues(blackTimerWidget, args, 1);
2243 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2244 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2245 XtGetValues(whiteTimerWidget, args, 2);
2247 if (appData.showButtonBar) {
2248 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2249 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2250 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2254 * formWidget uses these constraints but they are stored
2258 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2259 XtSetValues(menuBarWidget, args, i);
2260 if (appData.titleInWindow) {
2263 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2264 XtSetValues(whiteTimerWidget, args, i);
2266 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2267 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2268 XtSetValues(blackTimerWidget, args, i);
2270 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2271 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2272 XtSetValues(titleWidget, args, i);
2274 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2275 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2276 XtSetValues(messageWidget, args, i);
2277 if (appData.showButtonBar) {
2279 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2280 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2281 XtSetValues(buttonBarWidget, args, i);
2285 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2286 XtSetValues(whiteTimerWidget, args, i);
2288 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2289 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2290 XtSetValues(blackTimerWidget, args, i);
2292 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2293 XtSetValues(titleWidget, args, i);
2295 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2296 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2297 XtSetValues(messageWidget, args, i);
2298 if (appData.showButtonBar) {
2300 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2301 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2302 XtSetValues(buttonBarWidget, args, i);
2307 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2308 XtSetValues(whiteTimerWidget, args, i);
2310 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2311 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2312 XtSetValues(blackTimerWidget, args, i);
2314 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2315 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2316 XtSetValues(messageWidget, args, i);
2317 if (appData.showButtonBar) {
2319 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2320 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2321 XtSetValues(buttonBarWidget, args, i);
2325 XtSetArg(args[0], XtNfromVert, messageWidget);
2326 XtSetArg(args[1], XtNtop, XtChainTop);
2327 XtSetArg(args[2], XtNbottom, XtChainBottom);
2328 XtSetArg(args[3], XtNleft, XtChainLeft);
2329 XtSetArg(args[4], XtNright, XtChainRight);
2330 XtSetValues(boardWidget, args, 5);
2332 XtRealizeWidget(shellWidget);
2335 XtSetArg(args[0], XtNx, wpMain.x);
2336 XtSetArg(args[1], XtNy, wpMain.y);
2337 XtSetValues(shellWidget, args, 2);
2341 * Correct the width of the message and title widgets.
2342 * It is not known why some systems need the extra fudge term.
2343 * The value "2" is probably larger than needed.
2345 XawFormDoLayout(formWidget, False);
2347 #define WIDTH_FUDGE 2
2349 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2350 XtSetArg(args[i], XtNheight, &h); i++;
2351 XtGetValues(messageWidget, args, i);
2352 if (appData.showButtonBar) {
2354 XtSetArg(args[i], XtNwidth, &w); i++;
2355 XtGetValues(buttonBarWidget, args, i);
2356 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2358 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2361 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2362 if (gres != XtGeometryYes && appData.debugMode) {
2363 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2364 programName, gres, w, h, wr, hr);
2367 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2368 /* The size used for the child widget in layout lags one resize behind
2369 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2371 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2372 if (gres != XtGeometryYes && appData.debugMode) {
2373 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2374 programName, gres, w, h, wr, hr);
2377 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2378 XtSetArg(args[1], XtNright, XtChainRight);
2379 XtSetValues(messageWidget, args, 2);
2381 if (appData.titleInWindow) {
2383 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2384 XtSetArg(args[i], XtNheight, &h); i++;
2385 XtGetValues(titleWidget, args, i);
2387 w = boardWidth - 2*bor;
2389 XtSetArg(args[0], XtNwidth, &w);
2390 XtGetValues(menuBarWidget, args, 1);
2391 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2394 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2395 if (gres != XtGeometryYes && appData.debugMode) {
2397 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2398 programName, gres, w, h, wr, hr);
2401 XawFormDoLayout(formWidget, True);
2403 xBoardWindow = XtWindow(boardWidget);
2405 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2406 // not need to go into InitDrawingSizes().
2410 * Create X checkmark bitmap and initialize option menu checks.
2412 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2413 checkmark_bits, checkmark_width, checkmark_height);
2414 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2415 #ifndef OPTIONSDIALOG
2416 if (appData.alwaysPromoteToQueen) {
2417 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2420 if (appData.animateDragging) {
2421 XtSetValues(XtNameToWidget(menuBarWidget,
2422 "menuOptions.Animate Dragging"),
2425 if (appData.animate) {
2426 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2429 if (appData.autoCallFlag) {
2430 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2433 if (appData.autoFlipView) {
2434 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2437 if (appData.blindfold) {
2438 XtSetValues(XtNameToWidget(menuBarWidget,
2439 "menuOptions.Blindfold"), args, 1);
2441 if (appData.flashCount > 0) {
2442 XtSetValues(XtNameToWidget(menuBarWidget,
2443 "menuOptions.Flash Moves"),
2447 if (appData.highlightDragging) {
2448 XtSetValues(XtNameToWidget(menuBarWidget,
2449 "menuOptions.Highlight Dragging"),
2453 if (appData.highlightLastMove) {
2454 XtSetValues(XtNameToWidget(menuBarWidget,
2455 "menuOptions.Highlight Last Move"),
2458 if (appData.highlightMoveWithArrow) {
2459 XtSetValues(XtNameToWidget(menuBarWidget,
2460 "menuOptions.Arrow"),
2463 // if (appData.icsAlarm) {
2464 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2467 if (appData.ringBellAfterMoves) {
2468 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2471 if (appData.oneClick) {
2472 XtSetValues(XtNameToWidget(menuBarWidget,
2473 "menuOptions.OneClick"), args, 1);
2475 if (appData.periodicUpdates) {
2476 XtSetValues(XtNameToWidget(menuBarWidget,
2477 "menuOptions.Periodic Updates"), args, 1);
2479 if (appData.ponderNextMove) {
2480 XtSetValues(XtNameToWidget(menuBarWidget,
2481 "menuOptions.Ponder Next Move"), args, 1);
2483 if (appData.popupExitMessage) {
2484 XtSetValues(XtNameToWidget(menuBarWidget,
2485 "menuOptions.Popup Exit Message"), args, 1);
2487 if (appData.popupMoveErrors) {
2488 XtSetValues(XtNameToWidget(menuBarWidget,
2489 "menuOptions.Popup Move Errors"), args, 1);
2491 // if (appData.premove) {
2492 // XtSetValues(XtNameToWidget(menuBarWidget,
2493 // "menuOptions.Premove"), args, 1);
2495 if (appData.showCoords) {
2496 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2499 if (appData.hideThinkingFromHuman) {
2500 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2503 if (appData.testLegality) {
2504 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2508 if (saveSettingsOnExit) {
2509 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2516 ReadBitmap(&wIconPixmap, "icon_white.bm",
2517 icon_white_bits, icon_white_width, icon_white_height);
2518 ReadBitmap(&bIconPixmap, "icon_black.bm",
2519 icon_black_bits, icon_black_width, icon_black_height);
2520 iconPixmap = wIconPixmap;
2522 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2523 XtSetValues(shellWidget, args, i);
2526 * Create a cursor for the board widget.
2528 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2529 XChangeWindowAttributes(xDisplay, xBoardWindow,
2530 CWCursor, &window_attributes);
2533 * Inhibit shell resizing.
2535 shellArgs[0].value = (XtArgVal) &w;
2536 shellArgs[1].value = (XtArgVal) &h;
2537 XtGetValues(shellWidget, shellArgs, 2);
2538 shellArgs[4].value = shellArgs[2].value = w;
2539 shellArgs[5].value = shellArgs[3].value = h;
2540 XtSetValues(shellWidget, &shellArgs[2], 4);
2541 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2542 marginH = h - boardHeight;
2544 CatchDeleteWindow(shellWidget, "QuitProc");
2549 if (appData.bitmapDirectory[0] != NULLCHAR) {
2553 CreateXPMBoard(appData.liteBackTextureFile, 1);
2554 CreateXPMBoard(appData.darkBackTextureFile, 0);
2558 /* Create regular pieces */
2559 if (!useImages) CreatePieces();
2564 if (appData.animate || appData.animateDragging)
2567 XtAugmentTranslations(formWidget,
2568 XtParseTranslationTable(globalTranslations));
2569 XtAugmentTranslations(boardWidget,
2570 XtParseTranslationTable(boardTranslations));
2571 XtAugmentTranslations(whiteTimerWidget,
2572 XtParseTranslationTable(whiteTranslations));
2573 XtAugmentTranslations(blackTimerWidget,
2574 XtParseTranslationTable(blackTranslations));
2576 /* Why is the following needed on some versions of X instead
2577 * of a translation? */
2578 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2579 (XtEventHandler) EventProc, NULL);
2582 /* [AS] Restore layout */
2583 if( wpMoveHistory.visible ) {
2587 if( wpEvalGraph.visible )
2592 if( wpEngineOutput.visible ) {
2593 EngineOutputPopUp();
2598 if (errorExitStatus == -1) {
2599 if (appData.icsActive) {
2600 /* We now wait until we see "login:" from the ICS before
2601 sending the logon script (problems with timestamp otherwise) */
2602 /*ICSInitScript();*/
2603 if (appData.icsInputBox) ICSInputBoxPopUp();
2607 signal(SIGWINCH, TermSizeSigHandler);
2609 signal(SIGINT, IntSigHandler);
2610 signal(SIGTERM, IntSigHandler);
2611 if (*appData.cmailGameName != NULLCHAR) {
2612 signal(SIGUSR1, CmailSigHandler);
2615 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2617 XtSetKeyboardFocus(shellWidget, formWidget);
2619 XtAppMainLoop(appContext);
2620 if (appData.debugMode) fclose(debugFP); // [DM] debug
2627 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2628 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2630 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2631 unlink(gameCopyFilename);
2632 unlink(gamePasteFilename);
2635 RETSIGTYPE TermSizeSigHandler(int sig)
2648 CmailSigHandler(sig)
2654 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2656 /* Activate call-back function CmailSigHandlerCallBack() */
2657 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2659 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2663 CmailSigHandlerCallBack(isr, closure, message, count, error)
2671 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2673 /**** end signal code ****/
2679 /* try to open the icsLogon script, either in the location given
2680 * or in the users HOME directory
2687 f = fopen(appData.icsLogon, "r");
2690 homedir = getenv("HOME");
2691 if (homedir != NULL)
2693 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2694 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2695 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2696 f = fopen(buf, "r");
2701 ProcessICSInitScript(f);
2703 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2726 if (!menuBarWidget) return;
2727 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2729 DisplayError("menuEdit.Revert", 0);
2731 XtSetSensitive(w, !grey);
2733 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2735 DisplayError("menuEdit.Annotate", 0);
2737 XtSetSensitive(w, !grey);
2742 SetMenuEnables(enab)
2746 if (!menuBarWidget) return;
2747 while (enab->name != NULL) {
2748 w = XtNameToWidget(menuBarWidget, enab->name);
2750 DisplayError(enab->name, 0);
2752 XtSetSensitive(w, enab->value);
2758 Enables icsEnables[] = {
2759 { "menuFile.Mail Move", False },
2760 { "menuFile.Reload CMail Message", False },
2761 { "menuMode.Machine Black", False },
2762 { "menuMode.Machine White", False },
2763 { "menuMode.Analysis Mode", False },
2764 { "menuMode.Analyze File", False },
2765 { "menuMode.Two Machines", False },
2766 { "menuMode.Machine Match", False },
2768 { "menuEngine.Hint", False },
2769 { "menuEngine.Book", False },
2770 { "menuEngine.Move Now", False },
2771 #ifndef OPTIONSDIALOG
2772 { "menuOptions.Periodic Updates", False },
2773 { "menuOptions.Hide Thinking", False },
2774 { "menuOptions.Ponder Next Move", False },
2776 { "menuEngine.Engine #1 Settings", False },
2778 { "menuEngine.Engine #2 Settings", False },
2779 { "menuEdit.Annotate", False },
2783 Enables ncpEnables[] = {
2784 { "menuFile.Mail Move", False },
2785 { "menuFile.Reload CMail Message", False },
2786 { "menuMode.Machine White", False },
2787 { "menuMode.Machine Black", False },
2788 { "menuMode.Analysis Mode", False },
2789 { "menuMode.Analyze File", False },
2790 { "menuMode.Two Machines", False },
2791 { "menuMode.Machine Match", False },
2792 { "menuMode.ICS Client", False },
2793 { "menuView.ICStex", False },
2794 { "menuView.ICS Input Box", False },
2795 { "Action", False },
2796 { "menuEdit.Revert", False },
2797 { "menuEdit.Annotate", False },
2798 { "menuEngine.Engine #1 Settings", False },
2799 { "menuEngine.Engine #2 Settings", False },
2800 { "menuEngine.Move Now", False },
2801 { "menuEngine.Retract Move", False },
2802 { "menuOptions.ICS", False },
2803 #ifndef OPTIONSDIALOG
2804 { "menuOptions.Auto Flag", False },
2805 { "menuOptions.Auto Flip View", False },
2806 // { "menuOptions.ICS Alarm", False },
2807 { "menuOptions.Move Sound", False },
2808 { "menuOptions.Hide Thinking", False },
2809 { "menuOptions.Periodic Updates", False },
2810 { "menuOptions.Ponder Next Move", False },
2812 { "menuEngine.Hint", False },
2813 { "menuEngine.Book", False },
2817 Enables gnuEnables[] = {
2818 { "menuMode.ICS Client", False },
2819 { "menuView.ICStex", False },
2820 { "menuView.ICS Input Box", False },
2821 { "menuAction.Accept", False },
2822 { "menuAction.Decline", False },
2823 { "menuAction.Rematch", False },
2824 { "menuAction.Adjourn", False },
2825 { "menuAction.Stop Examining", False },
2826 { "menuAction.Stop Observing", False },
2827 { "menuAction.Upload to Examine", False },
2828 { "menuEdit.Revert", False },
2829 { "menuEdit.Annotate", False },
2830 { "menuOptions.ICS", False },
2832 /* The next two options rely on SetCmailMode being called *after* */
2833 /* SetGNUMode so that when GNU is being used to give hints these */
2834 /* menu options are still available */
2836 { "menuFile.Mail Move", False },
2837 { "menuFile.Reload CMail Message", False },
2841 Enables cmailEnables[] = {
2843 { "menuAction.Call Flag", False },
2844 { "menuAction.Draw", True },
2845 { "menuAction.Adjourn", False },
2846 { "menuAction.Abort", False },
2847 { "menuAction.Stop Observing", False },
2848 { "menuAction.Stop Examining", False },
2849 { "menuFile.Mail Move", True },
2850 { "menuFile.Reload CMail Message", True },
2854 Enables trainingOnEnables[] = {
2855 { "menuMode.Edit Comment", False },
2856 { "menuMode.Pause", False },
2857 { "menuEdit.Forward", False },
2858 { "menuEdit.Backward", False },
2859 { "menuEdit.Forward to End", False },
2860 { "menuEdit.Back to Start", False },
2861 { "menuEngine.Move Now", False },
2862 { "menuEdit.Truncate Game", False },
2866 Enables trainingOffEnables[] = {
2867 { "menuMode.Edit Comment", True },
2868 { "menuMode.Pause", True },
2869 { "menuEdit.Forward", True },
2870 { "menuEdit.Backward", True },
2871 { "menuEdit.Forward to End", True },
2872 { "menuEdit.Back to Start", True },
2873 { "menuEngine.Move Now", True },
2874 { "menuEdit.Truncate Game", True },
2878 Enables machineThinkingEnables[] = {
2879 { "menuFile.Load Game", False },
2880 // { "menuFile.Load Next Game", False },
2881 // { "menuFile.Load Previous Game", False },
2882 // { "menuFile.Reload Same Game", False },
2883 { "menuEdit.Paste Game", False },
2884 { "menuFile.Load Position", False },
2885 // { "menuFile.Load Next Position", False },
2886 // { "menuFile.Load Previous Position", False },
2887 // { "menuFile.Reload Same Position", False },
2888 { "menuEdit.Paste Position", False },
2889 { "menuMode.Machine White", False },
2890 { "menuMode.Machine Black", False },
2891 { "menuMode.Two Machines", False },
2892 { "menuMode.Machine Match", False },
2893 { "menuEngine.Retract Move", False },
2897 Enables userThinkingEnables[] = {
2898 { "menuFile.Load Game", True },
2899 // { "menuFile.Load Next Game", True },
2900 // { "menuFile.Load Previous Game", True },
2901 // { "menuFile.Reload Same Game", True },
2902 { "menuEdit.Paste Game", True },
2903 { "menuFile.Load Position", True },
2904 // { "menuFile.Load Next Position", True },
2905 // { "menuFile.Load Previous Position", True },
2906 // { "menuFile.Reload Same Position", True },
2907 { "menuEdit.Paste Position", True },
2908 { "menuMode.Machine White", True },
2909 { "menuMode.Machine Black", True },
2910 { "menuMode.Two Machines", True },
2911 { "menuMode.Machine Match", True },
2912 { "menuEngine.Retract Move", True },
2918 SetMenuEnables(icsEnables);
2921 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2922 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2929 SetMenuEnables(ncpEnables);
2935 SetMenuEnables(gnuEnables);
2941 SetMenuEnables(cmailEnables);
2947 SetMenuEnables(trainingOnEnables);
2948 if (appData.showButtonBar) {
2949 XtSetSensitive(buttonBarWidget, False);
2955 SetTrainingModeOff()
2957 SetMenuEnables(trainingOffEnables);
2958 if (appData.showButtonBar) {
2959 XtSetSensitive(buttonBarWidget, True);
2964 SetUserThinkingEnables()
2966 if (appData.noChessProgram) return;
2967 SetMenuEnables(userThinkingEnables);
2971 SetMachineThinkingEnables()
2973 if (appData.noChessProgram) return;
2974 SetMenuEnables(machineThinkingEnables);
2976 case MachinePlaysBlack:
2977 case MachinePlaysWhite:
2978 case TwoMachinesPlay:
2979 XtSetSensitive(XtNameToWidget(menuBarWidget,
2980 ModeToWidgetName(gameMode)), True);
2987 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2988 #define HISTORY_SIZE 64
2989 static char *history[HISTORY_SIZE];
2990 int histIn = 0, histP = 0;
2993 SaveInHistory(char *cmd)
2995 if (history[histIn] != NULL) {
2996 free(history[histIn]);
2997 history[histIn] = NULL;
2999 if (*cmd == NULLCHAR) return;
3000 history[histIn] = StrSave(cmd);
3001 histIn = (histIn + 1) % HISTORY_SIZE;
3002 if (history[histIn] != NULL) {
3003 free(history[histIn]);
3004 history[histIn] = NULL;
3010 PrevInHistory(char *cmd)
3013 if (histP == histIn) {
3014 if (history[histIn] != NULL) free(history[histIn]);
3015 history[histIn] = StrSave(cmd);
3017 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3018 if (newhp == histIn || history[newhp] == NULL) return NULL;
3020 return history[histP];
3026 if (histP == histIn) return NULL;
3027 histP = (histP + 1) % HISTORY_SIZE;
3028 return history[histP];
3030 // end of borrowed code
3032 #define Abs(n) ((n)<0 ? -(n) : (n))
3035 * Find a font that matches "pattern" that is as close as
3036 * possible to the targetPxlSize. Prefer fonts that are k
3037 * pixels smaller to fonts that are k pixels larger. The
3038 * pattern must be in the X Consortium standard format,
3039 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3040 * The return value should be freed with XtFree when no
3044 FindFont(pattern, targetPxlSize)
3048 char **fonts, *p, *best, *scalable, *scalableTail;
3049 int i, j, nfonts, minerr, err, pxlSize;
3052 char **missing_list;
3054 char *def_string, *base_fnt_lst, strInt[3];
3056 XFontStruct **fnt_list;
3058 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3059 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3060 p = strstr(pattern, "--");
3061 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3062 strcat(base_fnt_lst, strInt);
3063 strcat(base_fnt_lst, strchr(p + 2, '-'));
3065 if ((fntSet = XCreateFontSet(xDisplay,
3069 &def_string)) == NULL) {
3071 fprintf(stderr, _("Unable to create font set.\n"));
3075 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3077 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3079 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3080 programName, pattern);
3088 for (i=0; i<nfonts; i++) {
3091 if (*p != '-') continue;
3093 if (*p == NULLCHAR) break;
3094 if (*p++ == '-') j++;
3096 if (j < 7) continue;
3099 scalable = fonts[i];
3102 err = pxlSize - targetPxlSize;
3103 if (Abs(err) < Abs(minerr) ||
3104 (minerr > 0 && err < 0 && -err == minerr)) {
3110 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3111 /* If the error is too big and there is a scalable font,
3112 use the scalable font. */
3113 int headlen = scalableTail - scalable;
3114 p = (char *) XtMalloc(strlen(scalable) + 10);
3115 while (isdigit(*scalableTail)) scalableTail++;
3116 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3118 p = (char *) XtMalloc(strlen(best) + 2);
3119 safeStrCpy(p, best, strlen(best)+1 );
3121 if (appData.debugMode) {
3122 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3123 pattern, targetPxlSize, p);
3126 if (missing_count > 0)
3127 XFreeStringList(missing_list);
3128 XFreeFontSet(xDisplay, fntSet);
3130 XFreeFontNames(fonts);
3136 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3137 // must be called before all non-first callse to CreateGCs()
3138 XtReleaseGC(shellWidget, highlineGC);
3139 XtReleaseGC(shellWidget, lightSquareGC);
3140 XtReleaseGC(shellWidget, darkSquareGC);
3141 XtReleaseGC(shellWidget, lineGC);
3142 if (appData.monoMode) {
3143 if (DefaultDepth(xDisplay, xScreen) == 1) {
3144 XtReleaseGC(shellWidget, wbPieceGC);
3146 XtReleaseGC(shellWidget, bwPieceGC);
3149 XtReleaseGC(shellWidget, prelineGC);
3150 XtReleaseGC(shellWidget, jailSquareGC);
3151 XtReleaseGC(shellWidget, wdPieceGC);
3152 XtReleaseGC(shellWidget, wlPieceGC);
3153 XtReleaseGC(shellWidget, wjPieceGC);
3154 XtReleaseGC(shellWidget, bdPieceGC);
3155 XtReleaseGC(shellWidget, blPieceGC);
3156 XtReleaseGC(shellWidget, bjPieceGC);
3160 void CreateGCs(int redo)
3162 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3163 | GCBackground | GCFunction | GCPlaneMask;
3164 XGCValues gc_values;
3167 gc_values.plane_mask = AllPlanes;
3168 gc_values.line_width = lineGap;
3169 gc_values.line_style = LineSolid;
3170 gc_values.function = GXcopy;
3173 DeleteGCs(); // called a second time; clean up old GCs first
3174 } else { // [HGM] grid and font GCs created on first call only
3175 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3176 gc_values.background = XWhitePixel(xDisplay, xScreen);
3177 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3178 XSetFont(xDisplay, coordGC, coordFontID);
3180 // [HGM] make font for holdings counts (white on black)
3181 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3182 gc_values.background = XBlackPixel(xDisplay, xScreen);
3183 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3184 XSetFont(xDisplay, countGC, countFontID);
3186 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3187 gc_values.background = XBlackPixel(xDisplay, xScreen);
3188 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3190 if (appData.monoMode) {
3191 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3192 gc_values.background = XWhitePixel(xDisplay, xScreen);
3193 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3195 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3196 gc_values.background = XBlackPixel(xDisplay, xScreen);
3197 lightSquareGC = wbPieceGC
3198 = XtGetGC(shellWidget, value_mask, &gc_values);
3200 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3201 gc_values.background = XWhitePixel(xDisplay, xScreen);
3202 darkSquareGC = bwPieceGC
3203 = XtGetGC(shellWidget, value_mask, &gc_values);
3205 if (DefaultDepth(xDisplay, xScreen) == 1) {
3206 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3207 gc_values.function = GXcopyInverted;
3208 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3209 gc_values.function = GXcopy;
3210 if (XBlackPixel(xDisplay, xScreen) == 1) {
3211 bwPieceGC = darkSquareGC;
3212 wbPieceGC = copyInvertedGC;
3214 bwPieceGC = copyInvertedGC;
3215 wbPieceGC = lightSquareGC;
3219 gc_values.foreground = highlightSquareColor;
3220 gc_values.background = highlightSquareColor;
3221 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3223 gc_values.foreground = premoveHighlightColor;
3224 gc_values.background = premoveHighlightColor;
3225 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3227 gc_values.foreground = lightSquareColor;
3228 gc_values.background = darkSquareColor;
3229 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3231 gc_values.foreground = darkSquareColor;
3232 gc_values.background = lightSquareColor;
3233 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3235 gc_values.foreground = jailSquareColor;
3236 gc_values.background = jailSquareColor;
3237 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3239 gc_values.foreground = whitePieceColor;
3240 gc_values.background = darkSquareColor;
3241 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3243 gc_values.foreground = whitePieceColor;
3244 gc_values.background = lightSquareColor;
3245 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3247 gc_values.foreground = whitePieceColor;
3248 gc_values.background = jailSquareColor;
3249 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3251 gc_values.foreground = blackPieceColor;
3252 gc_values.background = darkSquareColor;
3253 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3255 gc_values.foreground = blackPieceColor;
3256 gc_values.background = lightSquareColor;
3257 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3259 gc_values.foreground = blackPieceColor;
3260 gc_values.background = jailSquareColor;
3261 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3265 void loadXIM(xim, xmask, filename, dest, mask)
3278 fp = fopen(filename, "rb");
3280 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3287 for (y=0; y<h; ++y) {
3288 for (x=0; x<h; ++x) {
3293 XPutPixel(xim, x, y, blackPieceColor);
3295 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3298 XPutPixel(xim, x, y, darkSquareColor);
3300 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3303 XPutPixel(xim, x, y, whitePieceColor);
3305 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3308 XPutPixel(xim, x, y, lightSquareColor);
3310 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3318 /* create Pixmap of piece */
3319 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3321 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3324 /* create Pixmap of clipmask
3325 Note: We assume the white/black pieces have the same
3326 outline, so we make only 6 masks. This is okay
3327 since the XPM clipmask routines do the same. */
3329 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3331 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3334 /* now create the 1-bit version */
3335 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3338 values.foreground = 1;
3339 values.background = 0;
3341 /* Don't use XtGetGC, not read only */
3342 maskGC = XCreateGC(xDisplay, *mask,
3343 GCForeground | GCBackground, &values);
3344 XCopyPlane(xDisplay, temp, *mask, maskGC,
3345 0, 0, squareSize, squareSize, 0, 0, 1);
3346 XFreePixmap(xDisplay, temp);
3351 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3353 void CreateXIMPieces()
3358 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3363 /* The XSynchronize calls were copied from CreatePieces.
3364 Not sure if needed, but can't hurt */
3365 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3368 /* temp needed by loadXIM() */
3369 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3370 0, 0, ss, ss, AllPlanes, XYPixmap);
3372 if (strlen(appData.pixmapDirectory) == 0) {
3376 if (appData.monoMode) {
3377 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3381 fprintf(stderr, _("\nLoading XIMs...\n"));
3383 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3384 fprintf(stderr, "%d", piece+1);
3385 for (kind=0; kind<4; kind++) {
3386 fprintf(stderr, ".");
3387 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3388 ExpandPathName(appData.pixmapDirectory),
3389 piece <= (int) WhiteKing ? "" : "w",
3390 pieceBitmapNames[piece],
3392 ximPieceBitmap[kind][piece] =
3393 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3394 0, 0, ss, ss, AllPlanes, XYPixmap);
3395 if (appData.debugMode)
3396 fprintf(stderr, _("(File:%s:) "), buf);
3397 loadXIM(ximPieceBitmap[kind][piece],
3399 &(xpmPieceBitmap2[kind][piece]),
3400 &(ximMaskPm2[piece]));
3401 if(piece <= (int)WhiteKing)
3402 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3404 fprintf(stderr," ");
3406 /* Load light and dark squares */
3407 /* If the LSQ and DSQ pieces don't exist, we will
3408 draw them with solid squares. */
3409 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3410 if (access(buf, 0) != 0) {
3414 fprintf(stderr, _("light square "));
3416 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3417 0, 0, ss, ss, AllPlanes, XYPixmap);
3418 if (appData.debugMode)
3419 fprintf(stderr, _("(File:%s:) "), buf);
3421 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3422 fprintf(stderr, _("dark square "));
3423 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3424 ExpandPathName(appData.pixmapDirectory), ss);
3425 if (appData.debugMode)
3426 fprintf(stderr, _("(File:%s:) "), buf);
3428 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3429 0, 0, ss, ss, AllPlanes, XYPixmap);
3430 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3431 xpmJailSquare = xpmLightSquare;
3433 fprintf(stderr, _("Done.\n"));
3435 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3438 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3441 void CreateXPMBoard(char *s, int kind)
3445 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3446 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3447 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3451 void FreeXPMPieces()
3452 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3453 // thisroutine has to be called t free the old piece pixmaps
3455 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3456 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3458 XFreePixmap(xDisplay, xpmLightSquare);
3459 XFreePixmap(xDisplay, xpmDarkSquare);
3463 void CreateXPMPieces()
3467 u_int ss = squareSize;
3469 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3470 XpmColorSymbol symbols[4];
3471 static int redo = False;
3473 if(redo) FreeXPMPieces(); else redo = 1;
3475 /* The XSynchronize calls were copied from CreatePieces.
3476 Not sure if needed, but can't hurt */
3477 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3479 /* Setup translations so piece colors match square colors */
3480 symbols[0].name = "light_piece";
3481 symbols[0].value = appData.whitePieceColor;
3482 symbols[1].name = "dark_piece";
3483 symbols[1].value = appData.blackPieceColor;
3484 symbols[2].name = "light_square";
3485 symbols[2].value = appData.lightSquareColor;
3486 symbols[3].name = "dark_square";
3487 symbols[3].value = appData.darkSquareColor;
3489 attr.valuemask = XpmColorSymbols;
3490 attr.colorsymbols = symbols;
3491 attr.numsymbols = 4;
3493 if (appData.monoMode) {
3494 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3498 if (strlen(appData.pixmapDirectory) == 0) {
3499 XpmPieces* pieces = builtInXpms;
3502 while (pieces->size != squareSize && pieces->size) pieces++;
3503 if (!pieces->size) {
3504 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3507 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3508 for (kind=0; kind<4; kind++) {
3510 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3511 pieces->xpm[piece][kind],
3512 &(xpmPieceBitmap2[kind][piece]),
3513 NULL, &attr)) != 0) {
3514 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3518 if(piece <= (int) WhiteKing)
3519 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3523 xpmJailSquare = xpmLightSquare;
3527 fprintf(stderr, _("\nLoading XPMs...\n"));
3530 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3531 fprintf(stderr, "%d ", piece+1);
3532 for (kind=0; kind<4; kind++) {
3533 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3534 ExpandPathName(appData.pixmapDirectory),
3535 piece > (int) WhiteKing ? "w" : "",
3536 pieceBitmapNames[piece],
3538 if (appData.debugMode) {
3539 fprintf(stderr, _("(File:%s:) "), buf);
3541 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3542 &(xpmPieceBitmap2[kind][piece]),
3543 NULL, &attr)) != 0) {
3544 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3545 // [HGM] missing: read of unorthodox piece failed; substitute King.
3546 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3547 ExpandPathName(appData.pixmapDirectory),
3549 if (appData.debugMode) {
3550 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3552 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3553 &(xpmPieceBitmap2[kind][piece]),
3557 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3562 if(piece <= (int) WhiteKing)
3563 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3566 /* Load light and dark squares */
3567 /* If the LSQ and DSQ pieces don't exist, we will
3568 draw them with solid squares. */
3569 fprintf(stderr, _("light square "));
3570 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3571 if (access(buf, 0) != 0) {
3575 if (appData.debugMode)
3576 fprintf(stderr, _("(File:%s:) "), buf);
3578 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3579 &xpmLightSquare, NULL, &attr)) != 0) {
3580 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3583 fprintf(stderr, _("dark square "));
3584 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3585 ExpandPathName(appData.pixmapDirectory), ss);
3586 if (appData.debugMode) {
3587 fprintf(stderr, _("(File:%s:) "), buf);
3589 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3590 &xpmDarkSquare, NULL, &attr)) != 0) {
3591 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3595 xpmJailSquare = xpmLightSquare;
3596 fprintf(stderr, _("Done.\n"));
3598 oldVariant = -1; // kludge to force re-makig of animation masks
3599 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3602 #endif /* HAVE_LIBXPM */
3605 /* No built-in bitmaps */
3610 u_int ss = squareSize;
3612 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3615 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3616 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3617 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3618 pieceBitmapNames[piece],
3619 ss, kind == SOLID ? 's' : 'o');
3620 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3621 if(piece <= (int)WhiteKing)
3622 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3626 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3630 /* With built-in bitmaps */
3633 BuiltInBits* bib = builtInBits;
3636 u_int ss = squareSize;
3638 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3641 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3643 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3644 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3645 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3646 pieceBitmapNames[piece],
3647 ss, kind == SOLID ? 's' : 'o');
3648 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3649 bib->bits[kind][piece], ss, ss);
3650 if(piece <= (int)WhiteKing)
3651 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3655 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3660 void ReadBitmap(pm, name, bits, wreq, hreq)
3663 unsigned char bits[];
3669 char msg[MSG_SIZ], fullname[MSG_SIZ];
3671 if (*appData.bitmapDirectory != NULLCHAR) {
3672 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3673 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3674 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3675 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3676 &w, &h, pm, &x_hot, &y_hot);
3677 fprintf(stderr, "load %s\n", name);
3678 if (errcode != BitmapSuccess) {
3680 case BitmapOpenFailed:
3681 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3683 case BitmapFileInvalid:
3684 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3686 case BitmapNoMemory:
3687 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3691 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3695 fprintf(stderr, _("%s: %s...using built-in\n"),
3697 } else if (w != wreq || h != hreq) {
3699 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3700 programName, fullname, w, h, wreq, hreq);
3706 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3715 if (lineGap == 0) return;
3717 /* [HR] Split this into 2 loops for non-square boards. */
3719 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3720 gridSegments[i].x1 = 0;
3721 gridSegments[i].x2 =
3722 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3723 gridSegments[i].y1 = gridSegments[i].y2
3724 = lineGap / 2 + (i * (squareSize + lineGap));
3727 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3728 gridSegments[j + i].y1 = 0;
3729 gridSegments[j + i].y2 =
3730 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3731 gridSegments[j + i].x1 = gridSegments[j + i].x2
3732 = lineGap / 2 + (j * (squareSize + lineGap));
3736 static void MenuBarSelect(w, addr, index)
3741 XtActionProc proc = (XtActionProc) addr;
3743 (proc)(NULL, NULL, NULL, NULL);
3746 void CreateMenuBarPopup(parent, name, mb)
3756 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3759 XtSetArg(args[j], XtNleftMargin, 20); j++;
3760 XtSetArg(args[j], XtNrightMargin, 20); j++;
3762 while (mi->string != NULL) {
3763 if (strcmp(mi->string, "----") == 0) {
3764 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3767 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3768 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3770 XtAddCallback(entry, XtNcallback,
3771 (XtCallbackProc) MenuBarSelect,
3772 (caddr_t) mi->proc);
3778 Widget CreateMenuBar(mb)
3782 Widget anchor, menuBar;
3784 char menuName[MSG_SIZ];
3787 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3788 XtSetArg(args[j], XtNvSpace, 0); j++;
3789 XtSetArg(args[j], XtNborderWidth, 0); j++;
3790 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3791 formWidget, args, j);
3793 while (mb->name != NULL) {
3794 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3795 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3797 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3800 shortName[0] = mb->name[0];
3801 shortName[1] = NULLCHAR;
3802 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3805 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3808 XtSetArg(args[j], XtNborderWidth, 0); j++;
3809 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3811 CreateMenuBarPopup(menuBar, menuName, mb);
3817 Widget CreateButtonBar(mi)
3821 Widget button, buttonBar;
3825 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3827 XtSetArg(args[j], XtNhSpace, 0); j++;
3829 XtSetArg(args[j], XtNborderWidth, 0); j++;
3830 XtSetArg(args[j], XtNvSpace, 0); j++;
3831 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3832 formWidget, args, j);
3834 while (mi->string != NULL) {
3837 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3838 XtSetArg(args[j], XtNborderWidth, 0); j++;
3840 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3841 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3842 buttonBar, args, j);
3843 XtAddCallback(button, XtNcallback,
3844 (XtCallbackProc) MenuBarSelect,
3845 (caddr_t) mi->proc);
3852 CreatePieceMenu(name, color)
3859 ChessSquare selection;
3861 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3862 boardWidget, args, 0);
3864 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3865 String item = pieceMenuStrings[color][i];
3867 if (strcmp(item, "----") == 0) {
3868 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3871 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3872 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3874 selection = pieceMenuTranslation[color][i];
3875 XtAddCallback(entry, XtNcallback,
3876 (XtCallbackProc) PieceMenuSelect,
3877 (caddr_t) selection);
3878 if (selection == WhitePawn || selection == BlackPawn) {
3879 XtSetArg(args[0], XtNpopupOnEntry, entry);
3880 XtSetValues(menu, args, 1);
3893 ChessSquare selection;
3895 whitePieceMenu = CreatePieceMenu("menuW", 0);
3896 blackPieceMenu = CreatePieceMenu("menuB", 1);
3898 XtRegisterGrabAction(PieceMenuPopup, True,
3899 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3900 GrabModeAsync, GrabModeAsync);
3902 XtSetArg(args[0], XtNlabel, _("Drop"));
3903 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3904 boardWidget, args, 1);
3905 for (i = 0; i < DROP_MENU_SIZE; i++) {
3906 String item = dropMenuStrings[i];
3908 if (strcmp(item, "----") == 0) {
3909 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3912 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3913 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3915 selection = dropMenuTranslation[i];
3916 XtAddCallback(entry, XtNcallback,
3917 (XtCallbackProc) DropMenuSelect,
3918 (caddr_t) selection);
3923 void SetupDropMenu()
3931 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3932 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3933 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3934 dmEnables[i].piece);
3935 XtSetSensitive(entry, p != NULL || !appData.testLegality
3936 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3937 && !appData.icsActive));
3939 while (p && *p++ == dmEnables[i].piece) count++;
3940 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3942 XtSetArg(args[j], XtNlabel, label); j++;
3943 XtSetValues(entry, args, j);
3947 void PieceMenuPopup(w, event, params, num_params)
3951 Cardinal *num_params;
3953 String whichMenu; int menuNr;
3954 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
3955 if (event->type == ButtonRelease)
3956 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3957 else if (event->type == ButtonPress)
3958 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3960 case 0: whichMenu = params[0]; break;
3961 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3963 case -1: if (errorUp) ErrorPopDown();
3966 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3969 static void PieceMenuSelect(w, piece, junk)
3974 if (pmFromX < 0 || pmFromY < 0) return;
3975 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3978 static void DropMenuSelect(w, piece, junk)
3983 if (pmFromX < 0 || pmFromY < 0) return;
3984 DropMenuEvent(piece, pmFromX, pmFromY);
3987 void WhiteClock(w, event, prms, nprms)
3996 void BlackClock(w, event, prms, nprms)
4007 * If the user selects on a border boundary, return -1; if off the board,
4008 * return -2. Otherwise map the event coordinate to the square.
4010 int EventToSquare(x, limit)
4018 if ((x % (squareSize + lineGap)) >= squareSize)
4020 x /= (squareSize + lineGap);
4026 static void do_flash_delay(msec)
4032 static void drawHighlight(file, rank, gc)
4038 if (lineGap == 0) return;
4041 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4042 (squareSize + lineGap);
4043 y = lineGap/2 + rank * (squareSize + lineGap);
4045 x = lineGap/2 + file * (squareSize + lineGap);
4046 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4047 (squareSize + lineGap);
4050 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4051 squareSize+lineGap, squareSize+lineGap);
4054 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4055 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4058 SetHighlights(fromX, fromY, toX, toY)
4059 int fromX, fromY, toX, toY;
4061 if (hi1X != fromX || hi1Y != fromY) {
4062 if (hi1X >= 0 && hi1Y >= 0) {
4063 drawHighlight(hi1X, hi1Y, lineGC);
4065 } // [HGM] first erase both, then draw new!
4066 if (hi2X != toX || hi2Y != toY) {
4067 if (hi2X >= 0 && hi2Y >= 0) {
4068 drawHighlight(hi2X, hi2Y, lineGC);
4071 if (hi1X != fromX || hi1Y != fromY) {
4072 if (fromX >= 0 && fromY >= 0) {
4073 drawHighlight(fromX, fromY, highlineGC);
4076 if (hi2X != toX || hi2Y != toY) {
4077 if (toX >= 0 && toY >= 0) {
4078 drawHighlight(toX, toY, highlineGC);
4090 SetHighlights(-1, -1, -1, -1);
4095 SetPremoveHighlights(fromX, fromY, toX, toY)
4096 int fromX, fromY, toX, toY;
4098 if (pm1X != fromX || pm1Y != fromY) {
4099 if (pm1X >= 0 && pm1Y >= 0) {
4100 drawHighlight(pm1X, pm1Y, lineGC);
4102 if (fromX >= 0 && fromY >= 0) {
4103 drawHighlight(fromX, fromY, prelineGC);
4106 if (pm2X != toX || pm2Y != toY) {
4107 if (pm2X >= 0 && pm2Y >= 0) {
4108 drawHighlight(pm2X, pm2Y, lineGC);
4110 if (toX >= 0 && toY >= 0) {
4111 drawHighlight(toX, toY, prelineGC);
4121 ClearPremoveHighlights()
4123 SetPremoveHighlights(-1, -1, -1, -1);
4126 static int CutOutSquare(x, y, x0, y0, kind)
4127 int x, y, *x0, *y0, kind;
4129 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4130 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4132 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4133 if(textureW[kind] < W*squareSize)
4134 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4136 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4137 if(textureH[kind] < H*squareSize)
4138 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4140 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4144 static void BlankSquare(x, y, color, piece, dest, fac)
4145 int x, y, color, fac;
4148 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4150 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4151 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4152 squareSize, squareSize, x*fac, y*fac);
4154 if (useImages && useImageSqs) {
4158 pm = xpmLightSquare;
4163 case 2: /* neutral */
4168 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4169 squareSize, squareSize, x*fac, y*fac);
4179 case 2: /* neutral */
4184 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4189 I split out the routines to draw a piece so that I could
4190 make a generic flash routine.
4192 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4194 int square_color, x, y;
4197 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4198 switch (square_color) {
4200 case 2: /* neutral */
4202 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4203 ? *pieceToOutline(piece)
4204 : *pieceToSolid(piece),
4205 dest, bwPieceGC, 0, 0,
4206 squareSize, squareSize, x, y);
4209 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4210 ? *pieceToSolid(piece)
4211 : *pieceToOutline(piece),
4212 dest, wbPieceGC, 0, 0,
4213 squareSize, squareSize, x, y);
4218 static void monoDrawPiece(piece, square_color, x, y, dest)
4220 int square_color, x, y;
4223 switch (square_color) {
4225 case 2: /* neutral */
4227 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4228 ? *pieceToOutline(piece)
4229 : *pieceToSolid(piece),
4230 dest, bwPieceGC, 0, 0,
4231 squareSize, squareSize, x, y, 1);
4234 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4235 ? *pieceToSolid(piece)
4236 : *pieceToOutline(piece),
4237 dest, wbPieceGC, 0, 0,
4238 squareSize, squareSize, x, y, 1);
4243 static void colorDrawPiece(piece, square_color, x, y, dest)
4245 int square_color, x, y;
4248 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4249 switch (square_color) {
4251 XCopyPlane(xDisplay, *pieceToSolid(piece),
4252 dest, (int) piece < (int) BlackPawn
4253 ? wlPieceGC : blPieceGC, 0, 0,
4254 squareSize, squareSize, x, y, 1);
4257 XCopyPlane(xDisplay, *pieceToSolid(piece),
4258 dest, (int) piece < (int) BlackPawn
4259 ? wdPieceGC : bdPieceGC, 0, 0,
4260 squareSize, squareSize, x, y, 1);
4262 case 2: /* neutral */
4264 XCopyPlane(xDisplay, *pieceToSolid(piece),
4265 dest, (int) piece < (int) BlackPawn
4266 ? wjPieceGC : bjPieceGC, 0, 0,
4267 squareSize, squareSize, x, y, 1);
4272 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4274 int square_color, x, y;
4277 int kind, p = piece;
4279 switch (square_color) {
4281 case 2: /* neutral */
4283 if ((int)piece < (int) BlackPawn) {
4291 if ((int)piece < (int) BlackPawn) {
4299 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4300 if(useTexture & square_color+1) {
4301 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4302 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4303 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4304 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4305 XSetClipMask(xDisplay, wlPieceGC, None);
4306 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4308 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4309 dest, wlPieceGC, 0, 0,
4310 squareSize, squareSize, x, y);
4313 typedef void (*DrawFunc)();
4315 DrawFunc ChooseDrawFunc()
4317 if (appData.monoMode) {
4318 if (DefaultDepth(xDisplay, xScreen) == 1) {
4319 return monoDrawPiece_1bit;
4321 return monoDrawPiece;
4325 return colorDrawPieceImage;
4327 return colorDrawPiece;
4331 /* [HR] determine square color depending on chess variant. */
4332 static int SquareColor(row, column)
4337 if (gameInfo.variant == VariantXiangqi) {
4338 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4340 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4342 } else if (row <= 4) {
4348 square_color = ((column + row) % 2) == 1;
4351 /* [hgm] holdings: next line makes all holdings squares light */
4352 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4354 return square_color;
4357 void DrawSquare(row, column, piece, do_flash)
4358 int row, column, do_flash;
4361 int square_color, x, y, direction, font_ascent, font_descent;
4364 XCharStruct overall;
4368 /* Calculate delay in milliseconds (2-delays per complete flash) */
4369 flash_delay = 500 / appData.flashRate;
4372 x = lineGap + ((BOARD_WIDTH-1)-column) *
4373 (squareSize + lineGap);
4374 y = lineGap + row * (squareSize + lineGap);
4376 x = lineGap + column * (squareSize + lineGap);
4377 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4378 (squareSize + lineGap);
4381 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4383 square_color = SquareColor(row, column);
4385 if ( // [HGM] holdings: blank out area between board and holdings
4386 column == BOARD_LEFT-1 || column == BOARD_RGHT
4387 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4388 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4389 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4391 // [HGM] print piece counts next to holdings
4392 string[1] = NULLCHAR;
4393 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4394 string[0] = '0' + piece;
4395 XTextExtents(countFontStruct, string, 1, &direction,
4396 &font_ascent, &font_descent, &overall);
4397 if (appData.monoMode) {
4398 XDrawImageString(xDisplay, xBoardWindow, countGC,
4399 x + squareSize - overall.width - 2,
4400 y + font_ascent + 1, string, 1);
4402 XDrawString(xDisplay, xBoardWindow, countGC,
4403 x + squareSize - overall.width - 2,
4404 y + font_ascent + 1, string, 1);
4407 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4408 string[0] = '0' + piece;
4409 XTextExtents(countFontStruct, string, 1, &direction,
4410 &font_ascent, &font_descent, &overall);
4411 if (appData.monoMode) {
4412 XDrawImageString(xDisplay, xBoardWindow, countGC,
4413 x + 2, y + font_ascent + 1, string, 1);
4415 XDrawString(xDisplay, xBoardWindow, countGC,
4416 x + 2, y + font_ascent + 1, string, 1);
4420 if (piece == EmptySquare || appData.blindfold) {
4421 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4423 drawfunc = ChooseDrawFunc();
4425 if (do_flash && appData.flashCount > 0) {
4426 for (i=0; i<appData.flashCount; ++i) {
4427 drawfunc(piece, square_color, x, y, xBoardWindow);
4428 XSync(xDisplay, False);
4429 do_flash_delay(flash_delay);
4431 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4432 XSync(xDisplay, False);
4433 do_flash_delay(flash_delay);
4436 drawfunc(piece, square_color, x, y, xBoardWindow);
4440 string[1] = NULLCHAR;
4441 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4442 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4443 string[0] = 'a' + column - BOARD_LEFT;
4444 XTextExtents(coordFontStruct, string, 1, &direction,
4445 &font_ascent, &font_descent, &overall);
4446 if (appData.monoMode) {
4447 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4448 x + squareSize - overall.width - 2,
4449 y + squareSize - font_descent - 1, string, 1);
4451 XDrawString(xDisplay, xBoardWindow, coordGC,
4452 x + squareSize - overall.width - 2,
4453 y + squareSize - font_descent - 1, string, 1);
4456 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4457 string[0] = ONE + row;
4458 XTextExtents(coordFontStruct, string, 1, &direction,
4459 &font_ascent, &font_descent, &overall);
4460 if (appData.monoMode) {
4461 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4462 x + 2, y + font_ascent + 1, string, 1);
4464 XDrawString(xDisplay, xBoardWindow, coordGC,
4465 x + 2, y + font_ascent + 1, string, 1);
4468 if(!partnerUp && marker[row][column]) {
4469 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4470 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4475 /* Why is this needed on some versions of X? */
4476 void EventProc(widget, unused, event)
4481 if (!XtIsRealized(widget))
4484 switch (event->type) {
4486 if (event->xexpose.count > 0) return; /* no clipping is done */
4487 XDrawPosition(widget, True, NULL);
4488 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4489 flipView = !flipView; partnerUp = !partnerUp;
4490 XDrawPosition(widget, True, NULL);
4491 flipView = !flipView; partnerUp = !partnerUp;
4495 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4502 void DrawPosition(fullRedraw, board)
4503 /*Boolean*/int fullRedraw;
4506 XDrawPosition(boardWidget, fullRedraw, board);
4509 /* Returns 1 if there are "too many" differences between b1 and b2
4510 (i.e. more than 1 move was made) */
4511 static int too_many_diffs(b1, b2)
4517 for (i=0; i<BOARD_HEIGHT; ++i) {
4518 for (j=0; j<BOARD_WIDTH; ++j) {
4519 if (b1[i][j] != b2[i][j]) {
4520 if (++c > 4) /* Castling causes 4 diffs */
4528 /* Matrix describing castling maneuvers */
4529 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4530 static int castling_matrix[4][5] = {
4531 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4532 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4533 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4534 { 7, 7, 4, 5, 6 } /* 0-0, black */
4537 /* Checks whether castling occurred. If it did, *rrow and *rcol
4538 are set to the destination (row,col) of the rook that moved.
4540 Returns 1 if castling occurred, 0 if not.
4542 Note: Only handles a max of 1 castling move, so be sure
4543 to call too_many_diffs() first.
4545 static int check_castle_draw(newb, oldb, rrow, rcol)
4552 /* For each type of castling... */
4553 for (i=0; i<4; ++i) {
4554 r = castling_matrix[i];
4556 /* Check the 4 squares involved in the castling move */
4558 for (j=1; j<=4; ++j) {
4559 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4566 /* All 4 changed, so it must be a castling move */
4575 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4576 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4578 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4581 void DrawSeekBackground( int left, int top, int right, int bottom )
4583 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4586 void DrawSeekText(char *buf, int x, int y)
4588 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4591 void DrawSeekDot(int x, int y, int colorNr)
4593 int square = colorNr & 0x80;
4596 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4598 XFillRectangle(xDisplay, xBoardWindow, color,
4599 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4601 XFillArc(xDisplay, xBoardWindow, color,
4602 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4605 static int damage[2][BOARD_RANKS][BOARD_FILES];
4608 * event handler for redrawing the board
4610 void XDrawPosition(w, repaint, board)
4612 /*Boolean*/int repaint;
4616 static int lastFlipView = 0;
4617 static int lastBoardValid[2] = {0, 0};
4618 static Board lastBoard[2];
4621 int nr = twoBoards*partnerUp;
4623 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4625 if (board == NULL) {
4626 if (!lastBoardValid[nr]) return;
4627 board = lastBoard[nr];
4629 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4630 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4631 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4636 * It would be simpler to clear the window with XClearWindow()
4637 * but this causes a very distracting flicker.
4640 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4642 if ( lineGap && IsDrawArrowEnabled())
4643 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4644 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4646 /* If too much changes (begin observing new game, etc.), don't
4648 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4650 /* Special check for castling so we don't flash both the king
4651 and the rook (just flash the king). */
4653 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4654 /* Draw rook with NO flashing. King will be drawn flashing later */
4655 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4656 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4660 /* First pass -- Draw (newly) empty squares and repair damage.
4661 This prevents you from having a piece show up twice while it
4662 is flashing on its new square */
4663 for (i = 0; i < BOARD_HEIGHT; i++)
4664 for (j = 0; j < BOARD_WIDTH; j++)
4665 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4666 || damage[nr][i][j]) {
4667 DrawSquare(i, j, board[i][j], 0);
4668 damage[nr][i][j] = False;
4671 /* Second pass -- Draw piece(s) in new position and flash them */
4672 for (i = 0; i < BOARD_HEIGHT; i++)
4673 for (j = 0; j < BOARD_WIDTH; j++)
4674 if (board[i][j] != lastBoard[nr][i][j]) {
4675 DrawSquare(i, j, board[i][j], do_flash);
4679 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4680 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4681 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4683 for (i = 0; i < BOARD_HEIGHT; i++)
4684 for (j = 0; j < BOARD_WIDTH; j++) {
4685 DrawSquare(i, j, board[i][j], 0);
4686 damage[nr][i][j] = False;
4690 CopyBoard(lastBoard[nr], board);
4691 lastBoardValid[nr] = 1;
4692 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4693 lastFlipView = flipView;
4695 /* Draw highlights */
4696 if (pm1X >= 0 && pm1Y >= 0) {
4697 drawHighlight(pm1X, pm1Y, prelineGC);
4699 if (pm2X >= 0 && pm2Y >= 0) {
4700 drawHighlight(pm2X, pm2Y, prelineGC);
4702 if (hi1X >= 0 && hi1Y >= 0) {
4703 drawHighlight(hi1X, hi1Y, highlineGC);
4705 if (hi2X >= 0 && hi2Y >= 0) {
4706 drawHighlight(hi2X, hi2Y, highlineGC);
4708 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4710 /* If piece being dragged around board, must redraw that too */
4713 XSync(xDisplay, False);
4718 * event handler for redrawing the board
4720 void DrawPositionProc(w, event, prms, nprms)
4726 XDrawPosition(w, True, NULL);
4731 * event handler for parsing user moves
4733 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4734 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4735 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4736 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4737 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4738 // and at the end FinishMove() to perform the move after optional promotion popups.
4739 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4740 void HandleUserMove(w, event, prms, nprms)
4746 if (w != boardWidget || errorExitStatus != -1) return;
4747 if(nprms) shiftKey = !strcmp(prms[0], "1");
4750 if (event->type == ButtonPress) {
4751 XtPopdown(promotionShell);
4752 XtDestroyWidget(promotionShell);
4753 promotionUp = False;
4761 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4762 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4763 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4766 void AnimateUserMove (Widget w, XEvent * event,
4767 String * params, Cardinal * nParams)
4769 DragPieceMove(event->xmotion.x, event->xmotion.y);
4772 void HandlePV (Widget w, XEvent * event,
4773 String * params, Cardinal * nParams)
4774 { // [HGM] pv: walk PV
4775 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4778 static int savedIndex; /* gross that this is global */
4780 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4783 XawTextPosition index, dummy;
4786 XawTextGetSelectionPos(w, &index, &dummy);
4787 XtSetArg(arg, XtNstring, &val);
4788 XtGetValues(w, &arg, 1);
4789 ReplaceComment(savedIndex, val);
4790 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4791 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4794 void EditCommentPopUp(index, title, text)
4799 if (text == NULL) text = "";
4800 NewCommentPopup(title, text, index);
4803 void ICSInputBoxPopUp()
4808 extern Option boxOptions[];
4810 void ICSInputSendText()
4817 edit = boxOptions[0].handle;
4819 XtSetArg(args[j], XtNstring, &val); j++;
4820 XtGetValues(edit, args, j);
4822 SendMultiLineToICS(val);
4823 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4824 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4827 void ICSInputBoxPopDown()
4832 void CommentPopUp(title, text)
4835 savedIndex = currentMove; // [HGM] vari
4836 NewCommentPopup(title, text, currentMove);
4839 void CommentPopDown()
4844 void FileNamePopUp(label, def, filter, proc, openMode)
4851 fileProc = proc; /* I can't see a way not */
4852 fileOpenMode = openMode; /* to use globals here */
4853 { // [HGM] use file-selector dialog stolen from Ghostview
4855 int index; // this is not supported yet
4857 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
4858 (def[0] ? def : NULL), filter, openMode, NULL, &name))
4859 (void) (*fileProc)(f, index=0, name);
4863 void FileNamePopDown()
4865 if (!filenameUp) return;
4866 XtPopdown(fileNameShell);
4867 XtDestroyWidget(fileNameShell);
4872 void FileNameCallback(w, client_data, call_data)
4874 XtPointer client_data, call_data;
4879 XtSetArg(args[0], XtNlabel, &name);
4880 XtGetValues(w, args, 1);
4882 if (strcmp(name, _("cancel")) == 0) {
4887 FileNameAction(w, NULL, NULL, NULL);
4890 void FileNameAction(w, event, prms, nprms)
4902 name = XawDialogGetValueString(w = XtParent(w));
4904 if ((name != NULL) && (*name != NULLCHAR)) {
4905 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
4906 XtPopdown(w = XtParent(XtParent(w)));
4910 p = strrchr(buf, ' ');
4917 fullname = ExpandPathName(buf);
4919 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
4922 f = fopen(fullname, fileOpenMode);
4924 DisplayError(_("Failed to open file"), errno);
4926 (void) (*fileProc)(f, index, buf);
4933 XtPopdown(w = XtParent(XtParent(w)));
4939 void PromotionPopUp()
4942 Widget dialog, layout;
4944 Dimension bw_width, pw_width;
4948 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4949 XtGetValues(boardWidget, args, j);
4952 XtSetArg(args[j], XtNresizable, True); j++;
4953 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
4955 XtCreatePopupShell("Promotion", transientShellWidgetClass,
4956 shellWidget, args, j);
4958 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
4959 layoutArgs, XtNumber(layoutArgs));
4962 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
4963 XtSetArg(args[j], XtNborderWidth, 0); j++;
4964 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
4967 if(gameInfo.variant != VariantShogi) {
4968 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
4969 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
4970 (XtPointer) dialog);
4971 XawDialogAddButton(dialog, _("General"), PromotionCallback,
4972 (XtPointer) dialog);
4973 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
4974 (XtPointer) dialog);
4975 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
4976 (XtPointer) dialog);
4978 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
4979 (XtPointer) dialog);
4980 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
4981 (XtPointer) dialog);
4982 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
4983 (XtPointer) dialog);
4984 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
4985 (XtPointer) dialog);
4987 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
4988 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4989 gameInfo.variant == VariantGiveaway) {
4990 XawDialogAddButton(dialog, _("King"), PromotionCallback,
4991 (XtPointer) dialog);
4993 if(gameInfo.variant == VariantCapablanca ||
4994 gameInfo.variant == VariantGothic ||
4995 gameInfo.variant == VariantCapaRandom) {
4996 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
4997 (XtPointer) dialog);
4998 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
4999 (XtPointer) dialog);
5001 } else // [HGM] shogi
5003 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5004 (XtPointer) dialog);
5005 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5006 (XtPointer) dialog);
5008 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5009 (XtPointer) dialog);
5011 XtRealizeWidget(promotionShell);
5012 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5015 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5016 XtGetValues(promotionShell, args, j);
5018 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5019 lineGap + squareSize/3 +
5020 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5021 0 : 6*(squareSize + lineGap)), &x, &y);
5024 XtSetArg(args[j], XtNx, x); j++;
5025 XtSetArg(args[j], XtNy, y); j++;
5026 XtSetValues(promotionShell, args, j);
5028 XtPopup(promotionShell, XtGrabNone);
5033 void PromotionPopDown()
5035 if (!promotionUp) return;
5036 XtPopdown(promotionShell);
5037 XtDestroyWidget(promotionShell);
5038 promotionUp = False;
5041 void PromotionCallback(w, client_data, call_data)
5043 XtPointer client_data, call_data;
5049 XtSetArg(args[0], XtNlabel, &name);
5050 XtGetValues(w, args, 1);
5054 if (fromX == -1) return;
5056 if (strcmp(name, _("cancel")) == 0) {
5060 } else if (strcmp(name, _("Knight")) == 0) {
5062 } else if (strcmp(name, _("Promote")) == 0) {
5064 } else if (strcmp(name, _("Defer")) == 0) {
5067 promoChar = ToLower(name[0]);
5070 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5072 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5073 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5078 void ErrorCallback(w, client_data, call_data)
5080 XtPointer client_data, call_data;
5083 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5085 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5091 if (!errorUp) return;
5093 XtPopdown(errorShell);
5094 XtDestroyWidget(errorShell);
5095 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5098 void ErrorPopUp(title, label, modal)
5099 char *title, *label;
5103 Widget dialog, layout;
5107 Dimension bw_width, pw_width;
5108 Dimension pw_height;
5112 XtSetArg(args[i], XtNresizable, True); i++;
5113 XtSetArg(args[i], XtNtitle, title); i++;
5115 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5116 shellWidget, args, i);
5118 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5119 layoutArgs, XtNumber(layoutArgs));
5122 XtSetArg(args[i], XtNlabel, label); i++;
5123 XtSetArg(args[i], XtNborderWidth, 0); i++;
5124 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5127 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5129 XtRealizeWidget(errorShell);
5130 CatchDeleteWindow(errorShell, "ErrorPopDown");
5133 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5134 XtGetValues(boardWidget, args, i);
5136 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5137 XtSetArg(args[i], XtNheight, &pw_height); i++;
5138 XtGetValues(errorShell, args, i);
5141 /* This code seems to tickle an X bug if it is executed too soon
5142 after xboard starts up. The coordinates get transformed as if
5143 the main window was positioned at (0, 0).
5145 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5146 0 - pw_height + squareSize / 3, &x, &y);
5148 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5149 RootWindowOfScreen(XtScreen(boardWidget)),
5150 (bw_width - pw_width) / 2,
5151 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5155 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5158 XtSetArg(args[i], XtNx, x); i++;
5159 XtSetArg(args[i], XtNy, y); i++;
5160 XtSetValues(errorShell, args, i);
5163 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5166 /* Disable all user input other than deleting the window */
5167 static int frozen = 0;
5171 /* Grab by a widget that doesn't accept input */
5172 XtAddGrab(messageWidget, TRUE, FALSE);
5176 /* Undo a FreezeUI */
5179 if (!frozen) return;
5180 XtRemoveGrab(messageWidget);
5184 char *ModeToWidgetName(mode)
5188 case BeginningOfGame:
5189 if (appData.icsActive)
5190 return "menuMode.ICS Client";
5191 else if (appData.noChessProgram ||
5192 *appData.cmailGameName != NULLCHAR)
5193 return "menuMode.Edit Game";
5195 return "menuMode.Machine Black";
5196 case MachinePlaysBlack:
5197 return "menuMode.Machine Black";
5198 case MachinePlaysWhite:
5199 return "menuMode.Machine White";
5201 return "menuMode.Analysis Mode";
5203 return "menuMode.Analyze File";
5204 case TwoMachinesPlay:
5205 return "menuMode.Two Machines";
5207 return "menuMode.Edit Game";
5208 case PlayFromGameFile:
5209 return "menuFile.Load Game";
5211 return "menuMode.Edit Position";
5213 return "menuMode.Training";
5214 case IcsPlayingWhite:
5215 case IcsPlayingBlack:
5219 return "menuMode.ICS Client";
5226 void ModeHighlight()
5229 static int oldPausing = FALSE;
5230 static GameMode oldmode = (GameMode) -1;
5233 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5235 if (pausing != oldPausing) {
5236 oldPausing = pausing;
5238 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5240 XtSetArg(args[0], XtNleftBitmap, None);
5242 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5245 if (appData.showButtonBar) {
5246 /* Always toggle, don't set. Previous code messes up when
5247 invoked while the button is pressed, as releasing it
5248 toggles the state again. */
5251 XtSetArg(args[0], XtNbackground, &oldbg);
5252 XtSetArg(args[1], XtNforeground, &oldfg);
5253 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5255 XtSetArg(args[0], XtNbackground, oldfg);
5256 XtSetArg(args[1], XtNforeground, oldbg);
5258 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5262 wname = ModeToWidgetName(oldmode);
5263 if (wname != NULL) {
5264 XtSetArg(args[0], XtNleftBitmap, None);
5265 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5267 wname = ModeToWidgetName(gameMode);
5268 if (wname != NULL) {
5269 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5270 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5274 /* Maybe all the enables should be handled here, not just this one */
5275 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5276 gameMode == Training || gameMode == PlayFromGameFile);
5281 * Button/menu procedures
5283 void ResetProc(w, event, prms, nprms)
5292 int LoadGamePopUp(f, gameNumber, title)
5297 cmailMsgLoaded = FALSE;
5298 if (gameNumber == 0) {
5299 int error = GameListBuild(f);
5301 DisplayError(_("Cannot build game list"), error);
5302 } else if (!ListEmpty(&gameList) &&
5303 ((ListGame *) gameList.tailPred)->number > 1) {
5304 GameListPopUp(f, title);
5310 return LoadGame(f, gameNumber, title, FALSE);
5313 void LoadGameProc(w, event, prms, nprms)
5319 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5322 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5325 void LoadNextGameProc(w, event, prms, nprms)
5334 void LoadPrevGameProc(w, event, prms, nprms)
5343 void ReloadGameProc(w, event, prms, nprms)
5352 void LoadNextPositionProc(w, event, prms, nprms)
5361 void LoadPrevPositionProc(w, event, prms, nprms)
5370 void ReloadPositionProc(w, event, prms, nprms)
5379 void LoadPositionProc(w, event, prms, nprms)
5385 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5388 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5391 void SaveGameProc(w, event, prms, nprms)
5397 FileNamePopUp(_("Save game file name?"),
5398 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5399 appData.oldSaveStyle ? ".game" : ".pgn",
5403 void SavePositionProc(w, event, prms, nprms)
5409 FileNamePopUp(_("Save position file name?"),
5410 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5411 appData.oldSaveStyle ? ".pos" : ".fen",
5415 void ReloadCmailMsgProc(w, event, prms, nprms)
5421 ReloadCmailMsgEvent(FALSE);
5424 void MailMoveProc(w, event, prms, nprms)
5433 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5434 char *selected_fen_position=NULL;
5437 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5438 Atom *type_return, XtPointer *value_return,
5439 unsigned long *length_return, int *format_return)
5441 char *selection_tmp;
5443 if (!selected_fen_position) return False; /* should never happen */
5444 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5445 /* note: since no XtSelectionDoneProc was registered, Xt will
5446 * automatically call XtFree on the value returned. So have to
5447 * make a copy of it allocated with XtMalloc */
5448 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5449 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5451 *value_return=selection_tmp;
5452 *length_return=strlen(selection_tmp);
5453 *type_return=*target;
5454 *format_return = 8; /* bits per byte */
5456 } else if (*target == XA_TARGETS(xDisplay)) {
5457 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5458 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5459 targets_tmp[1] = XA_STRING;
5460 *value_return = targets_tmp;
5461 *type_return = XA_ATOM;
5463 *format_return = 8 * sizeof(Atom);
5464 if (*format_return > 32) {
5465 *length_return *= *format_return / 32;
5466 *format_return = 32;
5474 /* note: when called from menu all parameters are NULL, so no clue what the
5475 * Widget which was clicked on was, or what the click event was
5477 void CopyPositionProc(w, event, prms, nprms)
5484 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5485 * have a notion of a position that is selected but not copied.
5486 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5488 if(gameMode == EditPosition) EditPositionDone(TRUE);
5489 if (selected_fen_position) free(selected_fen_position);
5490 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5491 if (!selected_fen_position) return;
5492 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5494 SendPositionSelection,
5495 NULL/* lose_ownership_proc */ ,
5496 NULL/* transfer_done_proc */);
5497 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5499 SendPositionSelection,
5500 NULL/* lose_ownership_proc */ ,
5501 NULL/* transfer_done_proc */);
5504 /* function called when the data to Paste is ready */
5506 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5507 Atom *type, XtPointer value, unsigned long *len, int *format)
5510 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5511 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5512 EditPositionPasteFEN(fenstr);
5516 /* called when Paste Position button is pressed,
5517 * all parameters will be NULL */
5518 void PastePositionProc(w, event, prms, nprms)
5524 XtGetSelectionValue(menuBarWidget,
5525 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5526 /* (XtSelectionCallbackProc) */ PastePositionCB,
5527 NULL, /* client_data passed to PastePositionCB */
5529 /* better to use the time field from the event that triggered the
5530 * call to this function, but that isn't trivial to get
5538 SendGameSelection(Widget w, Atom *selection, Atom *target,
5539 Atom *type_return, XtPointer *value_return,
5540 unsigned long *length_return, int *format_return)
5542 char *selection_tmp;
5544 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5545 FILE* f = fopen(gameCopyFilename, "r");
5548 if (f == NULL) return False;
5552 selection_tmp = XtMalloc(len + 1);
5553 count = fread(selection_tmp, 1, len, f);
5556 XtFree(selection_tmp);
5559 selection_tmp[len] = NULLCHAR;
5560 *value_return = selection_tmp;
5561 *length_return = len;
5562 *type_return = *target;
5563 *format_return = 8; /* bits per byte */
5565 } else if (*target == XA_TARGETS(xDisplay)) {
5566 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5567 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5568 targets_tmp[1] = XA_STRING;
5569 *value_return = targets_tmp;
5570 *type_return = XA_ATOM;
5572 *format_return = 8 * sizeof(Atom);
5573 if (*format_return > 32) {
5574 *length_return *= *format_return / 32;
5575 *format_return = 32;
5583 /* note: when called from menu all parameters are NULL, so no clue what the
5584 * Widget which was clicked on was, or what the click event was
5586 void CopyGameProc(w, event, prms, nprms)
5594 ret = SaveGameToFile(gameCopyFilename, FALSE);
5598 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5599 * have a notion of a game that is selected but not copied.
5600 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5602 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5605 NULL/* lose_ownership_proc */ ,
5606 NULL/* transfer_done_proc */);
5607 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5610 NULL/* lose_ownership_proc */ ,
5611 NULL/* transfer_done_proc */);
5614 /* function called when the data to Paste is ready */
5616 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5617 Atom *type, XtPointer value, unsigned long *len, int *format)
5620 if (value == NULL || *len == 0) {
5621 return; /* nothing had been selected to copy */
5623 f = fopen(gamePasteFilename, "w");
5625 DisplayError(_("Can't open temp file"), errno);
5628 fwrite(value, 1, *len, f);
5631 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5634 /* called when Paste Game button is pressed,
5635 * all parameters will be NULL */
5636 void PasteGameProc(w, event, prms, nprms)
5642 XtGetSelectionValue(menuBarWidget,
5643 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5644 /* (XtSelectionCallbackProc) */ PasteGameCB,
5645 NULL, /* client_data passed to PasteGameCB */
5647 /* better to use the time field from the event that triggered the
5648 * call to this function, but that isn't trivial to get
5658 SaveGameProc(NULL, NULL, NULL, NULL);
5662 void QuitProc(w, event, prms, nprms)
5671 void PauseProc(w, event, prms, nprms)
5681 void MachineBlackProc(w, event, prms, nprms)
5687 MachineBlackEvent();
5690 void MachineWhiteProc(w, event, prms, nprms)
5696 MachineWhiteEvent();
5699 void AnalyzeModeProc(w, event, prms, nprms)
5707 if (!first.analysisSupport) {
5708 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5709 DisplayError(buf, 0);
5712 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5713 if (appData.icsActive) {
5714 if (gameMode != IcsObserving) {
5715 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5716 DisplayError(buf, 0);
5718 if (appData.icsEngineAnalyze) {
5719 if (appData.debugMode)
5720 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5726 /* if enable, use want disable icsEngineAnalyze */
5727 if (appData.icsEngineAnalyze) {
5732 appData.icsEngineAnalyze = TRUE;
5733 if (appData.debugMode)
5734 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5736 #ifndef OPTIONSDIALOG
5737 if (!appData.showThinking)
5738 ShowThinkingProc(w,event,prms,nprms);
5744 void AnalyzeFileProc(w, event, prms, nprms)
5750 if (!first.analysisSupport) {
5752 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5753 DisplayError(buf, 0);
5757 #ifndef OPTIONSDIALOG
5758 if (!appData.showThinking)
5759 ShowThinkingProc(w,event,prms,nprms);
5762 FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5763 AnalysisPeriodicEvent(1);
5766 void TwoMachinesProc(w, event, prms, nprms)
5775 void MatchProc(w, event, prms, nprms)
5781 if(gameMode != BeginningOfGame) { DisplayError(_("You can only start a match from the initial position."), 0); return; }
5782 matchMode = 2; // This is back-end, really
\r
5783 appData.matchGames = appData.defaultMatchGames;
\r
5785 first.matchWins = second.matchWins = 0;
\r
5789 void IcsClientProc(w, event, prms, nprms)
5798 void EditGameProc(w, event, prms, nprms)
5807 void EditPositionProc(w, event, prms, nprms)
5813 EditPositionEvent();
5816 void TrainingProc(w, event, prms, nprms)
5825 void EditCommentProc(w, event, prms, nprms)
5833 if (PopDown(1)) { // popdown succesful
5835 XtSetArg(args[j], XtNleftBitmap, None); j++;
5836 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
5837 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
5838 } else // was not up
5842 void IcsInputBoxProc(w, event, prms, nprms)
5848 if (!PopDown(4)) ICSInputBoxPopUp();
5851 void AcceptProc(w, event, prms, nprms)
5860 void DeclineProc(w, event, prms, nprms)
5869 void RematchProc(w, event, prms, nprms)
5878 void CallFlagProc(w, event, prms, nprms)
5887 void DrawProc(w, event, prms, nprms)
5896 void AbortProc(w, event, prms, nprms)
5905 void AdjournProc(w, event, prms, nprms)
5914 void ResignProc(w, event, prms, nprms)
5923 void AdjuWhiteProc(w, event, prms, nprms)
5929 UserAdjudicationEvent(+1);
5932 void AdjuBlackProc(w, event, prms, nprms)
5938 UserAdjudicationEvent(-1);
5941 void AdjuDrawProc(w, event, prms, nprms)
5947 UserAdjudicationEvent(0);
5950 void EnterKeyProc(w, event, prms, nprms)
5956 if (shellUp[4] == True)
5960 void UpKeyProc(w, event, prms, nprms)
5965 { // [HGM] input: let up-arrow recall previous line from history
5972 if (!shellUp[4]) return;
5973 edit = boxOptions[0].handle;
5975 XtSetArg(args[j], XtNstring, &val); j++;
5976 XtGetValues(edit, args, j);
5977 val = PrevInHistory(val);
5978 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5979 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5981 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
5982 XawTextReplace(edit, 0, 0, &t);
5983 XawTextSetInsertionPoint(edit, 9999);
5987 void DownKeyProc(w, event, prms, nprms)
5992 { // [HGM] input: let down-arrow recall next line from history
5997 if (!shellUp[4]) return;
5998 edit = boxOptions[0].handle;
5999 val = NextInHistory();
6000 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6001 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6003 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6004 XawTextReplace(edit, 0, 0, &t);
6005 XawTextSetInsertionPoint(edit, 9999);
6009 void StopObservingProc(w, event, prms, nprms)
6015 StopObservingEvent();
6018 void StopExaminingProc(w, event, prms, nprms)
6024 StopExaminingEvent();
6027 void UploadProc(w, event, prms, nprms)
6037 void ForwardProc(w, event, prms, nprms)
6047 void BackwardProc(w, event, prms, nprms)
6056 void ToStartProc(w, event, prms, nprms)
6065 void ToEndProc(w, event, prms, nprms)
6074 void RevertProc(w, event, prms, nprms)
6083 void AnnotateProc(w, event, prms, nprms)
6092 void TruncateGameProc(w, event, prms, nprms)
6098 TruncateGameEvent();
6100 void RetractMoveProc(w, event, prms, nprms)
6109 void MoveNowProc(w, event, prms, nprms)
6118 void FlipViewProc(w, event, prms, nprms)
6124 flipView = !flipView;
6125 DrawPosition(True, NULL);
6128 void PonderNextMoveProc(w, event, prms, nprms)
6136 PonderNextMoveEvent(!appData.ponderNextMove);
6137 #ifndef OPTIONSDIALOG
6138 if (appData.ponderNextMove) {
6139 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6141 XtSetArg(args[0], XtNleftBitmap, None);
6143 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6148 #ifndef OPTIONSDIALOG
6149 void AlwaysQueenProc(w, event, prms, nprms)
6157 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6159 if (appData.alwaysPromoteToQueen) {
6160 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6162 XtSetArg(args[0], XtNleftBitmap, None);
6164 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6168 void AnimateDraggingProc(w, event, prms, nprms)
6176 appData.animateDragging = !appData.animateDragging;
6178 if (appData.animateDragging) {
6179 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6182 XtSetArg(args[0], XtNleftBitmap, None);
6184 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6188 void AnimateMovingProc(w, event, prms, nprms)
6196 appData.animate = !appData.animate;
6198 if (appData.animate) {
6199 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6202 XtSetArg(args[0], XtNleftBitmap, None);
6204 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6208 void AutoflagProc(w, event, prms, nprms)
6216 appData.autoCallFlag = !appData.autoCallFlag;
6218 if (appData.autoCallFlag) {
6219 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6221 XtSetArg(args[0], XtNleftBitmap, None);
6223 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6227 void AutoflipProc(w, event, prms, nprms)
6235 appData.autoFlipView = !appData.autoFlipView;
6237 if (appData.autoFlipView) {
6238 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6240 XtSetArg(args[0], XtNleftBitmap, None);
6242 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6246 void BlindfoldProc(w, event, prms, nprms)
6254 appData.blindfold = !appData.blindfold;
6256 if (appData.blindfold) {
6257 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6259 XtSetArg(args[0], XtNleftBitmap, None);
6261 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6264 DrawPosition(True, NULL);
6267 void TestLegalityProc(w, event, prms, nprms)
6275 appData.testLegality = !appData.testLegality;
6277 if (appData.testLegality) {
6278 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6280 XtSetArg(args[0], XtNleftBitmap, None);
6282 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6287 void FlashMovesProc(w, event, prms, nprms)
6295 if (appData.flashCount == 0) {
6296 appData.flashCount = 3;
6298 appData.flashCount = -appData.flashCount;
6301 if (appData.flashCount > 0) {
6302 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6304 XtSetArg(args[0], XtNleftBitmap, None);
6306 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6311 void HighlightDraggingProc(w, event, prms, nprms)
6319 appData.highlightDragging = !appData.highlightDragging;
6321 if (appData.highlightDragging) {
6322 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6324 XtSetArg(args[0], XtNleftBitmap, None);
6326 XtSetValues(XtNameToWidget(menuBarWidget,
6327 "menuOptions.Highlight Dragging"), args, 1);
6331 void HighlightLastMoveProc(w, event, prms, nprms)
6339 appData.highlightLastMove = !appData.highlightLastMove;
6341 if (appData.highlightLastMove) {
6342 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6344 XtSetArg(args[0], XtNleftBitmap, None);
6346 XtSetValues(XtNameToWidget(menuBarWidget,
6347 "menuOptions.Highlight Last Move"), args, 1);
6350 void HighlightArrowProc(w, event, prms, nprms)
6358 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6360 if (appData.highlightMoveWithArrow) {
6361 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6363 XtSetArg(args[0], XtNleftBitmap, None);
6365 XtSetValues(XtNameToWidget(menuBarWidget,
6366 "menuOptions.Arrow"), args, 1);
6370 void IcsAlarmProc(w, event, prms, nprms)
6378 appData.icsAlarm = !appData.icsAlarm;
6380 if (appData.icsAlarm) {
6381 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6383 XtSetArg(args[0], XtNleftBitmap, None);
6385 XtSetValues(XtNameToWidget(menuBarWidget,
6386 "menuOptions.ICS Alarm"), args, 1);
6390 void MoveSoundProc(w, event, prms, nprms)
6398 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6400 if (appData.ringBellAfterMoves) {
6401 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6403 XtSetArg(args[0], XtNleftBitmap, None);
6405 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6409 void OneClickProc(w, event, prms, nprms)
6417 appData.oneClick = !appData.oneClick;
6419 if (appData.oneClick) {
6420 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6422 XtSetArg(args[0], XtNleftBitmap, None);
6424 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6428 void PeriodicUpdatesProc(w, event, prms, nprms)
6436 PeriodicUpdatesEvent(!appData.periodicUpdates);
6438 if (appData.periodicUpdates) {
6439 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6441 XtSetArg(args[0], XtNleftBitmap, None);
6443 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6447 void PopupExitMessageProc(w, event, prms, nprms)
6455 appData.popupExitMessage = !appData.popupExitMessage;
6457 if (appData.popupExitMessage) {
6458 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6460 XtSetArg(args[0], XtNleftBitmap, None);
6462 XtSetValues(XtNameToWidget(menuBarWidget,
6463 "menuOptions.Popup Exit Message"), args, 1);
6466 void PopupMoveErrorsProc(w, event, prms, nprms)
6474 appData.popupMoveErrors = !appData.popupMoveErrors;
6476 if (appData.popupMoveErrors) {
6477 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6479 XtSetArg(args[0], XtNleftBitmap, None);
6481 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6486 void PremoveProc(w, event, prms, nprms)
6494 appData.premove = !appData.premove;
6496 if (appData.premove) {
6497 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6499 XtSetArg(args[0], XtNleftBitmap, None);
6501 XtSetValues(XtNameToWidget(menuBarWidget,
6502 "menuOptions.Premove"), args, 1);
6506 void ShowCoordsProc(w, event, prms, nprms)
6514 appData.showCoords = !appData.showCoords;
6516 if (appData.showCoords) {
6517 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6519 XtSetArg(args[0], XtNleftBitmap, None);
6521 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6524 DrawPosition(True, NULL);
6527 void ShowThinkingProc(w, event, prms, nprms)
6533 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6534 ShowThinkingEvent();
6537 void HideThinkingProc(w, event, prms, nprms)
6545 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6546 ShowThinkingEvent();
6548 if (appData.hideThinkingFromHuman) {
6549 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6551 XtSetArg(args[0], XtNleftBitmap, None);
6553 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6558 void SaveOnExitProc(w, event, prms, nprms)
6566 saveSettingsOnExit = !saveSettingsOnExit;
6568 if (saveSettingsOnExit) {
6569 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6571 XtSetArg(args[0], XtNleftBitmap, None);
6573 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6577 void SaveSettingsProc(w, event, prms, nprms)
6583 SaveSettings(settingsFileName);
6586 void InfoProc(w, event, prms, nprms)
6593 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6598 void ManProc(w, event, prms, nprms)
6606 if (nprms && *nprms > 0)
6610 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6614 void HintProc(w, event, prms, nprms)
6623 void BookProc(w, event, prms, nprms)
6632 void AboutProc(w, event, prms, nprms)
6640 char *zippy = " (with Zippy code)";
6644 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6645 programVersion, zippy,
6646 "Copyright 1991 Digital Equipment Corporation",
6647 "Enhancements Copyright 1992-2009 Free Software Foundation",
6648 "Enhancements Copyright 2005 Alessandro Scotti",
6649 PACKAGE, " is free software and carries NO WARRANTY;",
6650 "see the file COPYING for more information.");
6651 ErrorPopUp(_("About XBoard"), buf, FALSE);
6654 void DebugProc(w, event, prms, nprms)
6660 appData.debugMode = !appData.debugMode;
6663 void AboutGameProc(w, event, prms, nprms)
6672 void NothingProc(w, event, prms, nprms)
6681 void Iconify(w, event, prms, nprms)
6690 XtSetArg(args[0], XtNiconic, True);
6691 XtSetValues(shellWidget, args, 1);
6694 void DisplayMessage(message, extMessage)
6695 char *message, *extMessage;
6697 /* display a message in the message widget */
6706 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6711 message = extMessage;
6715 /* need to test if messageWidget already exists, since this function
6716 can also be called during the startup, if for example a Xresource
6717 is not set up correctly */
6720 XtSetArg(arg, XtNlabel, message);
6721 XtSetValues(messageWidget, &arg, 1);
6727 void DisplayTitle(text)
6732 char title[MSG_SIZ];
6735 if (text == NULL) text = "";
6737 if (appData.titleInWindow) {
6739 XtSetArg(args[i], XtNlabel, text); i++;
6740 XtSetValues(titleWidget, args, i);
6743 if (*text != NULLCHAR) {
6744 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6745 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6746 } else if (appData.icsActive) {
6747 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6748 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6749 } else if (appData.cmailGameName[0] != NULLCHAR) {
6750 snprintf(icon, sizeof(icon), "%s", "CMail");
6751 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6753 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6754 } else if (gameInfo.variant == VariantGothic) {
6755 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6756 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6759 } else if (gameInfo.variant == VariantFalcon) {
6760 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6761 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6763 } else if (appData.noChessProgram) {
6764 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6765 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6767 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6768 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6771 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6772 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6773 XtSetValues(shellWidget, args, i);
6778 DisplayError(message, error)
6785 if (appData.debugMode || appData.matchMode) {
6786 fprintf(stderr, "%s: %s\n", programName, message);
6789 if (appData.debugMode || appData.matchMode) {
6790 fprintf(stderr, "%s: %s: %s\n",
6791 programName, message, strerror(error));
6793 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6796 ErrorPopUp(_("Error"), message, FALSE);
6800 void DisplayMoveError(message)
6805 DrawPosition(FALSE, NULL);
6806 if (appData.debugMode || appData.matchMode) {
6807 fprintf(stderr, "%s: %s\n", programName, message);
6809 if (appData.popupMoveErrors) {
6810 ErrorPopUp(_("Error"), message, FALSE);
6812 DisplayMessage(message, "");
6817 void DisplayFatalError(message, error, status)
6823 errorExitStatus = status;
6825 fprintf(stderr, "%s: %s\n", programName, message);
6827 fprintf(stderr, "%s: %s: %s\n",
6828 programName, message, strerror(error));
6829 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6832 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6833 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6839 void DisplayInformation(message)
6843 ErrorPopUp(_("Information"), message, TRUE);
6846 void DisplayNote(message)
6850 ErrorPopUp(_("Note"), message, FALSE);
6854 NullXErrorCheck(dpy, error_event)
6856 XErrorEvent *error_event;
6861 void DisplayIcsInteractionTitle(message)
6864 if (oldICSInteractionTitle == NULL) {
6865 /* Magic to find the old window title, adapted from vim */
6866 char *wina = getenv("WINDOWID");
6868 Window win = (Window) atoi(wina);
6869 Window root, parent, *children;
6870 unsigned int nchildren;
6871 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6873 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6874 if (!XQueryTree(xDisplay, win, &root, &parent,
6875 &children, &nchildren)) break;
6876 if (children) XFree((void *)children);
6877 if (parent == root || parent == 0) break;
6880 XSetErrorHandler(oldHandler);
6882 if (oldICSInteractionTitle == NULL) {
6883 oldICSInteractionTitle = "xterm";
6886 printf("\033]0;%s\007", message);
6890 char pendingReplyPrefix[MSG_SIZ];
6891 ProcRef pendingReplyPR;
6893 void AskQuestionProc(w, event, prms, nprms)
6900 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6904 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6907 void AskQuestionPopDown()
6909 if (!askQuestionUp) return;
6910 XtPopdown(askQuestionShell);
6911 XtDestroyWidget(askQuestionShell);
6912 askQuestionUp = False;
6915 void AskQuestionReplyAction(w, event, prms, nprms)
6925 reply = XawDialogGetValueString(w = XtParent(w));
6926 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
6927 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
6928 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
6929 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
6930 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6931 AskQuestionPopDown();
6933 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
6936 void AskQuestionCallback(w, client_data, call_data)
6938 XtPointer client_data, call_data;
6943 XtSetArg(args[0], XtNlabel, &name);
6944 XtGetValues(w, args, 1);
6946 if (strcmp(name, _("cancel")) == 0) {
6947 AskQuestionPopDown();
6949 AskQuestionReplyAction(w, NULL, NULL, NULL);
6953 void AskQuestion(title, question, replyPrefix, pr)
6954 char *title, *question, *replyPrefix;
6958 Widget popup, layout, dialog, edit;
6964 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
6965 pendingReplyPR = pr;
6968 XtSetArg(args[i], XtNresizable, True); i++;
6969 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
6970 askQuestionShell = popup =
6971 XtCreatePopupShell(title, transientShellWidgetClass,
6972 shellWidget, args, i);
6975 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
6976 layoutArgs, XtNumber(layoutArgs));
6979 XtSetArg(args[i], XtNlabel, question); i++;
6980 XtSetArg(args[i], XtNvalue, ""); i++;
6981 XtSetArg(args[i], XtNborderWidth, 0); i++;
6982 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
6985 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
6986 (XtPointer) dialog);
6987 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
6988 (XtPointer) dialog);
6990 XtRealizeWidget(popup);
6991 CatchDeleteWindow(popup, "AskQuestionPopDown");
6993 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
6994 &x, &y, &win_x, &win_y, &mask);
6996 XtSetArg(args[0], XtNx, x - 10);
6997 XtSetArg(args[1], XtNy, y - 30);
6998 XtSetValues(popup, args, 2);
7000 XtPopup(popup, XtGrabExclusive);
7001 askQuestionUp = True;
7003 edit = XtNameToWidget(dialog, "*value");
7004 XtSetKeyboardFocus(popup, edit);
7012 if (*name == NULLCHAR) {
7014 } else if (strcmp(name, "$") == 0) {
7015 putc(BELLCHAR, stderr);
7018 char *prefix = "", *sep = "";
7019 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7020 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7028 PlaySound(appData.soundMove);
7034 PlaySound(appData.soundIcsWin);
7040 PlaySound(appData.soundIcsLoss);
7046 PlaySound(appData.soundIcsDraw);
7050 PlayIcsUnfinishedSound()
7052 PlaySound(appData.soundIcsUnfinished);
7058 PlaySound(appData.soundIcsAlarm);
7064 system("stty echo");
7070 system("stty -echo");
7074 Colorize(cc, continuation)
7079 int count, outCount, error;
7081 if (textColors[(int)cc].bg > 0) {
7082 if (textColors[(int)cc].fg > 0) {
7083 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7084 textColors[(int)cc].fg, textColors[(int)cc].bg);
7086 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7087 textColors[(int)cc].bg);
7090 if (textColors[(int)cc].fg > 0) {
7091 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7092 textColors[(int)cc].fg);
7094 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7097 count = strlen(buf);
7098 outCount = OutputToProcess(NoProc, buf, count, &error);
7099 if (outCount < count) {
7100 DisplayFatalError(_("Error writing to display"), error, 1);
7103 if (continuation) return;
7106 PlaySound(appData.soundShout);
7109 PlaySound(appData.soundSShout);
7112 PlaySound(appData.soundChannel1);
7115 PlaySound(appData.soundChannel);
7118 PlaySound(appData.soundKibitz);
7121 PlaySound(appData.soundTell);
7123 case ColorChallenge:
7124 PlaySound(appData.soundChallenge);
7127 PlaySound(appData.soundRequest);
7130 PlaySound(appData.soundSeek);
7141 return getpwuid(getuid())->pw_name;
7145 ExpandPathName(path)
7148 static char static_buf[4*MSG_SIZ];
7149 char *d, *s, buf[4*MSG_SIZ];
7155 while (*s && isspace(*s))
7164 if (*(s+1) == '/') {
7165 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7169 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7170 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7171 pwd = getpwnam(buf);
7174 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7178 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7179 strcat(d, strchr(s+1, '/'));
7183 safeStrCpy(d, s, 4*MSG_SIZ );
7190 static char host_name[MSG_SIZ];
7192 #if HAVE_GETHOSTNAME
7193 gethostname(host_name, MSG_SIZ);
7195 #else /* not HAVE_GETHOSTNAME */
7196 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7197 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7199 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7201 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7202 #endif /* not HAVE_GETHOSTNAME */
7205 XtIntervalId delayedEventTimerXID = 0;
7206 DelayedEventCallback delayedEventCallback = 0;
7211 delayedEventTimerXID = 0;
7212 delayedEventCallback();
7216 ScheduleDelayedEvent(cb, millisec)
7217 DelayedEventCallback cb; long millisec;
7219 if(delayedEventTimerXID && delayedEventCallback == cb)
7220 // [HGM] alive: replace, rather than add or flush identical event
7221 XtRemoveTimeOut(delayedEventTimerXID);
7222 delayedEventCallback = cb;
7223 delayedEventTimerXID =
7224 XtAppAddTimeOut(appContext, millisec,
7225 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7228 DelayedEventCallback
7231 if (delayedEventTimerXID) {
7232 return delayedEventCallback;
7239 CancelDelayedEvent()
7241 if (delayedEventTimerXID) {
7242 XtRemoveTimeOut(delayedEventTimerXID);
7243 delayedEventTimerXID = 0;
7247 XtIntervalId loadGameTimerXID = 0;
7249 int LoadGameTimerRunning()
7251 return loadGameTimerXID != 0;
7254 int StopLoadGameTimer()
7256 if (loadGameTimerXID != 0) {
7257 XtRemoveTimeOut(loadGameTimerXID);
7258 loadGameTimerXID = 0;
7266 LoadGameTimerCallback(arg, id)
7270 loadGameTimerXID = 0;
7275 StartLoadGameTimer(millisec)
7279 XtAppAddTimeOut(appContext, millisec,
7280 (XtTimerCallbackProc) LoadGameTimerCallback,
7284 XtIntervalId analysisClockXID = 0;
7287 AnalysisClockCallback(arg, id)
7291 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7292 || appData.icsEngineAnalyze) { // [DM]
7293 AnalysisPeriodicEvent(0);
7294 StartAnalysisClock();
7299 StartAnalysisClock()
7302 XtAppAddTimeOut(appContext, 2000,
7303 (XtTimerCallbackProc) AnalysisClockCallback,
7307 XtIntervalId clockTimerXID = 0;
7309 int ClockTimerRunning()
7311 return clockTimerXID != 0;
7314 int StopClockTimer()
7316 if (clockTimerXID != 0) {
7317 XtRemoveTimeOut(clockTimerXID);
7326 ClockTimerCallback(arg, id)
7335 StartClockTimer(millisec)
7339 XtAppAddTimeOut(appContext, millisec,
7340 (XtTimerCallbackProc) ClockTimerCallback,
7345 DisplayTimerLabel(w, color, timer, highlight)
7354 /* check for low time warning */
7355 Pixel foregroundOrWarningColor = timerForegroundPixel;
7358 appData.lowTimeWarning &&
7359 (timer / 1000) < appData.icsAlarmTime)
7360 foregroundOrWarningColor = lowTimeWarningColor;
7362 if (appData.clockMode) {
7363 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7364 XtSetArg(args[0], XtNlabel, buf);
7366 snprintf(buf, MSG_SIZ, "%s ", color);
7367 XtSetArg(args[0], XtNlabel, buf);
7372 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7373 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7375 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7376 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7379 XtSetValues(w, args, 3);
7383 DisplayWhiteClock(timeRemaining, highlight)
7389 if(appData.noGUI) return;
7390 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7391 if (highlight && iconPixmap == bIconPixmap) {
7392 iconPixmap = wIconPixmap;
7393 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7394 XtSetValues(shellWidget, args, 1);
7399 DisplayBlackClock(timeRemaining, highlight)
7405 if(appData.noGUI) return;
7406 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7407 if (highlight && iconPixmap == wIconPixmap) {
7408 iconPixmap = bIconPixmap;
7409 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7410 XtSetValues(shellWidget, args, 1);
7428 int StartChildProcess(cmdLine, dir, pr)
7435 int to_prog[2], from_prog[2];
7439 if (appData.debugMode) {
7440 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7443 /* We do NOT feed the cmdLine to the shell; we just
7444 parse it into blank-separated arguments in the
7445 most simple-minded way possible.
7448 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7451 while(*p == ' ') p++;
7453 if(*p == '"' || *p == '\'')
7454 p = strchr(++argv[i-1], *p);
7455 else p = strchr(p, ' ');
7456 if (p == NULL) break;
7461 SetUpChildIO(to_prog, from_prog);
7463 if ((pid = fork()) == 0) {
7465 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7466 close(to_prog[1]); // first close the unused pipe ends
7467 close(from_prog[0]);
7468 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7469 dup2(from_prog[1], 1);
7470 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7471 close(from_prog[1]); // and closing again loses one of the pipes!
7472 if(fileno(stderr) >= 2) // better safe than sorry...
7473 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7475 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7480 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7482 execvp(argv[0], argv);
7484 /* If we get here, exec failed */
7489 /* Parent process */
7491 close(from_prog[1]);
7493 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7496 cp->fdFrom = from_prog[0];
7497 cp->fdTo = to_prog[1];
7502 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7503 static RETSIGTYPE AlarmCallBack(int n)
7509 DestroyChildProcess(pr, signalType)
7513 ChildProc *cp = (ChildProc *) pr;
7515 if (cp->kind != CPReal) return;
7517 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7518 signal(SIGALRM, AlarmCallBack);
7520 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7521 kill(cp->pid, SIGKILL); // kill it forcefully
7522 wait((int *) 0); // and wait again
7526 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7528 /* Process is exiting either because of the kill or because of
7529 a quit command sent by the backend; either way, wait for it to die.
7538 InterruptChildProcess(pr)
7541 ChildProc *cp = (ChildProc *) pr;
7543 if (cp->kind != CPReal) return;
7544 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7547 int OpenTelnet(host, port, pr)
7552 char cmdLine[MSG_SIZ];
7554 if (port[0] == NULLCHAR) {
7555 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7557 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7559 return StartChildProcess(cmdLine, "", pr);
7562 int OpenTCP(host, port, pr)
7568 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7569 #else /* !OMIT_SOCKETS */
7571 struct sockaddr_in sa;
7573 unsigned short uport;
7576 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7580 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7581 sa.sin_family = AF_INET;
7582 sa.sin_addr.s_addr = INADDR_ANY;
7583 uport = (unsigned short) 0;
7584 sa.sin_port = htons(uport);
7585 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7589 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7590 if (!(hp = gethostbyname(host))) {
7592 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7593 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7594 hp->h_addrtype = AF_INET;
7596 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7597 hp->h_addr_list[0] = (char *) malloc(4);
7598 hp->h_addr_list[0][0] = b0;
7599 hp->h_addr_list[0][1] = b1;
7600 hp->h_addr_list[0][2] = b2;
7601 hp->h_addr_list[0][3] = b3;
7606 sa.sin_family = hp->h_addrtype;
7607 uport = (unsigned short) atoi(port);
7608 sa.sin_port = htons(uport);
7609 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7611 if (connect(s, (struct sockaddr *) &sa,
7612 sizeof(struct sockaddr_in)) < 0) {
7616 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7623 #endif /* !OMIT_SOCKETS */
7628 int OpenCommPort(name, pr)
7635 fd = open(name, 2, 0);
7636 if (fd < 0) return errno;
7638 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7648 int OpenLoopback(pr)
7654 SetUpChildIO(to, from);
7656 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7659 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7666 int OpenRcmd(host, user, cmd, pr)
7667 char *host, *user, *cmd;
7670 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7674 #define INPUT_SOURCE_BUF_SIZE 8192
7683 char buf[INPUT_SOURCE_BUF_SIZE];
7688 DoInputCallback(closure, source, xid)
7693 InputSource *is = (InputSource *) closure;
7698 if (is->lineByLine) {
7699 count = read(is->fd, is->unused,
7700 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7702 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7705 is->unused += count;
7707 while (p < is->unused) {
7708 q = memchr(p, '\n', is->unused - p);
7709 if (q == NULL) break;
7711 (is->func)(is, is->closure, p, q - p, 0);
7715 while (p < is->unused) {
7720 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7725 (is->func)(is, is->closure, is->buf, count, error);
7729 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7736 ChildProc *cp = (ChildProc *) pr;
7738 is = (InputSource *) calloc(1, sizeof(InputSource));
7739 is->lineByLine = lineByLine;
7743 is->fd = fileno(stdin);
7745 is->kind = cp->kind;
7746 is->fd = cp->fdFrom;
7749 is->unused = is->buf;
7752 is->xid = XtAppAddInput(appContext, is->fd,
7753 (XtPointer) (XtInputReadMask),
7754 (XtInputCallbackProc) DoInputCallback,
7756 is->closure = closure;
7757 return (InputSourceRef) is;
7761 RemoveInputSource(isr)
7764 InputSource *is = (InputSource *) isr;
7766 if (is->xid == 0) return;
7767 XtRemoveInput(is->xid);
7771 int OutputToProcess(pr, message, count, outError)
7777 static int line = 0;
7778 ChildProc *cp = (ChildProc *) pr;
7783 if (appData.noJoin || !appData.useInternalWrap)
7784 outCount = fwrite(message, 1, count, stdout);
7787 int width = get_term_width();
7788 int len = wrap(NULL, message, count, width, &line);
7789 char *msg = malloc(len);
7793 outCount = fwrite(message, 1, count, stdout);
7796 dbgchk = wrap(msg, message, count, width, &line);
7797 if (dbgchk != len && appData.debugMode)
7798 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7799 outCount = fwrite(msg, 1, dbgchk, stdout);
7805 outCount = write(cp->fdTo, message, count);
7815 /* Output message to process, with "ms" milliseconds of delay
7816 between each character. This is needed when sending the logon
7817 script to ICC, which for some reason doesn't like the
7818 instantaneous send. */
7819 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7826 ChildProc *cp = (ChildProc *) pr;
7831 r = write(cp->fdTo, message++, 1);
7844 /**** Animation code by Hugh Fisher, DCS, ANU.
7846 Known problem: if a window overlapping the board is
7847 moved away while a piece is being animated underneath,
7848 the newly exposed area won't be updated properly.
7849 I can live with this.
7851 Known problem: if you look carefully at the animation
7852 of pieces in mono mode, they are being drawn as solid
7853 shapes without interior detail while moving. Fixing
7854 this would be a major complication for minimal return.
7857 /* Masks for XPM pieces. Black and white pieces can have
7858 different shapes, but in the interest of retaining my
7859 sanity pieces must have the same outline on both light
7860 and dark squares, and all pieces must use the same
7861 background square colors/images. */
7863 static int xpmDone = 0;
7866 CreateAnimMasks (pieceDepth)
7873 unsigned long plane;
7876 /* Need a bitmap just to get a GC with right depth */
7877 buf = XCreatePixmap(xDisplay, xBoardWindow,
7879 values.foreground = 1;
7880 values.background = 0;
7881 /* Don't use XtGetGC, not read only */
7882 maskGC = XCreateGC(xDisplay, buf,
7883 GCForeground | GCBackground, &values);
7884 XFreePixmap(xDisplay, buf);
7886 buf = XCreatePixmap(xDisplay, xBoardWindow,
7887 squareSize, squareSize, pieceDepth);
7888 values.foreground = XBlackPixel(xDisplay, xScreen);
7889 values.background = XWhitePixel(xDisplay, xScreen);
7890 bufGC = XCreateGC(xDisplay, buf,
7891 GCForeground | GCBackground, &values);
7893 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7894 /* Begin with empty mask */
7895 if(!xpmDone) // [HGM] pieces: keep using existing
7896 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7897 squareSize, squareSize, 1);
7898 XSetFunction(xDisplay, maskGC, GXclear);
7899 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7900 0, 0, squareSize, squareSize);
7902 /* Take a copy of the piece */
7907 XSetFunction(xDisplay, bufGC, GXcopy);
7908 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7910 0, 0, squareSize, squareSize, 0, 0);
7912 /* XOR the background (light) over the piece */
7913 XSetFunction(xDisplay, bufGC, GXxor);
7915 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7916 0, 0, squareSize, squareSize, 0, 0);
7918 XSetForeground(xDisplay, bufGC, lightSquareColor);
7919 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7922 /* We now have an inverted piece image with the background
7923 erased. Construct mask by just selecting all the non-zero
7924 pixels - no need to reconstruct the original image. */
7925 XSetFunction(xDisplay, maskGC, GXor);
7927 /* Might be quicker to download an XImage and create bitmap
7928 data from it rather than this N copies per piece, but it
7929 only takes a fraction of a second and there is a much
7930 longer delay for loading the pieces. */
7931 for (n = 0; n < pieceDepth; n ++) {
7932 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7933 0, 0, squareSize, squareSize,
7939 XFreePixmap(xDisplay, buf);
7940 XFreeGC(xDisplay, bufGC);
7941 XFreeGC(xDisplay, maskGC);
7945 InitAnimState (anim, info)
7947 XWindowAttributes * info;
7952 /* Each buffer is square size, same depth as window */
7953 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
7954 squareSize, squareSize, info->depth);
7955 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
7956 squareSize, squareSize, info->depth);
7958 /* Create a plain GC for blitting */
7959 mask = GCForeground | GCBackground | GCFunction |
7960 GCPlaneMask | GCGraphicsExposures;
7961 values.foreground = XBlackPixel(xDisplay, xScreen);
7962 values.background = XWhitePixel(xDisplay, xScreen);
7963 values.function = GXcopy;
7964 values.plane_mask = AllPlanes;
7965 values.graphics_exposures = False;
7966 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
7968 /* Piece will be copied from an existing context at
7969 the start of each new animation/drag. */
7970 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
7972 /* Outline will be a read-only copy of an existing */
7973 anim->outlineGC = None;
7979 XWindowAttributes info;
7981 if (xpmDone && gameInfo.variant == oldVariant) return;
7982 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
7983 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
7985 InitAnimState(&game, &info);
7986 InitAnimState(&player, &info);
7988 /* For XPM pieces, we need bitmaps to use as masks. */
7990 CreateAnimMasks(info.depth);
7996 static Boolean frameWaiting;
7998 static RETSIGTYPE FrameAlarm (sig)
8001 frameWaiting = False;
8002 /* In case System-V style signals. Needed?? */
8003 signal(SIGALRM, FrameAlarm);
8010 struct itimerval delay;
8012 XSync(xDisplay, False);
8015 frameWaiting = True;
8016 signal(SIGALRM, FrameAlarm);
8017 delay.it_interval.tv_sec =
8018 delay.it_value.tv_sec = time / 1000;
8019 delay.it_interval.tv_usec =
8020 delay.it_value.tv_usec = (time % 1000) * 1000;
8021 setitimer(ITIMER_REAL, &delay, NULL);
8022 while (frameWaiting) pause();
8023 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8024 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8025 setitimer(ITIMER_REAL, &delay, NULL);
8035 XSync(xDisplay, False);
8037 usleep(time * 1000);
8042 /* Convert board position to corner of screen rect and color */
8045 ScreenSquare(column, row, pt, color)
8046 int column; int row; XPoint * pt; int * color;
8049 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8050 pt->y = lineGap + row * (squareSize + lineGap);
8052 pt->x = lineGap + column * (squareSize + lineGap);
8053 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8055 *color = SquareColor(row, column);
8058 /* Convert window coords to square */
8061 BoardSquare(x, y, column, row)
8062 int x; int y; int * column; int * row;
8064 *column = EventToSquare(x, BOARD_WIDTH);
8065 if (flipView && *column >= 0)
8066 *column = BOARD_WIDTH - 1 - *column;
8067 *row = EventToSquare(y, BOARD_HEIGHT);
8068 if (!flipView && *row >= 0)
8069 *row = BOARD_HEIGHT - 1 - *row;
8074 #undef Max /* just in case */
8076 #define Max(a, b) ((a) > (b) ? (a) : (b))
8077 #define Min(a, b) ((a) < (b) ? (a) : (b))
8080 SetRect(rect, x, y, width, height)
8081 XRectangle * rect; int x; int y; int width; int height;
8085 rect->width = width;
8086 rect->height = height;
8089 /* Test if two frames overlap. If they do, return
8090 intersection rect within old and location of
8091 that rect within new. */
8094 Intersect(old, new, size, area, pt)
8095 XPoint * old; XPoint * new;
8096 int size; XRectangle * area; XPoint * pt;
8098 if (old->x > new->x + size || new->x > old->x + size ||
8099 old->y > new->y + size || new->y > old->y + size) {
8102 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8103 size - abs(old->x - new->x), size - abs(old->y - new->y));
8104 pt->x = Max(old->x - new->x, 0);
8105 pt->y = Max(old->y - new->y, 0);
8110 /* For two overlapping frames, return the rect(s)
8111 in the old that do not intersect with the new. */
8114 CalcUpdateRects(old, new, size, update, nUpdates)
8115 XPoint * old; XPoint * new; int size;
8116 XRectangle update[]; int * nUpdates;
8120 /* If old = new (shouldn't happen) then nothing to draw */
8121 if (old->x == new->x && old->y == new->y) {
8125 /* Work out what bits overlap. Since we know the rects
8126 are the same size we don't need a full intersect calc. */
8128 /* Top or bottom edge? */
8129 if (new->y > old->y) {
8130 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8132 } else if (old->y > new->y) {
8133 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8134 size, old->y - new->y);
8137 /* Left or right edge - don't overlap any update calculated above. */
8138 if (new->x > old->x) {
8139 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8140 new->x - old->x, size - abs(new->y - old->y));
8142 } else if (old->x > new->x) {
8143 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8144 old->x - new->x, size - abs(new->y - old->y));
8151 /* Generate a series of frame coords from start->mid->finish.
8152 The movement rate doubles until the half way point is
8153 reached, then halves back down to the final destination,
8154 which gives a nice slow in/out effect. The algorithmn
8155 may seem to generate too many intermediates for short
8156 moves, but remember that the purpose is to attract the
8157 viewers attention to the piece about to be moved and
8158 then to where it ends up. Too few frames would be less
8162 Tween(start, mid, finish, factor, frames, nFrames)
8163 XPoint * start; XPoint * mid;
8164 XPoint * finish; int factor;
8165 XPoint frames[]; int * nFrames;
8167 int fraction, n, count;
8171 /* Slow in, stepping 1/16th, then 1/8th, ... */
8173 for (n = 0; n < factor; n++)
8175 for (n = 0; n < factor; n++) {
8176 frames[count].x = start->x + (mid->x - start->x) / fraction;
8177 frames[count].y = start->y + (mid->y - start->y) / fraction;
8179 fraction = fraction / 2;
8183 frames[count] = *mid;
8186 /* Slow out, stepping 1/2, then 1/4, ... */
8188 for (n = 0; n < factor; n++) {
8189 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8190 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8192 fraction = fraction * 2;
8197 /* Draw a piece on the screen without disturbing what's there */
8200 SelectGCMask(piece, clip, outline, mask)
8201 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8205 /* Bitmap for piece being moved. */
8206 if (appData.monoMode) {
8207 *mask = *pieceToSolid(piece);
8208 } else if (useImages) {
8210 *mask = xpmMask[piece];
8212 *mask = ximMaskPm[piece];
8215 *mask = *pieceToSolid(piece);
8218 /* GC for piece being moved. Square color doesn't matter, but
8219 since it gets modified we make a copy of the original. */
8221 if (appData.monoMode)
8226 if (appData.monoMode)
8231 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8233 /* Outline only used in mono mode and is not modified */
8235 *outline = bwPieceGC;
8237 *outline = wbPieceGC;
8241 OverlayPiece(piece, clip, outline, dest)
8242 ChessSquare piece; GC clip; GC outline; Drawable dest;
8247 /* Draw solid rectangle which will be clipped to shape of piece */
8248 XFillRectangle(xDisplay, dest, clip,
8249 0, 0, squareSize, squareSize);
8250 if (appData.monoMode)
8251 /* Also draw outline in contrasting color for black
8252 on black / white on white cases */
8253 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8254 0, 0, squareSize, squareSize, 0, 0, 1);
8256 /* Copy the piece */
8261 if(appData.upsideDown && flipView) kind ^= 2;
8262 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8264 0, 0, squareSize, squareSize,
8269 /* Animate the movement of a single piece */
8272 BeginAnimation(anim, piece, startColor, start)
8280 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8281 /* The old buffer is initialised with the start square (empty) */
8282 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8283 anim->prevFrame = *start;
8285 /* The piece will be drawn using its own bitmap as a matte */
8286 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8287 XSetClipMask(xDisplay, anim->pieceGC, mask);
8291 AnimationFrame(anim, frame, piece)
8296 XRectangle updates[4];
8301 /* Save what we are about to draw into the new buffer */
8302 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8303 frame->x, frame->y, squareSize, squareSize,
8306 /* Erase bits of the previous frame */
8307 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8308 /* Where the new frame overlapped the previous,
8309 the contents in newBuf are wrong. */
8310 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8311 overlap.x, overlap.y,
8312 overlap.width, overlap.height,
8314 /* Repaint the areas in the old that don't overlap new */
8315 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8316 for (i = 0; i < count; i++)
8317 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8318 updates[i].x - anim->prevFrame.x,
8319 updates[i].y - anim->prevFrame.y,
8320 updates[i].width, updates[i].height,
8321 updates[i].x, updates[i].y);
8323 /* Easy when no overlap */
8324 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8325 0, 0, squareSize, squareSize,
8326 anim->prevFrame.x, anim->prevFrame.y);
8329 /* Save this frame for next time round */
8330 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8331 0, 0, squareSize, squareSize,
8333 anim->prevFrame = *frame;
8335 /* Draw piece over original screen contents, not current,
8336 and copy entire rect. Wipes out overlapping piece images. */
8337 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8338 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8339 0, 0, squareSize, squareSize,
8340 frame->x, frame->y);
8344 EndAnimation (anim, finish)
8348 XRectangle updates[4];
8353 /* The main code will redraw the final square, so we
8354 only need to erase the bits that don't overlap. */
8355 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8356 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8357 for (i = 0; i < count; i++)
8358 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8359 updates[i].x - anim->prevFrame.x,
8360 updates[i].y - anim->prevFrame.y,
8361 updates[i].width, updates[i].height,
8362 updates[i].x, updates[i].y);
8364 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8365 0, 0, squareSize, squareSize,
8366 anim->prevFrame.x, anim->prevFrame.y);
8371 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8373 ChessSquare piece; int startColor;
8374 XPoint * start; XPoint * finish;
8375 XPoint frames[]; int nFrames;
8379 BeginAnimation(anim, piece, startColor, start);
8380 for (n = 0; n < nFrames; n++) {
8381 AnimationFrame(anim, &(frames[n]), piece);
8382 FrameDelay(appData.animSpeed);
8384 EndAnimation(anim, finish);
8388 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8391 ChessSquare piece = board[fromY][toY];
8392 board[fromY][toY] = EmptySquare;
8393 DrawPosition(FALSE, board);
8395 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8396 y = lineGap + toY * (squareSize + lineGap);
8398 x = lineGap + toX * (squareSize + lineGap);
8399 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8401 for(i=1; i<4*kFactor; i++) {
8402 int r = squareSize * 9 * i/(20*kFactor - 5);
8403 XFillArc(xDisplay, xBoardWindow, highlineGC,
8404 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8405 FrameDelay(appData.animSpeed);
8407 board[fromY][toY] = piece;
8410 /* Main control logic for deciding what to animate and how */
8413 AnimateMove(board, fromX, fromY, toX, toY)
8422 XPoint start, finish, mid;
8423 XPoint frames[kFactor * 2 + 1];
8424 int nFrames, startColor, endColor;
8426 /* Are we animating? */
8427 if (!appData.animate || appData.blindfold)
8430 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8431 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8432 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8434 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8435 piece = board[fromY][fromX];
8436 if (piece >= EmptySquare) return;
8441 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8444 if (appData.debugMode) {
8445 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8446 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8447 piece, fromX, fromY, toX, toY); }
8449 ScreenSquare(fromX, fromY, &start, &startColor);
8450 ScreenSquare(toX, toY, &finish, &endColor);
8453 /* Knight: make straight movement then diagonal */
8454 if (abs(toY - fromY) < abs(toX - fromX)) {
8455 mid.x = start.x + (finish.x - start.x) / 2;
8459 mid.y = start.y + (finish.y - start.y) / 2;
8462 mid.x = start.x + (finish.x - start.x) / 2;
8463 mid.y = start.y + (finish.y - start.y) / 2;
8466 /* Don't use as many frames for very short moves */
8467 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8468 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8470 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8471 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8472 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8474 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8475 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8478 /* Be sure end square is redrawn */
8479 damage[0][toY][toX] = True;
8483 DragPieceBegin(x, y)
8486 int boardX, boardY, color;
8489 /* Are we animating? */
8490 if (!appData.animateDragging || appData.blindfold)
8493 /* Figure out which square we start in and the
8494 mouse position relative to top left corner. */
8495 BoardSquare(x, y, &boardX, &boardY);
8496 player.startBoardX = boardX;
8497 player.startBoardY = boardY;
8498 ScreenSquare(boardX, boardY, &corner, &color);
8499 player.startSquare = corner;
8500 player.startColor = color;
8501 /* As soon as we start dragging, the piece will jump slightly to
8502 be centered over the mouse pointer. */
8503 player.mouseDelta.x = squareSize/2;
8504 player.mouseDelta.y = squareSize/2;
8505 /* Initialise animation */
8506 player.dragPiece = PieceForSquare(boardX, boardY);
8508 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8509 player.dragActive = True;
8510 BeginAnimation(&player, player.dragPiece, color, &corner);
8511 /* Mark this square as needing to be redrawn. Note that
8512 we don't remove the piece though, since logically (ie
8513 as seen by opponent) the move hasn't been made yet. */
8514 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8515 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8516 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8517 corner.x, corner.y, squareSize, squareSize,
8518 0, 0); // [HGM] zh: unstack in stead of grab
8519 if(gatingPiece != EmptySquare) {
8520 /* Kludge alert: When gating we want the introduced
8521 piece to appear on the from square. To generate an
8522 image of it, we draw it on the board, copy the image,
8523 and draw the original piece again. */
8524 ChessSquare piece = boards[currentMove][boardY][boardX];
8525 DrawSquare(boardY, boardX, gatingPiece, 0);
8526 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8527 corner.x, corner.y, squareSize, squareSize, 0, 0);
8528 DrawSquare(boardY, boardX, piece, 0);
8530 damage[0][boardY][boardX] = True;
8532 player.dragActive = False;
8542 /* Are we animating? */
8543 if (!appData.animateDragging || appData.blindfold)
8547 if (! player.dragActive)
8549 /* Move piece, maintaining same relative position
8550 of mouse within square */
8551 corner.x = x - player.mouseDelta.x;
8552 corner.y = y - player.mouseDelta.y;
8553 AnimationFrame(&player, &corner, player.dragPiece);
8555 if (appData.highlightDragging) {
8557 BoardSquare(x, y, &boardX, &boardY);
8558 SetHighlights(fromX, fromY, boardX, boardY);
8567 int boardX, boardY, color;
8570 /* Are we animating? */
8571 if (!appData.animateDragging || appData.blindfold)
8575 if (! player.dragActive)
8577 /* Last frame in sequence is square piece is
8578 placed on, which may not match mouse exactly. */
8579 BoardSquare(x, y, &boardX, &boardY);
8580 ScreenSquare(boardX, boardY, &corner, &color);
8581 EndAnimation(&player, &corner);
8583 /* Be sure end square is redrawn */
8584 damage[0][boardY][boardX] = True;
8586 /* This prevents weird things happening with fast successive
8587 clicks which on my Sun at least can cause motion events
8588 without corresponding press/release. */
8589 player.dragActive = False;
8592 /* Handle expose event while piece being dragged */
8597 if (!player.dragActive || appData.blindfold)
8600 /* What we're doing: logically, the move hasn't been made yet,
8601 so the piece is still in it's original square. But visually
8602 it's being dragged around the board. So we erase the square
8603 that the piece is on and draw it at the last known drag point. */
8604 BlankSquare(player.startSquare.x, player.startSquare.y,
8605 player.startColor, EmptySquare, xBoardWindow, 1);
8606 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8607 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8610 #include <sys/ioctl.h>
8611 int get_term_width()
8613 int fd, default_width;
8616 default_width = 79; // this is FICS default anyway...
8618 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8620 if (!ioctl(fd, TIOCGSIZE, &win))
8621 default_width = win.ts_cols;
8622 #elif defined(TIOCGWINSZ)
8624 if (!ioctl(fd, TIOCGWINSZ, &win))
8625 default_width = win.ws_col;
8627 return default_width;
8633 static int old_width = 0;
8634 int new_width = get_term_width();
8636 if (old_width != new_width)
8637 ics_printf("set width %d\n", new_width);
8638 old_width = new_width;
8641 void NotifyFrontendLogin()
8646 /* [AS] Arrow highlighting support */
8648 static double A_WIDTH = 5; /* Width of arrow body */
8650 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8651 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8653 static double Sqr( double x )
8658 static int Round( double x )
8660 return (int) (x + 0.5);
8663 void SquareToPos(int rank, int file, int *x, int *y)
8666 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8667 *y = lineGap + rank * (squareSize + lineGap);
8669 *x = lineGap + file * (squareSize + lineGap);
8670 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8674 /* Draw an arrow between two points using current settings */
8675 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8678 double dx, dy, j, k, x, y;
8681 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8683 arrow[0].x = s_x + A_WIDTH + 0.5;
8686 arrow[1].x = s_x + A_WIDTH + 0.5;
8687 arrow[1].y = d_y - h;
8689 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8690 arrow[2].y = d_y - h;
8695 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8696 arrow[5].y = d_y - h;
8698 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8699 arrow[4].y = d_y - h;
8701 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8704 else if( d_y == s_y ) {
8705 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8708 arrow[0].y = s_y + A_WIDTH + 0.5;
8710 arrow[1].x = d_x - w;
8711 arrow[1].y = s_y + A_WIDTH + 0.5;
8713 arrow[2].x = d_x - w;
8714 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8719 arrow[5].x = d_x - w;
8720 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8722 arrow[4].x = d_x - w;
8723 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8726 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8729 /* [AS] Needed a lot of paper for this! :-) */
8730 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8731 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8733 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8735 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8740 arrow[0].x = Round(x - j);
8741 arrow[0].y = Round(y + j*dx);
8743 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8744 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8747 x = (double) d_x - k;
8748 y = (double) d_y - k*dy;
8751 x = (double) d_x + k;
8752 y = (double) d_y + k*dy;
8755 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8757 arrow[6].x = Round(x - j);
8758 arrow[6].y = Round(y + j*dx);
8760 arrow[2].x = Round(arrow[6].x + 2*j);
8761 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8763 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8764 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8769 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8770 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8773 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8774 // Polygon( hdc, arrow, 7 );
8777 /* [AS] Draw an arrow between two squares */
8778 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
8780 int s_x, s_y, d_x, d_y, hor, vert, i;
8782 if( s_col == d_col && s_row == d_row ) {
8786 /* Get source and destination points */
8787 SquareToPos( s_row, s_col, &s_x, &s_y);
8788 SquareToPos( d_row, d_col, &d_x, &d_y);
8791 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8793 else if( d_y < s_y ) {
8794 d_y += squareSize / 2 + squareSize / 4;
8797 d_y += squareSize / 2;
8801 d_x += squareSize / 2 - squareSize / 4;
8803 else if( d_x < s_x ) {
8804 d_x += squareSize / 2 + squareSize / 4;
8807 d_x += squareSize / 2;
8810 s_x += squareSize / 2;
8811 s_y += squareSize / 2;
8814 A_WIDTH = squareSize / 14.; //[HGM] make float
8816 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8818 hor = 64*s_col + 32; vert = 64*s_row + 32;
8819 for(i=0; i<= 64; i++) {
8820 damage[0][vert+6>>6][hor+6>>6] = True;
8821 damage[0][vert-6>>6][hor+6>>6] = True;
8822 damage[0][vert+6>>6][hor-6>>6] = True;
8823 damage[0][vert-6>>6][hor-6>>6] = True;
8824 hor += d_col - s_col; vert += d_row - s_row;
8828 Boolean IsDrawArrowEnabled()
8830 return appData.highlightMoveWithArrow && squareSize >= 32;
8833 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
8835 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
8836 DrawArrowBetweenSquares(fromX, fromY, toX, toY);