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;
542 Pixmap pieceBitmap[2][(int)BlackPawn];
543 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
544 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
545 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
546 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
547 Pixmap xpmBoardBitmap[2];
548 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
549 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
550 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
551 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
552 XImage *ximLightSquare, *ximDarkSquare;
555 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
556 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
558 #define White(piece) ((int)(piece) < (int)BlackPawn)
560 /* Variables for doing smooth animation. This whole thing
561 would be much easier if the board was double-buffered,
562 but that would require a fairly major rewrite. */
567 GC blitGC, pieceGC, outlineGC;
568 XPoint startSquare, prevFrame, mouseDelta;
572 int startBoardX, startBoardY;
575 /* There can be two pieces being animated at once: a player
576 can begin dragging a piece before the remote opponent has moved. */
578 static AnimState game, player;
580 /* Bitmaps for use as masks when drawing XPM pieces.
581 Need one for each black and white piece. */
582 static Pixmap xpmMask[BlackKing + 1];
584 /* This magic number is the number of intermediate frames used
585 in each half of the animation. For short moves it's reduced
586 by 1. The total number of frames will be factor * 2 + 1. */
589 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
591 MenuItem fileMenu[] = {
592 {N_("New Game Ctrl+N"), "New Game", ResetProc},
593 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
594 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
595 {"----", NULL, NothingProc},
596 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
597 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
598 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
599 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
600 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
601 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
602 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
603 {"----", NULL, NothingProc},
604 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
605 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
606 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
607 {"----", NULL, NothingProc},
608 {N_("Mail Move"), "Mail Move", MailMoveProc},
609 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
610 {"----", NULL, NothingProc},
611 {N_("Quit Ctr+Q"), "Exit", QuitProc},
615 MenuItem editMenu[] = {
616 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
617 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
618 {"----", NULL, NothingProc},
619 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
620 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
621 {"----", NULL, NothingProc},
622 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
623 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
624 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
625 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
626 {"----", NULL, NothingProc},
627 {N_("Revert Home"), "Revert", RevertProc},
628 {N_("Annotate"), "Annotate", AnnotateProc},
629 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
630 {"----", NULL, NothingProc},
631 {N_("Backward Alt+Left"), "Backward", BackwardProc},
632 {N_("Forward Alt+Right"), "Forward", ForwardProc},
633 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
634 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
638 MenuItem viewMenu[] = {
639 {N_("Flip View F2"), "Flip View", FlipViewProc},
640 {"----", NULL, NothingProc},
641 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
642 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
643 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
644 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
645 {N_("ICS text menu"), "ICStex", IcsTextProc},
646 {"----", NULL, NothingProc},
647 {N_("Tags"), "Show Tags", EditTagsProc},
648 {N_("Comments"), "Show Comments", EditCommentProc},
649 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
650 {"----", NULL, NothingProc},
651 {N_("Board..."), "Board Options", BoardOptionsProc},
652 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
656 MenuItem modeMenu[] = {
657 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
658 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
659 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
660 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
661 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
662 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
663 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
664 {N_("Training"), "Training", TrainingProc},
665 {N_("ICS Client"), "ICS Client", IcsClientProc},
666 {"----", NULL, NothingProc},
667 {N_("Machine Match"), "Machine Match", MatchProc},
668 {N_("Pause Pause"), "Pause", PauseProc},
672 MenuItem actionMenu[] = {
673 {N_("Accept F3"), "Accept", AcceptProc},
674 {N_("Decline F4"), "Decline", DeclineProc},
675 {N_("Rematch F12"), "Rematch", RematchProc},
676 {"----", NULL, NothingProc},
677 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
678 {N_("Draw F6"), "Draw", DrawProc},
679 {N_("Adjourn F7"), "Adjourn", AdjournProc},
680 {N_("Abort F8"),"Abort", AbortProc},
681 {N_("Resign F9"), "Resign", ResignProc},
682 {"----", NULL, NothingProc},
683 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
684 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
685 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
686 {"----", NULL, NothingProc},
687 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
688 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
689 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
693 MenuItem engineMenu[] = {
694 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
695 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
696 {"----", NULL, NothingProc},
697 {N_("Hint"), "Hint", HintProc},
698 {N_("Book"), "Book", BookProc},
699 {"----", NULL, NothingProc},
700 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
701 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
705 MenuItem optionsMenu[] = {
706 #define OPTIONSDIALOG
708 {N_("General ..."), "General", OptionsProc},
710 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
711 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
712 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
713 {N_("ICS ..."), "ICS", IcsOptionsProc},
714 {N_("Match ..."), "Match", MatchOptionsProc},
715 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
716 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
717 // {N_(" ..."), "", OptionsProc},
718 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
719 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
720 {"----", NULL, NothingProc},
721 #ifndef OPTIONSDIALOG
722 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
723 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
724 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
725 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
726 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
727 {N_("Blindfold"), "Blindfold", BlindfoldProc},
728 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
730 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
732 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
733 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
734 {N_("Move Sound"), "Move Sound", MoveSoundProc},
735 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
736 {N_("One-Click Moving"), "OneClick", OneClickProc},
737 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
738 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
739 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
740 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
741 // {N_("Premove"), "Premove", PremoveProc},
742 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
743 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
744 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
745 {"----", NULL, NothingProc},
747 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
748 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
752 MenuItem helpMenu[] = {
753 {N_("Info XBoard"), "Info XBoard", InfoProc},
754 {N_("Man XBoard F1"), "Man XBoard", ManProc},
755 {"----", NULL, NothingProc},
756 {N_("About XBoard"), "About XBoard", AboutProc},
761 {N_("File"), "File", fileMenu},
762 {N_("Edit"), "Edit", editMenu},
763 {N_("View"), "View", viewMenu},
764 {N_("Mode"), "Mode", modeMenu},
765 {N_("Action"), "Action", actionMenu},
766 {N_("Engine"), "Engine", engineMenu},
767 {N_("Options"), "Options", optionsMenu},
768 {N_("Help"), "Help", helpMenu},
772 #define PAUSE_BUTTON "P"
773 MenuItem buttonBar[] = {
774 {"<<", "<<", ToStartProc},
775 {"<", "<", BackwardProc},
776 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
777 {">", ">", ForwardProc},
778 {">>", ">>", ToEndProc},
782 #define PIECE_MENU_SIZE 18
783 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
784 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
785 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
786 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
787 N_("Empty square"), N_("Clear board") },
788 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
789 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
790 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
791 N_("Empty square"), N_("Clear board") }
793 /* must be in same order as PieceMenuStrings! */
794 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
795 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
796 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
797 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
798 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
799 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
800 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
801 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
802 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
805 #define DROP_MENU_SIZE 6
806 String dropMenuStrings[DROP_MENU_SIZE] = {
807 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
809 /* must be in same order as PieceMenuStrings! */
810 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
811 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
812 WhiteRook, WhiteQueen
820 DropMenuEnables dmEnables[] = {
838 { XtNborderWidth, 0 },
839 { XtNdefaultDistance, 0 },
843 { XtNborderWidth, 0 },
844 { XtNresizable, (XtArgVal) True },
848 { XtNborderWidth, 0 },
854 { XtNjustify, (XtArgVal) XtJustifyRight },
855 { XtNlabel, (XtArgVal) "..." },
856 { XtNresizable, (XtArgVal) True },
857 { XtNresize, (XtArgVal) False }
860 Arg messageArgs[] = {
861 { XtNjustify, (XtArgVal) XtJustifyLeft },
862 { XtNlabel, (XtArgVal) "..." },
863 { XtNresizable, (XtArgVal) True },
864 { XtNresize, (XtArgVal) False }
868 { XtNborderWidth, 0 },
869 { XtNjustify, (XtArgVal) XtJustifyLeft }
872 XtResource clientResources[] = {
873 { "flashCount", "flashCount", XtRInt, sizeof(int),
874 XtOffset(AppDataPtr, flashCount), XtRImmediate,
875 (XtPointer) FLASH_COUNT },
878 XrmOptionDescRec shellOptions[] = {
879 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
880 { "-flash", "flashCount", XrmoptionNoArg, "3" },
881 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
884 XtActionsRec boardActions[] = {
885 { "DrawPosition", DrawPositionProc },
886 { "HandleUserMove", HandleUserMove },
887 { "AnimateUserMove", AnimateUserMove },
888 { "HandlePV", HandlePV },
889 { "SelectPV", SelectPV },
890 { "StopPV", StopPV },
891 { "FileNameAction", FileNameAction },
892 { "AskQuestionProc", AskQuestionProc },
893 { "AskQuestionReplyAction", AskQuestionReplyAction },
894 { "PieceMenuPopup", PieceMenuPopup },
895 { "WhiteClock", WhiteClock },
896 { "BlackClock", BlackClock },
897 { "Iconify", Iconify },
898 { "ResetProc", ResetProc },
899 { "NewVariantProc", NewVariantProc },
900 { "LoadGameProc", LoadGameProc },
901 { "LoadNextGameProc", LoadNextGameProc },
902 { "LoadPrevGameProc", LoadPrevGameProc },
903 { "LoadSelectedProc", LoadSelectedProc },
904 { "SetFilterProc", SetFilterProc },
905 { "ReloadGameProc", ReloadGameProc },
906 { "LoadPositionProc", LoadPositionProc },
907 { "LoadNextPositionProc", LoadNextPositionProc },
908 { "LoadPrevPositionProc", LoadPrevPositionProc },
909 { "ReloadPositionProc", ReloadPositionProc },
910 { "CopyPositionProc", CopyPositionProc },
911 { "PastePositionProc", PastePositionProc },
912 { "CopyGameProc", CopyGameProc },
913 { "PasteGameProc", PasteGameProc },
914 { "SaveGameProc", SaveGameProc },
915 { "SavePositionProc", SavePositionProc },
916 { "MailMoveProc", MailMoveProc },
917 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
918 { "QuitProc", QuitProc },
919 { "MachineWhiteProc", MachineWhiteProc },
920 { "MachineBlackProc", MachineBlackProc },
921 { "AnalysisModeProc", AnalyzeModeProc },
922 { "AnalyzeFileProc", AnalyzeFileProc },
923 { "TwoMachinesProc", TwoMachinesProc },
924 { "IcsClientProc", IcsClientProc },
925 { "EditGameProc", EditGameProc },
926 { "EditPositionProc", EditPositionProc },
927 { "TrainingProc", EditPositionProc },
928 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
929 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
930 { "ShowGameListProc", ShowGameListProc },
931 { "ShowMoveListProc", HistoryShowProc},
932 { "EditTagsProc", EditCommentProc },
933 { "EditCommentProc", EditCommentProc },
934 { "IcsInputBoxProc", IcsInputBoxProc },
935 { "PauseProc", PauseProc },
936 { "AcceptProc", AcceptProc },
937 { "DeclineProc", DeclineProc },
938 { "RematchProc", RematchProc },
939 { "CallFlagProc", CallFlagProc },
940 { "DrawProc", DrawProc },
941 { "AdjournProc", AdjournProc },
942 { "AbortProc", AbortProc },
943 { "ResignProc", ResignProc },
944 { "AdjuWhiteProc", AdjuWhiteProc },
945 { "AdjuBlackProc", AdjuBlackProc },
946 { "AdjuDrawProc", AdjuDrawProc },
947 { "EnterKeyProc", EnterKeyProc },
948 { "UpKeyProc", UpKeyProc },
949 { "DownKeyProc", DownKeyProc },
950 { "StopObservingProc", StopObservingProc },
951 { "StopExaminingProc", StopExaminingProc },
952 { "UploadProc", UploadProc },
953 { "BackwardProc", BackwardProc },
954 { "ForwardProc", ForwardProc },
955 { "ToStartProc", ToStartProc },
956 { "ToEndProc", ToEndProc },
957 { "RevertProc", RevertProc },
958 { "AnnotateProc", AnnotateProc },
959 { "TruncateGameProc", TruncateGameProc },
960 { "MoveNowProc", MoveNowProc },
961 { "RetractMoveProc", RetractMoveProc },
962 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
963 { "UciMenuProc", (XtActionProc) UciMenuProc },
964 { "TimeControlProc", (XtActionProc) TimeControlProc },
965 { "FlipViewProc", FlipViewProc },
966 { "PonderNextMoveProc", PonderNextMoveProc },
967 #ifndef OPTIONSDIALOG
968 { "AlwaysQueenProc", AlwaysQueenProc },
969 { "AnimateDraggingProc", AnimateDraggingProc },
970 { "AnimateMovingProc", AnimateMovingProc },
971 { "AutoflagProc", AutoflagProc },
972 { "AutoflipProc", AutoflipProc },
973 { "BlindfoldProc", BlindfoldProc },
974 { "FlashMovesProc", FlashMovesProc },
976 { "HighlightDraggingProc", HighlightDraggingProc },
978 { "HighlightLastMoveProc", HighlightLastMoveProc },
979 // { "IcsAlarmProc", IcsAlarmProc },
980 { "MoveSoundProc", MoveSoundProc },
981 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
982 { "PopupExitMessageProc", PopupExitMessageProc },
983 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
984 // { "PremoveProc", PremoveProc },
985 { "ShowCoordsProc", ShowCoordsProc },
986 { "ShowThinkingProc", ShowThinkingProc },
987 { "HideThinkingProc", HideThinkingProc },
988 { "TestLegalityProc", TestLegalityProc },
990 { "SaveSettingsProc", SaveSettingsProc },
991 { "SaveOnExitProc", SaveOnExitProc },
992 { "InfoProc", InfoProc },
993 { "ManProc", ManProc },
994 { "HintProc", HintProc },
995 { "BookProc", BookProc },
996 { "AboutGameProc", AboutGameProc },
997 { "AboutProc", AboutProc },
998 { "DebugProc", DebugProc },
999 { "NothingProc", NothingProc },
1000 { "CommentClick", (XtActionProc) CommentClick },
1001 { "CommentPopDown", (XtActionProc) CommentPopDown },
1002 { "TagsPopDown", (XtActionProc) TagsPopDown },
1003 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1004 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1005 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1006 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1007 { "GameListPopDown", (XtActionProc) GameListPopDown },
1008 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1009 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1010 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1011 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1012 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1013 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1014 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1015 { "GenericPopDown", (XtActionProc) GenericPopDown },
1016 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1019 char globalTranslations[] =
1020 ":<Key>F9: ResignProc() \n \
1021 :Ctrl<Key>n: ResetProc() \n \
1022 :Meta<Key>V: NewVariantProc() \n \
1023 :Ctrl<Key>o: LoadGameProc() \n \
1024 :Meta<Key>Next: LoadNextGameProc() \n \
1025 :Meta<Key>Prior: LoadPrevGameProc() \n \
1026 :Ctrl<Key>s: SaveGameProc() \n \
1027 :Ctrl<Key>c: CopyGameProc() \n \
1028 :Ctrl<Key>v: PasteGameProc() \n \
1029 :Ctrl<Key>O: LoadPositionProc() \n \
1030 :Shift<Key>Next: LoadNextPositionProc() \n \
1031 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1032 :Ctrl<Key>S: SavePositionProc() \n \
1033 :Ctrl<Key>C: CopyPositionProc() \n \
1034 :Ctrl<Key>V: PastePositionProc() \n \
1035 :Ctrl<Key>q: QuitProc() \n \
1036 :Ctrl<Key>w: MachineWhiteProc() \n \
1037 :Ctrl<Key>b: MachineBlackProc() \n \
1038 :Ctrl<Key>t: TwoMachinesProc() \n \
1039 :Ctrl<Key>a: AnalysisModeProc() \n \
1040 :Ctrl<Key>f: AnalyzeFileProc() \n \
1041 :Ctrl<Key>e: EditGameProc() \n \
1042 :Ctrl<Key>E: EditPositionProc() \n \
1043 :Meta<Key>O: EngineOutputProc() \n \
1044 :Meta<Key>E: EvalGraphProc() \n \
1045 :Meta<Key>G: ShowGameListProc() \n \
1046 :Meta<Key>H: ShowMoveListProc() \n \
1047 :<Key>Pause: PauseProc() \n \
1048 :<Key>F3: AcceptProc() \n \
1049 :<Key>F4: DeclineProc() \n \
1050 :<Key>F12: RematchProc() \n \
1051 :<Key>F5: CallFlagProc() \n \
1052 :<Key>F6: DrawProc() \n \
1053 :<Key>F7: AdjournProc() \n \
1054 :<Key>F8: AbortProc() \n \
1055 :<Key>F10: StopObservingProc() \n \
1056 :<Key>F11: StopExaminingProc() \n \
1057 :Meta Ctrl<Key>F12: DebugProc() \n \
1058 :Meta<Key>End: ToEndProc() \n \
1059 :Meta<Key>Right: ForwardProc() \n \
1060 :Meta<Key>Home: ToStartProc() \n \
1061 :Meta<Key>Left: BackwardProc() \n \
1062 :<Key>Home: RevertProc() \n \
1063 :<Key>End: TruncateGameProc() \n \
1064 :Ctrl<Key>m: MoveNowProc() \n \
1065 :Ctrl<Key>x: RetractMoveProc() \n \
1066 :Meta<Key>J: EngineMenuProc() \n \
1067 :Meta<Key>U: UciMenuProc() \n \
1068 :Meta<Key>T: TimeControlProc() \n \
1069 :Ctrl<Key>P: PonderNextMoveProc() \n "
1070 #ifndef OPTIONSDIALOG
1072 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1073 :Ctrl<Key>F: AutoflagProc() \n \
1074 :Ctrl<Key>A: AnimateMovingProc() \n \
1075 :Ctrl<Key>L: TestLegalityProc() \n \
1076 :Ctrl<Key>H: HideThinkingProc() \n "
1079 :<Key>-: Iconify() \n \
1080 :<Key>F1: ManProc() \n \
1081 :<Key>F2: FlipViewProc() \n \
1082 <KeyDown>.: BackwardProc() \n \
1083 <KeyUp>.: ForwardProc() \n \
1084 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1085 \"Send to chess program:\",,1) \n \
1086 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1087 \"Send to second chess program:\",,2) \n";
1089 char boardTranslations[] =
1090 "<Btn1Down>: HandleUserMove(0) \n \
1091 Shift<Btn1Up>: HandleUserMove(1) \n \
1092 <Btn1Up>: HandleUserMove(0) \n \
1093 <Btn1Motion>: AnimateUserMove() \n \
1094 <Btn3Motion>: HandlePV() \n \
1095 <Btn3Up>: PieceMenuPopup(menuB) \n \
1096 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1097 PieceMenuPopup(menuB) \n \
1098 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1099 PieceMenuPopup(menuW) \n \
1100 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1101 PieceMenuPopup(menuW) \n \
1102 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1103 PieceMenuPopup(menuB) \n";
1105 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1106 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1108 char ICSInputTranslations[] =
1109 "<Key>Up: UpKeyProc() \n "
1110 "<Key>Down: DownKeyProc() \n "
1111 "<Key>Return: EnterKeyProc() \n";
1113 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1114 // as the widget is destroyed before the up-click can call extend-end
1115 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1117 String xboardResources[] = {
1118 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1119 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1120 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1125 /* Max possible square size */
1126 #define MAXSQSIZE 256
1128 static int xpm_avail[MAXSQSIZE];
1130 #ifdef HAVE_DIR_STRUCT
1132 /* Extract piece size from filename */
1134 xpm_getsize(name, len, ext)
1145 if ((p=strchr(name, '.')) == NULL ||
1146 StrCaseCmp(p+1, ext) != 0)
1152 while (*p && isdigit(*p))
1159 /* Setup xpm_avail */
1161 xpm_getavail(dirname, ext)
1169 for (i=0; i<MAXSQSIZE; ++i)
1172 if (appData.debugMode)
1173 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1175 dir = opendir(dirname);
1178 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1179 programName, dirname);
1183 while ((ent=readdir(dir)) != NULL) {
1184 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1185 if (i > 0 && i < MAXSQSIZE)
1195 xpm_print_avail(fp, ext)
1201 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1202 for (i=1; i<MAXSQSIZE; ++i) {
1208 /* Return XPM piecesize closest to size */
1210 xpm_closest_to(dirname, size, ext)
1216 int sm_diff = MAXSQSIZE;
1220 xpm_getavail(dirname, ext);
1222 if (appData.debugMode)
1223 xpm_print_avail(stderr, ext);
1225 for (i=1; i<MAXSQSIZE; ++i) {
1228 diff = (diff<0) ? -diff : diff;
1229 if (diff < sm_diff) {
1237 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1243 #else /* !HAVE_DIR_STRUCT */
1244 /* If we are on a system without a DIR struct, we can't
1245 read the directory, so we can't collect a list of
1246 filenames, etc., so we can't do any size-fitting. */
1248 xpm_closest_to(dirname, size, ext)
1253 fprintf(stderr, _("\
1254 Warning: No DIR structure found on this system --\n\
1255 Unable to autosize for XPM/XIM pieces.\n\
1256 Please report this error to frankm@hiwaay.net.\n\
1257 Include system type & operating system in message.\n"));
1260 #endif /* HAVE_DIR_STRUCT */
1262 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1263 "magenta", "cyan", "white" };
1267 TextColors textColors[(int)NColorClasses];
1269 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1271 parse_color(str, which)
1275 char *p, buf[100], *d;
1278 if (strlen(str) > 99) /* watch bounds on buf */
1283 for (i=0; i<which; ++i) {
1290 /* Could be looking at something like:
1292 .. in which case we want to stop on a comma also */
1293 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1297 return -1; /* Use default for empty field */
1300 if (which == 2 || isdigit(*p))
1303 while (*p && isalpha(*p))
1308 for (i=0; i<8; ++i) {
1309 if (!StrCaseCmp(buf, cnames[i]))
1310 return which? (i+40) : (i+30);
1312 if (!StrCaseCmp(buf, "default")) return -1;
1314 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1319 parse_cpair(cc, str)
1323 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1324 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1329 /* bg and attr are optional */
1330 textColors[(int)cc].bg = parse_color(str, 1);
1331 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1332 textColors[(int)cc].attr = 0;
1338 /* Arrange to catch delete-window events */
1339 Atom wm_delete_window;
1341 CatchDeleteWindow(Widget w, String procname)
1344 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1345 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1346 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1353 XtSetArg(args[0], XtNiconic, False);
1354 XtSetValues(shellWidget, args, 1);
1356 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1359 //---------------------------------------------------------------------------------------------------------
1360 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1363 #define CW_USEDEFAULT (1<<31)
1364 #define ICS_TEXT_MENU_SIZE 90
1365 #define DEBUG_FILE "xboard.debug"
1366 #define SetCurrentDirectory chdir
1367 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1371 // these two must some day move to frontend.h, when they are implemented
1372 Boolean GameListIsUp();
1374 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1377 // front-end part of option handling
1379 // [HGM] This platform-dependent table provides the location for storing the color info
1380 extern char *crWhite, * crBlack;
1384 &appData.whitePieceColor,
1385 &appData.blackPieceColor,
1386 &appData.lightSquareColor,
1387 &appData.darkSquareColor,
1388 &appData.highlightSquareColor,
1389 &appData.premoveHighlightColor,
1390 &appData.lowTimeWarningColor,
1401 // [HGM] font: keep a font for each square size, even non-stndard ones
1402 #define NUM_SIZES 18
1403 #define MAX_SIZE 130
1404 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1405 char *fontTable[NUM_FONTS][MAX_SIZE];
1408 ParseFont(char *name, int number)
1409 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1411 if(sscanf(name, "size%d:", &size)) {
1412 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1413 // defer processing it until we know if it matches our board size
1414 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1415 fontTable[number][size] = strdup(strchr(name, ':')+1);
1416 fontValid[number][size] = True;
1421 case 0: // CLOCK_FONT
1422 appData.clockFont = strdup(name);
1424 case 1: // MESSAGE_FONT
1425 appData.font = strdup(name);
1427 case 2: // COORD_FONT
1428 appData.coordFont = strdup(name);
1433 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1438 { // only 2 fonts currently
1439 appData.clockFont = CLOCK_FONT_NAME;
1440 appData.coordFont = COORD_FONT_NAME;
1441 appData.font = DEFAULT_FONT_NAME;
1446 { // no-op, until we identify the code for this already in XBoard and move it here
1450 ParseColor(int n, char *name)
1451 { // in XBoard, just copy the color-name string
1452 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1456 ParseTextAttribs(ColorClass cc, char *s)
1458 (&appData.colorShout)[cc] = strdup(s);
1462 ParseBoardSize(void *addr, char *name)
1464 appData.boardSize = strdup(name);
1469 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1473 SetCommPortDefaults()
1474 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1477 // [HGM] args: these three cases taken out to stay in front-end
1479 SaveFontArg(FILE *f, ArgDescriptor *ad)
1482 int i, n = (int)(intptr_t)ad->argLoc;
1484 case 0: // CLOCK_FONT
1485 name = appData.clockFont;
1487 case 1: // MESSAGE_FONT
1488 name = appData.font;
1490 case 2: // COORD_FONT
1491 name = appData.coordFont;
1496 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1497 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1498 fontTable[n][squareSize] = strdup(name);
1499 fontValid[n][squareSize] = True;
1502 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1503 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1508 { // nothing to do, as the sounds are at all times represented by their text-string names already
1512 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1513 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1514 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1518 SaveColor(FILE *f, ArgDescriptor *ad)
1519 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1520 if(colorVariable[(int)(intptr_t)ad->argLoc])
1521 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1525 SaveBoardSize(FILE *f, char *name, void *addr)
1526 { // wrapper to shield back-end from BoardSize & sizeInfo
1527 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1531 ParseCommPortSettings(char *s)
1532 { // no such option in XBoard (yet)
1535 extern Widget engineOutputShell;
1536 extern Widget tagsShell, editTagsShell;
1538 GetActualPlacement(Widget wg, WindowPlacement *wp)
1548 XtSetArg(args[i], XtNx, &x); i++;
1549 XtSetArg(args[i], XtNy, &y); i++;
1550 XtSetArg(args[i], XtNwidth, &w); i++;
1551 XtSetArg(args[i], XtNheight, &h); i++;
1552 XtGetValues(wg, args, i);
1561 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1562 // In XBoard this will have to wait until awareness of window parameters is implemented
1563 GetActualPlacement(shellWidget, &wpMain);
1564 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1565 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1566 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1567 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1568 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1569 else GetActualPlacement(editShell, &wpComment);
1570 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1571 else GetActualPlacement(editTagsShell, &wpTags);
1575 PrintCommPortSettings(FILE *f, char *name)
1576 { // This option does not exist in XBoard
1580 MySearchPath(char *installDir, char *name, char *fullname)
1581 { // just append installDir and name. Perhaps ExpandPath should be used here?
1582 name = ExpandPathName(name);
1583 if(name && name[0] == '/')
1584 safeStrCpy(fullname, name, MSG_SIZ );
1586 sprintf(fullname, "%s%c%s", installDir, '/', name);
1592 MyGetFullPathName(char *name, char *fullname)
1593 { // should use ExpandPath?
1594 name = ExpandPathName(name);
1595 safeStrCpy(fullname, name, MSG_SIZ );
1600 EnsureOnScreen(int *x, int *y, int minX, int minY)
1607 { // [HGM] args: allows testing if main window is realized from back-end
1608 return xBoardWindow != 0;
1612 PopUpStartupDialog()
1613 { // start menu not implemented in XBoard
1617 ConvertToLine(int argc, char **argv)
1619 static char line[128*1024], buf[1024];
1623 for(i=1; i<argc; i++)
1625 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1626 && argv[i][0] != '{' )
1627 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1629 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1630 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1633 line[strlen(line)-1] = NULLCHAR;
1637 //--------------------------------------------------------------------------------------------
1639 extern Boolean twoBoards, partnerUp;
1642 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1644 #define BoardSize int
1645 void InitDrawingSizes(BoardSize boardSize, int flags)
1646 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1647 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1649 XtGeometryResult gres;
1652 if(!formWidget) return;
1655 * Enable shell resizing.
1657 shellArgs[0].value = (XtArgVal) &w;
1658 shellArgs[1].value = (XtArgVal) &h;
1659 XtGetValues(shellWidget, shellArgs, 2);
1661 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1662 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1663 XtSetValues(shellWidget, &shellArgs[2], 4);
1665 XtSetArg(args[0], XtNdefaultDistance, &sep);
1666 XtGetValues(formWidget, args, 1);
1668 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1669 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1670 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1672 hOffset = boardWidth + 10;
1673 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1674 secondSegments[i] = gridSegments[i];
1675 secondSegments[i].x1 += hOffset;
1676 secondSegments[i].x2 += hOffset;
1679 XtSetArg(args[0], XtNwidth, boardWidth);
1680 XtSetArg(args[1], XtNheight, boardHeight);
1681 XtSetValues(boardWidget, args, 2);
1683 timerWidth = (boardWidth - sep) / 2;
1684 XtSetArg(args[0], XtNwidth, timerWidth);
1685 XtSetValues(whiteTimerWidget, args, 1);
1686 XtSetValues(blackTimerWidget, args, 1);
1688 XawFormDoLayout(formWidget, False);
1690 if (appData.titleInWindow) {
1692 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1693 XtSetArg(args[i], XtNheight, &h); i++;
1694 XtGetValues(titleWidget, args, i);
1696 w = boardWidth - 2*bor;
1698 XtSetArg(args[0], XtNwidth, &w);
1699 XtGetValues(menuBarWidget, args, 1);
1700 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1703 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1704 if (gres != XtGeometryYes && appData.debugMode) {
1706 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1707 programName, gres, w, h, wr, hr);
1711 XawFormDoLayout(formWidget, True);
1714 * Inhibit shell resizing.
1716 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1717 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1718 shellArgs[4].value = shellArgs[2].value = w;
1719 shellArgs[5].value = shellArgs[3].value = h;
1720 XtSetValues(shellWidget, &shellArgs[0], 6);
1722 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1725 for(i=0; i<4; i++) {
1727 for(p=0; p<=(int)WhiteKing; p++)
1728 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1729 if(gameInfo.variant == VariantShogi) {
1730 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1731 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1732 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1733 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1734 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1737 if(gameInfo.variant == VariantGothic) {
1738 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1741 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1742 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1743 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1746 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1747 for(p=0; p<=(int)WhiteKing; p++)
1748 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1749 if(gameInfo.variant == VariantShogi) {
1750 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1751 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1752 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1753 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1754 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1757 if(gameInfo.variant == VariantGothic) {
1758 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1761 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1762 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1763 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1768 for(i=0; i<2; i++) {
1770 for(p=0; p<=(int)WhiteKing; p++)
1771 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1772 if(gameInfo.variant == VariantShogi) {
1773 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1774 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1775 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1776 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1777 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1780 if(gameInfo.variant == VariantGothic) {
1781 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1784 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1785 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1786 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1796 void ParseIcsTextColors()
1797 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1798 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1799 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1800 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1801 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1802 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1803 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1804 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1805 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1806 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1807 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1809 if (appData.colorize) {
1811 _("%s: can't parse color names; disabling colorization\n"),
1814 appData.colorize = FALSE;
1819 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1820 XrmValue vFrom, vTo;
1821 int forceMono = False;
1823 if (!appData.monoMode) {
1824 vFrom.addr = (caddr_t) appData.lightSquareColor;
1825 vFrom.size = strlen(appData.lightSquareColor);
1826 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1827 if (vTo.addr == NULL) {
1828 appData.monoMode = True;
1831 lightSquareColor = *(Pixel *) vTo.addr;
1834 if (!appData.monoMode) {
1835 vFrom.addr = (caddr_t) appData.darkSquareColor;
1836 vFrom.size = strlen(appData.darkSquareColor);
1837 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1838 if (vTo.addr == NULL) {
1839 appData.monoMode = True;
1842 darkSquareColor = *(Pixel *) vTo.addr;
1845 if (!appData.monoMode) {
1846 vFrom.addr = (caddr_t) appData.whitePieceColor;
1847 vFrom.size = strlen(appData.whitePieceColor);
1848 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1849 if (vTo.addr == NULL) {
1850 appData.monoMode = True;
1853 whitePieceColor = *(Pixel *) vTo.addr;
1856 if (!appData.monoMode) {
1857 vFrom.addr = (caddr_t) appData.blackPieceColor;
1858 vFrom.size = strlen(appData.blackPieceColor);
1859 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1860 if (vTo.addr == NULL) {
1861 appData.monoMode = True;
1864 blackPieceColor = *(Pixel *) vTo.addr;
1868 if (!appData.monoMode) {
1869 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1870 vFrom.size = strlen(appData.highlightSquareColor);
1871 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1872 if (vTo.addr == NULL) {
1873 appData.monoMode = True;
1876 highlightSquareColor = *(Pixel *) vTo.addr;
1880 if (!appData.monoMode) {
1881 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1882 vFrom.size = strlen(appData.premoveHighlightColor);
1883 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1884 if (vTo.addr == NULL) {
1885 appData.monoMode = True;
1888 premoveHighlightColor = *(Pixel *) vTo.addr;
1899 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1900 XSetWindowAttributes window_attributes;
1902 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1903 XrmValue vFrom, vTo;
1904 XtGeometryResult gres;
1907 int forceMono = False;
1909 srandom(time(0)); // [HGM] book: make random truly random
1911 setbuf(stdout, NULL);
1912 setbuf(stderr, NULL);
1915 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1916 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1920 programName = strrchr(argv[0], '/');
1921 if (programName == NULL)
1922 programName = argv[0];
1927 XtSetLanguageProc(NULL, NULL, NULL);
1928 bindtextdomain(PACKAGE, LOCALEDIR);
1929 textdomain(PACKAGE);
1933 XtAppInitialize(&appContext, "XBoard", shellOptions,
1934 XtNumber(shellOptions),
1935 &argc, argv, xboardResources, NULL, 0);
1936 appData.boardSize = "";
1937 InitAppData(ConvertToLine(argc, argv));
1939 if (p == NULL) p = "/tmp";
1940 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1941 gameCopyFilename = (char*) malloc(i);
1942 gamePasteFilename = (char*) malloc(i);
1943 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1944 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1946 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1947 clientResources, XtNumber(clientResources),
1950 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1951 static char buf[MSG_SIZ];
1952 EscapeExpand(buf, appData.initString);
1953 appData.initString = strdup(buf);
1954 EscapeExpand(buf, appData.secondInitString);
1955 appData.secondInitString = strdup(buf);
1956 EscapeExpand(buf, appData.firstComputerString);
1957 appData.firstComputerString = strdup(buf);
1958 EscapeExpand(buf, appData.secondComputerString);
1959 appData.secondComputerString = strdup(buf);
1962 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1965 if (chdir(chessDir) != 0) {
1966 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1972 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1973 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1974 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1975 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1978 setbuf(debugFP, NULL);
1981 /* [HGM,HR] make sure board size is acceptable */
1982 if(appData.NrFiles > BOARD_FILES ||
1983 appData.NrRanks > BOARD_RANKS )
1984 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1987 /* This feature does not work; animation needs a rewrite */
1988 appData.highlightDragging = FALSE;
1992 xDisplay = XtDisplay(shellWidget);
1993 xScreen = DefaultScreen(xDisplay);
1994 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1996 gameInfo.variant = StringToVariant(appData.variant);
1997 InitPosition(FALSE);
2000 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2002 if (isdigit(appData.boardSize[0])) {
2003 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2004 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2005 &fontPxlSize, &smallLayout, &tinyLayout);
2007 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2008 programName, appData.boardSize);
2012 /* Find some defaults; use the nearest known size */
2013 SizeDefaults *szd, *nearest;
2014 int distance = 99999;
2015 nearest = szd = sizeDefaults;
2016 while (szd->name != NULL) {
2017 if (abs(szd->squareSize - squareSize) < distance) {
2019 distance = abs(szd->squareSize - squareSize);
2020 if (distance == 0) break;
2024 if (i < 2) lineGap = nearest->lineGap;
2025 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2026 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2027 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2028 if (i < 6) smallLayout = nearest->smallLayout;
2029 if (i < 7) tinyLayout = nearest->tinyLayout;
2032 SizeDefaults *szd = sizeDefaults;
2033 if (*appData.boardSize == NULLCHAR) {
2034 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2035 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2038 if (szd->name == NULL) szd--;
2039 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2041 while (szd->name != NULL &&
2042 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2043 if (szd->name == NULL) {
2044 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2045 programName, appData.boardSize);
2049 squareSize = szd->squareSize;
2050 lineGap = szd->lineGap;
2051 clockFontPxlSize = szd->clockFontPxlSize;
2052 coordFontPxlSize = szd->coordFontPxlSize;
2053 fontPxlSize = szd->fontPxlSize;
2054 smallLayout = szd->smallLayout;
2055 tinyLayout = szd->tinyLayout;
2056 // [HGM] font: use defaults from settings file if available and not overruled
2058 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2059 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2060 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2061 appData.font = fontTable[MESSAGE_FONT][squareSize];
2062 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2063 appData.coordFont = fontTable[COORD_FONT][squareSize];
2065 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2066 if (strlen(appData.pixmapDirectory) > 0) {
2067 p = ExpandPathName(appData.pixmapDirectory);
2069 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2070 appData.pixmapDirectory);
2073 if (appData.debugMode) {
2074 fprintf(stderr, _("\
2075 XBoard square size (hint): %d\n\
2076 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2078 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2079 if (appData.debugMode) {
2080 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2083 defaultLineGap = lineGap;
2084 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2086 /* [HR] height treated separately (hacked) */
2087 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2088 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2089 if (appData.showJail == 1) {
2090 /* Jail on top and bottom */
2091 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2092 XtSetArg(boardArgs[2], XtNheight,
2093 boardHeight + 2*(lineGap + squareSize));
2094 } else if (appData.showJail == 2) {
2096 XtSetArg(boardArgs[1], XtNwidth,
2097 boardWidth + 2*(lineGap + squareSize));
2098 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2101 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2102 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2106 * Determine what fonts to use.
2108 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2109 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2110 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2111 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2112 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2113 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2114 appData.font = FindFont(appData.font, fontPxlSize);
2115 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2116 countFontStruct = XQueryFont(xDisplay, countFontID);
2117 // appData.font = FindFont(appData.font, fontPxlSize);
2119 xdb = XtDatabase(xDisplay);
2120 XrmPutStringResource(&xdb, "*font", appData.font);
2123 * Detect if there are not enough colors available and adapt.
2125 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2126 appData.monoMode = True;
2129 forceMono = MakeColors();
2132 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2135 if (appData.bitmapDirectory == NULL ||
2136 appData.bitmapDirectory[0] == NULLCHAR)
2137 appData.bitmapDirectory = DEF_BITMAP_DIR;
2140 if (appData.lowTimeWarning && !appData.monoMode) {
2141 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2142 vFrom.size = strlen(appData.lowTimeWarningColor);
2143 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2144 if (vTo.addr == NULL)
2145 appData.monoMode = True;
2147 lowTimeWarningColor = *(Pixel *) vTo.addr;
2150 if (appData.monoMode && appData.debugMode) {
2151 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2152 (unsigned long) XWhitePixel(xDisplay, xScreen),
2153 (unsigned long) XBlackPixel(xDisplay, xScreen));
2156 ParseIcsTextColors();
2157 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2158 textColors[ColorNone].attr = 0;
2160 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2166 layoutName = "tinyLayout";
2167 } else if (smallLayout) {
2168 layoutName = "smallLayout";
2170 layoutName = "normalLayout";
2172 /* Outer layoutWidget is there only to provide a name for use in
2173 resources that depend on the layout style */
2175 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2176 layoutArgs, XtNumber(layoutArgs));
2178 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2179 formArgs, XtNumber(formArgs));
2180 XtSetArg(args[0], XtNdefaultDistance, &sep);
2181 XtGetValues(formWidget, args, 1);
2184 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2185 XtSetArg(args[0], XtNtop, XtChainTop);
2186 XtSetArg(args[1], XtNbottom, XtChainTop);
2187 XtSetArg(args[2], XtNright, XtChainLeft);
2188 XtSetValues(menuBarWidget, args, 3);
2190 widgetList[j++] = whiteTimerWidget =
2191 XtCreateWidget("whiteTime", labelWidgetClass,
2192 formWidget, timerArgs, XtNumber(timerArgs));
2193 XtSetArg(args[0], XtNfont, clockFontStruct);
2194 XtSetArg(args[1], XtNtop, XtChainTop);
2195 XtSetArg(args[2], XtNbottom, XtChainTop);
2196 XtSetValues(whiteTimerWidget, args, 3);
2198 widgetList[j++] = blackTimerWidget =
2199 XtCreateWidget("blackTime", labelWidgetClass,
2200 formWidget, timerArgs, XtNumber(timerArgs));
2201 XtSetArg(args[0], XtNfont, clockFontStruct);
2202 XtSetArg(args[1], XtNtop, XtChainTop);
2203 XtSetArg(args[2], XtNbottom, XtChainTop);
2204 XtSetValues(blackTimerWidget, args, 3);
2206 if (appData.titleInWindow) {
2207 widgetList[j++] = titleWidget =
2208 XtCreateWidget("title", labelWidgetClass, formWidget,
2209 titleArgs, XtNumber(titleArgs));
2210 XtSetArg(args[0], XtNtop, XtChainTop);
2211 XtSetArg(args[1], XtNbottom, XtChainTop);
2212 XtSetValues(titleWidget, args, 2);
2215 if (appData.showButtonBar) {
2216 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2217 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2218 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2219 XtSetArg(args[2], XtNtop, XtChainTop);
2220 XtSetArg(args[3], XtNbottom, XtChainTop);
2221 XtSetValues(buttonBarWidget, args, 4);
2224 widgetList[j++] = messageWidget =
2225 XtCreateWidget("message", labelWidgetClass, formWidget,
2226 messageArgs, XtNumber(messageArgs));
2227 XtSetArg(args[0], XtNtop, XtChainTop);
2228 XtSetArg(args[1], XtNbottom, XtChainTop);
2229 XtSetValues(messageWidget, args, 2);
2231 widgetList[j++] = boardWidget =
2232 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2233 XtNumber(boardArgs));
2235 XtManageChildren(widgetList, j);
2237 timerWidth = (boardWidth - sep) / 2;
2238 XtSetArg(args[0], XtNwidth, timerWidth);
2239 XtSetValues(whiteTimerWidget, args, 1);
2240 XtSetValues(blackTimerWidget, args, 1);
2242 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2243 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2244 XtGetValues(whiteTimerWidget, args, 2);
2246 if (appData.showButtonBar) {
2247 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2248 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2249 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2253 * formWidget uses these constraints but they are stored
2257 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2258 XtSetValues(menuBarWidget, args, i);
2259 if (appData.titleInWindow) {
2262 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2263 XtSetValues(whiteTimerWidget, args, i);
2265 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2266 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2267 XtSetValues(blackTimerWidget, args, i);
2269 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2270 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2271 XtSetValues(titleWidget, args, i);
2273 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2274 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2275 XtSetValues(messageWidget, args, i);
2276 if (appData.showButtonBar) {
2278 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2279 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2280 XtSetValues(buttonBarWidget, args, i);
2284 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2285 XtSetValues(whiteTimerWidget, args, i);
2287 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2288 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2289 XtSetValues(blackTimerWidget, args, i);
2291 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2292 XtSetValues(titleWidget, args, i);
2294 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2295 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2296 XtSetValues(messageWidget, args, i);
2297 if (appData.showButtonBar) {
2299 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2300 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2301 XtSetValues(buttonBarWidget, args, i);
2306 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2307 XtSetValues(whiteTimerWidget, args, i);
2309 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2310 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2311 XtSetValues(blackTimerWidget, args, i);
2313 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2314 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2315 XtSetValues(messageWidget, args, i);
2316 if (appData.showButtonBar) {
2318 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2319 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2320 XtSetValues(buttonBarWidget, args, i);
2324 XtSetArg(args[0], XtNfromVert, messageWidget);
2325 XtSetArg(args[1], XtNtop, XtChainTop);
2326 XtSetArg(args[2], XtNbottom, XtChainBottom);
2327 XtSetArg(args[3], XtNleft, XtChainLeft);
2328 XtSetArg(args[4], XtNright, XtChainRight);
2329 XtSetValues(boardWidget, args, 5);
2331 XtRealizeWidget(shellWidget);
2334 XtSetArg(args[0], XtNx, wpMain.x);
2335 XtSetArg(args[1], XtNy, wpMain.y);
2336 XtSetValues(shellWidget, args, 2);
2340 * Correct the width of the message and title widgets.
2341 * It is not known why some systems need the extra fudge term.
2342 * The value "2" is probably larger than needed.
2344 XawFormDoLayout(formWidget, False);
2346 #define WIDTH_FUDGE 2
2348 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2349 XtSetArg(args[i], XtNheight, &h); i++;
2350 XtGetValues(messageWidget, args, i);
2351 if (appData.showButtonBar) {
2353 XtSetArg(args[i], XtNwidth, &w); i++;
2354 XtGetValues(buttonBarWidget, args, i);
2355 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2357 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2360 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2361 if (gres != XtGeometryYes && appData.debugMode) {
2362 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2363 programName, gres, w, h, wr, hr);
2366 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2367 /* The size used for the child widget in layout lags one resize behind
2368 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2370 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2371 if (gres != XtGeometryYes && appData.debugMode) {
2372 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2373 programName, gres, w, h, wr, hr);
2376 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2377 XtSetArg(args[1], XtNright, XtChainRight);
2378 XtSetValues(messageWidget, args, 2);
2380 if (appData.titleInWindow) {
2382 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2383 XtSetArg(args[i], XtNheight, &h); i++;
2384 XtGetValues(titleWidget, args, i);
2386 w = boardWidth - 2*bor;
2388 XtSetArg(args[0], XtNwidth, &w);
2389 XtGetValues(menuBarWidget, args, 1);
2390 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2393 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2394 if (gres != XtGeometryYes && appData.debugMode) {
2396 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2397 programName, gres, w, h, wr, hr);
2400 XawFormDoLayout(formWidget, True);
2402 xBoardWindow = XtWindow(boardWidget);
2404 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2405 // not need to go into InitDrawingSizes().
2409 * Create X checkmark bitmap and initialize option menu checks.
2411 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2412 checkmark_bits, checkmark_width, checkmark_height);
2413 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2414 #ifndef OPTIONSDIALOG
2415 if (appData.alwaysPromoteToQueen) {
2416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2419 if (appData.animateDragging) {
2420 XtSetValues(XtNameToWidget(menuBarWidget,
2421 "menuOptions.Animate Dragging"),
2424 if (appData.animate) {
2425 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2428 if (appData.autoCallFlag) {
2429 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2432 if (appData.autoFlipView) {
2433 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2436 if (appData.blindfold) {
2437 XtSetValues(XtNameToWidget(menuBarWidget,
2438 "menuOptions.Blindfold"), args, 1);
2440 if (appData.flashCount > 0) {
2441 XtSetValues(XtNameToWidget(menuBarWidget,
2442 "menuOptions.Flash Moves"),
2446 if (appData.highlightDragging) {
2447 XtSetValues(XtNameToWidget(menuBarWidget,
2448 "menuOptions.Highlight Dragging"),
2452 if (appData.highlightLastMove) {
2453 XtSetValues(XtNameToWidget(menuBarWidget,
2454 "menuOptions.Highlight Last Move"),
2457 if (appData.highlightMoveWithArrow) {
2458 XtSetValues(XtNameToWidget(menuBarWidget,
2459 "menuOptions.Arrow"),
2462 // if (appData.icsAlarm) {
2463 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2466 if (appData.ringBellAfterMoves) {
2467 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2470 if (appData.oneClick) {
2471 XtSetValues(XtNameToWidget(menuBarWidget,
2472 "menuOptions.OneClick"), args, 1);
2474 if (appData.periodicUpdates) {
2475 XtSetValues(XtNameToWidget(menuBarWidget,
2476 "menuOptions.Periodic Updates"), args, 1);
2478 if (appData.ponderNextMove) {
2479 XtSetValues(XtNameToWidget(menuBarWidget,
2480 "menuOptions.Ponder Next Move"), args, 1);
2482 if (appData.popupExitMessage) {
2483 XtSetValues(XtNameToWidget(menuBarWidget,
2484 "menuOptions.Popup Exit Message"), args, 1);
2486 if (appData.popupMoveErrors) {
2487 XtSetValues(XtNameToWidget(menuBarWidget,
2488 "menuOptions.Popup Move Errors"), args, 1);
2490 // if (appData.premove) {
2491 // XtSetValues(XtNameToWidget(menuBarWidget,
2492 // "menuOptions.Premove"), args, 1);
2494 if (appData.showCoords) {
2495 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2498 if (appData.hideThinkingFromHuman) {
2499 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2502 if (appData.testLegality) {
2503 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2507 if (saveSettingsOnExit) {
2508 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2515 ReadBitmap(&wIconPixmap, "icon_white.bm",
2516 icon_white_bits, icon_white_width, icon_white_height);
2517 ReadBitmap(&bIconPixmap, "icon_black.bm",
2518 icon_black_bits, icon_black_width, icon_black_height);
2519 iconPixmap = wIconPixmap;
2521 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2522 XtSetValues(shellWidget, args, i);
2525 * Create a cursor for the board widget.
2527 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2528 XChangeWindowAttributes(xDisplay, xBoardWindow,
2529 CWCursor, &window_attributes);
2532 * Inhibit shell resizing.
2534 shellArgs[0].value = (XtArgVal) &w;
2535 shellArgs[1].value = (XtArgVal) &h;
2536 XtGetValues(shellWidget, shellArgs, 2);
2537 shellArgs[4].value = shellArgs[2].value = w;
2538 shellArgs[5].value = shellArgs[3].value = h;
2539 XtSetValues(shellWidget, &shellArgs[2], 4);
2540 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2541 marginH = h - boardHeight;
2543 CatchDeleteWindow(shellWidget, "QuitProc");
2548 if (appData.bitmapDirectory[0] != NULLCHAR) {
2552 CreateXPMBoard(appData.liteBackTextureFile, 1);
2553 CreateXPMBoard(appData.darkBackTextureFile, 0);
2557 /* Create regular pieces */
2558 if (!useImages) CreatePieces();
2563 if (appData.animate || appData.animateDragging)
2566 XtAugmentTranslations(formWidget,
2567 XtParseTranslationTable(globalTranslations));
2568 XtAugmentTranslations(boardWidget,
2569 XtParseTranslationTable(boardTranslations));
2570 XtAugmentTranslations(whiteTimerWidget,
2571 XtParseTranslationTable(whiteTranslations));
2572 XtAugmentTranslations(blackTimerWidget,
2573 XtParseTranslationTable(blackTranslations));
2575 /* Why is the following needed on some versions of X instead
2576 * of a translation? */
2577 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2578 (XtEventHandler) EventProc, NULL);
2581 /* [AS] Restore layout */
2582 if( wpMoveHistory.visible ) {
2586 if( wpEvalGraph.visible )
2591 if( wpEngineOutput.visible ) {
2592 EngineOutputPopUp();
2597 if (errorExitStatus == -1) {
2598 if (appData.icsActive) {
2599 /* We now wait until we see "login:" from the ICS before
2600 sending the logon script (problems with timestamp otherwise) */
2601 /*ICSInitScript();*/
2602 if (appData.icsInputBox) ICSInputBoxPopUp();
2606 signal(SIGWINCH, TermSizeSigHandler);
2608 signal(SIGINT, IntSigHandler);
2609 signal(SIGTERM, IntSigHandler);
2610 if (*appData.cmailGameName != NULLCHAR) {
2611 signal(SIGUSR1, CmailSigHandler);
2614 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2616 XtSetKeyboardFocus(shellWidget, formWidget);
2618 XtAppMainLoop(appContext);
2619 if (appData.debugMode) fclose(debugFP); // [DM] debug
2626 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2627 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2629 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2630 unlink(gameCopyFilename);
2631 unlink(gamePasteFilename);
2634 RETSIGTYPE TermSizeSigHandler(int sig)
2647 CmailSigHandler(sig)
2653 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2655 /* Activate call-back function CmailSigHandlerCallBack() */
2656 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2658 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2662 CmailSigHandlerCallBack(isr, closure, message, count, error)
2670 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2672 /**** end signal code ****/
2678 /* try to open the icsLogon script, either in the location given
2679 * or in the users HOME directory
2686 f = fopen(appData.icsLogon, "r");
2689 homedir = getenv("HOME");
2690 if (homedir != NULL)
2692 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2693 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2694 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2695 f = fopen(buf, "r");
2700 ProcessICSInitScript(f);
2702 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2725 if (!menuBarWidget) return;
2726 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2728 DisplayError("menuEdit.Revert", 0);
2730 XtSetSensitive(w, !grey);
2732 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2734 DisplayError("menuEdit.Annotate", 0);
2736 XtSetSensitive(w, !grey);
2741 SetMenuEnables(enab)
2745 if (!menuBarWidget) return;
2746 while (enab->name != NULL) {
2747 w = XtNameToWidget(menuBarWidget, enab->name);
2749 DisplayError(enab->name, 0);
2751 XtSetSensitive(w, enab->value);
2757 Enables icsEnables[] = {
2758 { "menuFile.Mail Move", False },
2759 { "menuFile.Reload CMail Message", False },
2760 { "menuMode.Machine Black", False },
2761 { "menuMode.Machine White", False },
2762 { "menuMode.Analysis Mode", False },
2763 { "menuMode.Analyze File", False },
2764 { "menuMode.Two Machines", False },
2765 { "menuMode.Machine Match", False },
2767 { "menuEngine.Hint", False },
2768 { "menuEngine.Book", False },
2769 { "menuEngine.Move Now", False },
2770 #ifndef OPTIONSDIALOG
2771 { "menuOptions.Periodic Updates", False },
2772 { "menuOptions.Hide Thinking", False },
2773 { "menuOptions.Ponder Next Move", False },
2775 { "menuEngine.Engine #1 Settings", False },
2777 { "menuEngine.Engine #2 Settings", False },
2778 { "menuEdit.Annotate", False },
2782 Enables ncpEnables[] = {
2783 { "menuFile.Mail Move", False },
2784 { "menuFile.Reload CMail Message", False },
2785 { "menuMode.Machine White", False },
2786 { "menuMode.Machine Black", False },
2787 { "menuMode.Analysis Mode", False },
2788 { "menuMode.Analyze File", False },
2789 { "menuMode.Two Machines", False },
2790 { "menuMode.Machine Match", False },
2791 { "menuMode.ICS Client", False },
2792 { "menuView.ICStex", False },
2793 { "menuView.ICS Input Box", False },
2794 { "Action", False },
2795 { "menuEdit.Revert", False },
2796 { "menuEdit.Annotate", False },
2797 { "menuEngine.Engine #1 Settings", False },
2798 { "menuEngine.Engine #2 Settings", False },
2799 { "menuEngine.Move Now", False },
2800 { "menuEngine.Retract Move", False },
2801 { "menuOptions.ICS", False },
2802 #ifndef OPTIONSDIALOG
2803 { "menuOptions.Auto Flag", False },
2804 { "menuOptions.Auto Flip View", False },
2805 // { "menuOptions.ICS Alarm", False },
2806 { "menuOptions.Move Sound", False },
2807 { "menuOptions.Hide Thinking", False },
2808 { "menuOptions.Periodic Updates", False },
2809 { "menuOptions.Ponder Next Move", False },
2811 { "menuEngine.Hint", False },
2812 { "menuEngine.Book", False },
2816 Enables gnuEnables[] = {
2817 { "menuMode.ICS Client", False },
2818 { "menuView.ICStex", False },
2819 { "menuView.ICS Input Box", False },
2820 { "menuAction.Accept", False },
2821 { "menuAction.Decline", False },
2822 { "menuAction.Rematch", False },
2823 { "menuAction.Adjourn", False },
2824 { "menuAction.Stop Examining", False },
2825 { "menuAction.Stop Observing", False },
2826 { "menuAction.Upload to Examine", False },
2827 { "menuEdit.Revert", False },
2828 { "menuEdit.Annotate", False },
2829 { "menuOptions.ICS", False },
2831 /* The next two options rely on SetCmailMode being called *after* */
2832 /* SetGNUMode so that when GNU is being used to give hints these */
2833 /* menu options are still available */
2835 { "menuFile.Mail Move", False },
2836 { "menuFile.Reload CMail Message", False },
2840 Enables cmailEnables[] = {
2842 { "menuAction.Call Flag", False },
2843 { "menuAction.Draw", True },
2844 { "menuAction.Adjourn", False },
2845 { "menuAction.Abort", False },
2846 { "menuAction.Stop Observing", False },
2847 { "menuAction.Stop Examining", False },
2848 { "menuFile.Mail Move", True },
2849 { "menuFile.Reload CMail Message", True },
2853 Enables trainingOnEnables[] = {
2854 { "menuMode.Edit Comment", False },
2855 { "menuMode.Pause", False },
2856 { "menuEdit.Forward", False },
2857 { "menuEdit.Backward", False },
2858 { "menuEdit.Forward to End", False },
2859 { "menuEdit.Back to Start", False },
2860 { "menuEngine.Move Now", False },
2861 { "menuEdit.Truncate Game", False },
2865 Enables trainingOffEnables[] = {
2866 { "menuMode.Edit Comment", True },
2867 { "menuMode.Pause", True },
2868 { "menuEdit.Forward", True },
2869 { "menuEdit.Backward", True },
2870 { "menuEdit.Forward to End", True },
2871 { "menuEdit.Back to Start", True },
2872 { "menuEngine.Move Now", True },
2873 { "menuEdit.Truncate Game", True },
2877 Enables machineThinkingEnables[] = {
2878 { "menuFile.Load Game", False },
2879 // { "menuFile.Load Next Game", False },
2880 // { "menuFile.Load Previous Game", False },
2881 // { "menuFile.Reload Same Game", False },
2882 { "menuEdit.Paste Game", False },
2883 { "menuFile.Load Position", False },
2884 // { "menuFile.Load Next Position", False },
2885 // { "menuFile.Load Previous Position", False },
2886 // { "menuFile.Reload Same Position", False },
2887 { "menuEdit.Paste Position", False },
2888 { "menuMode.Machine White", False },
2889 { "menuMode.Machine Black", False },
2890 { "menuMode.Two Machines", False },
2891 { "menuMode.Machine Match", False },
2892 { "menuEngine.Retract Move", False },
2896 Enables userThinkingEnables[] = {
2897 { "menuFile.Load Game", True },
2898 // { "menuFile.Load Next Game", True },
2899 // { "menuFile.Load Previous Game", True },
2900 // { "menuFile.Reload Same Game", True },
2901 { "menuEdit.Paste Game", True },
2902 { "menuFile.Load Position", True },
2903 // { "menuFile.Load Next Position", True },
2904 // { "menuFile.Load Previous Position", True },
2905 // { "menuFile.Reload Same Position", True },
2906 { "menuEdit.Paste Position", True },
2907 { "menuMode.Machine White", True },
2908 { "menuMode.Machine Black", True },
2909 { "menuMode.Two Machines", True },
2910 { "menuMode.Machine Match", True },
2911 { "menuEngine.Retract Move", True },
2917 SetMenuEnables(icsEnables);
2920 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2921 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2928 SetMenuEnables(ncpEnables);
2934 SetMenuEnables(gnuEnables);
2940 SetMenuEnables(cmailEnables);
2946 SetMenuEnables(trainingOnEnables);
2947 if (appData.showButtonBar) {
2948 XtSetSensitive(buttonBarWidget, False);
2954 SetTrainingModeOff()
2956 SetMenuEnables(trainingOffEnables);
2957 if (appData.showButtonBar) {
2958 XtSetSensitive(buttonBarWidget, True);
2963 SetUserThinkingEnables()
2965 if (appData.noChessProgram) return;
2966 SetMenuEnables(userThinkingEnables);
2970 SetMachineThinkingEnables()
2972 if (appData.noChessProgram) return;
2973 SetMenuEnables(machineThinkingEnables);
2975 case MachinePlaysBlack:
2976 case MachinePlaysWhite:
2977 case TwoMachinesPlay:
2978 XtSetSensitive(XtNameToWidget(menuBarWidget,
2979 ModeToWidgetName(gameMode)), True);
2986 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2987 #define HISTORY_SIZE 64
2988 static char *history[HISTORY_SIZE];
2989 int histIn = 0, histP = 0;
2992 SaveInHistory(char *cmd)
2994 if (history[histIn] != NULL) {
2995 free(history[histIn]);
2996 history[histIn] = NULL;
2998 if (*cmd == NULLCHAR) return;
2999 history[histIn] = StrSave(cmd);
3000 histIn = (histIn + 1) % HISTORY_SIZE;
3001 if (history[histIn] != NULL) {
3002 free(history[histIn]);
3003 history[histIn] = NULL;
3009 PrevInHistory(char *cmd)
3012 if (histP == histIn) {
3013 if (history[histIn] != NULL) free(history[histIn]);
3014 history[histIn] = StrSave(cmd);
3016 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3017 if (newhp == histIn || history[newhp] == NULL) return NULL;
3019 return history[histP];
3025 if (histP == histIn) return NULL;
3026 histP = (histP + 1) % HISTORY_SIZE;
3027 return history[histP];
3029 // end of borrowed code
3031 #define Abs(n) ((n)<0 ? -(n) : (n))
3034 * Find a font that matches "pattern" that is as close as
3035 * possible to the targetPxlSize. Prefer fonts that are k
3036 * pixels smaller to fonts that are k pixels larger. The
3037 * pattern must be in the X Consortium standard format,
3038 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3039 * The return value should be freed with XtFree when no
3043 FindFont(pattern, targetPxlSize)
3047 char **fonts, *p, *best, *scalable, *scalableTail;
3048 int i, j, nfonts, minerr, err, pxlSize;
3051 char **missing_list;
3053 char *def_string, *base_fnt_lst, strInt[3];
3055 XFontStruct **fnt_list;
3057 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3058 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3059 p = strstr(pattern, "--");
3060 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3061 strcat(base_fnt_lst, strInt);
3062 strcat(base_fnt_lst, strchr(p + 2, '-'));
3064 if ((fntSet = XCreateFontSet(xDisplay,
3068 &def_string)) == NULL) {
3070 fprintf(stderr, _("Unable to create font set.\n"));
3074 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3076 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3078 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3079 programName, pattern);
3087 for (i=0; i<nfonts; i++) {
3090 if (*p != '-') continue;
3092 if (*p == NULLCHAR) break;
3093 if (*p++ == '-') j++;
3095 if (j < 7) continue;
3098 scalable = fonts[i];
3101 err = pxlSize - targetPxlSize;
3102 if (Abs(err) < Abs(minerr) ||
3103 (minerr > 0 && err < 0 && -err == minerr)) {
3109 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3110 /* If the error is too big and there is a scalable font,
3111 use the scalable font. */
3112 int headlen = scalableTail - scalable;
3113 p = (char *) XtMalloc(strlen(scalable) + 10);
3114 while (isdigit(*scalableTail)) scalableTail++;
3115 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3117 p = (char *) XtMalloc(strlen(best) + 2);
3118 safeStrCpy(p, best, strlen(best)+1 );
3120 if (appData.debugMode) {
3121 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3122 pattern, targetPxlSize, p);
3125 if (missing_count > 0)
3126 XFreeStringList(missing_list);
3127 XFreeFontSet(xDisplay, fntSet);
3129 XFreeFontNames(fonts);
3135 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3136 // must be called before all non-first callse to CreateGCs()
3137 XtReleaseGC(shellWidget, highlineGC);
3138 XtReleaseGC(shellWidget, lightSquareGC);
3139 XtReleaseGC(shellWidget, darkSquareGC);
3140 XtReleaseGC(shellWidget, lineGC);
3141 if (appData.monoMode) {
3142 if (DefaultDepth(xDisplay, xScreen) == 1) {
3143 XtReleaseGC(shellWidget, wbPieceGC);
3145 XtReleaseGC(shellWidget, bwPieceGC);
3148 XtReleaseGC(shellWidget, prelineGC);
3149 XtReleaseGC(shellWidget, jailSquareGC);
3150 XtReleaseGC(shellWidget, wdPieceGC);
3151 XtReleaseGC(shellWidget, wlPieceGC);
3152 XtReleaseGC(shellWidget, wjPieceGC);
3153 XtReleaseGC(shellWidget, bdPieceGC);
3154 XtReleaseGC(shellWidget, blPieceGC);
3155 XtReleaseGC(shellWidget, bjPieceGC);
3159 void CreateGCs(int redo)
3161 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3162 | GCBackground | GCFunction | GCPlaneMask;
3163 XGCValues gc_values;
3166 gc_values.plane_mask = AllPlanes;
3167 gc_values.line_width = lineGap;
3168 gc_values.line_style = LineSolid;
3169 gc_values.function = GXcopy;
3172 DeleteGCs(); // called a second time; clean up old GCs first
3173 } else { // [HGM] grid and font GCs created on first call only
3174 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3175 gc_values.background = XWhitePixel(xDisplay, xScreen);
3176 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3177 XSetFont(xDisplay, coordGC, coordFontID);
3179 // [HGM] make font for holdings counts (white on black)
3180 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3181 gc_values.background = XBlackPixel(xDisplay, xScreen);
3182 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3183 XSetFont(xDisplay, countGC, countFontID);
3185 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3186 gc_values.background = XBlackPixel(xDisplay, xScreen);
3187 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3189 if (appData.monoMode) {
3190 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3191 gc_values.background = XWhitePixel(xDisplay, xScreen);
3192 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3194 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3195 gc_values.background = XBlackPixel(xDisplay, xScreen);
3196 lightSquareGC = wbPieceGC
3197 = XtGetGC(shellWidget, value_mask, &gc_values);
3199 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3200 gc_values.background = XWhitePixel(xDisplay, xScreen);
3201 darkSquareGC = bwPieceGC
3202 = XtGetGC(shellWidget, value_mask, &gc_values);
3204 if (DefaultDepth(xDisplay, xScreen) == 1) {
3205 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3206 gc_values.function = GXcopyInverted;
3207 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3208 gc_values.function = GXcopy;
3209 if (XBlackPixel(xDisplay, xScreen) == 1) {
3210 bwPieceGC = darkSquareGC;
3211 wbPieceGC = copyInvertedGC;
3213 bwPieceGC = copyInvertedGC;
3214 wbPieceGC = lightSquareGC;
3218 gc_values.foreground = highlightSquareColor;
3219 gc_values.background = highlightSquareColor;
3220 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3222 gc_values.foreground = premoveHighlightColor;
3223 gc_values.background = premoveHighlightColor;
3224 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3226 gc_values.foreground = lightSquareColor;
3227 gc_values.background = darkSquareColor;
3228 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3230 gc_values.foreground = darkSquareColor;
3231 gc_values.background = lightSquareColor;
3232 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3234 gc_values.foreground = jailSquareColor;
3235 gc_values.background = jailSquareColor;
3236 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3238 gc_values.foreground = whitePieceColor;
3239 gc_values.background = darkSquareColor;
3240 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3242 gc_values.foreground = whitePieceColor;
3243 gc_values.background = lightSquareColor;
3244 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3246 gc_values.foreground = whitePieceColor;
3247 gc_values.background = jailSquareColor;
3248 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3250 gc_values.foreground = blackPieceColor;
3251 gc_values.background = darkSquareColor;
3252 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3254 gc_values.foreground = blackPieceColor;
3255 gc_values.background = lightSquareColor;
3256 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3258 gc_values.foreground = blackPieceColor;
3259 gc_values.background = jailSquareColor;
3260 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3264 void loadXIM(xim, xmask, filename, dest, mask)
3277 fp = fopen(filename, "rb");
3279 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3286 for (y=0; y<h; ++y) {
3287 for (x=0; x<h; ++x) {
3292 XPutPixel(xim, x, y, blackPieceColor);
3294 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3297 XPutPixel(xim, x, y, darkSquareColor);
3299 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3302 XPutPixel(xim, x, y, whitePieceColor);
3304 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3307 XPutPixel(xim, x, y, lightSquareColor);
3309 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3317 /* create Pixmap of piece */
3318 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3320 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3323 /* create Pixmap of clipmask
3324 Note: We assume the white/black pieces have the same
3325 outline, so we make only 6 masks. This is okay
3326 since the XPM clipmask routines do the same. */
3328 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3330 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3333 /* now create the 1-bit version */
3334 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3337 values.foreground = 1;
3338 values.background = 0;
3340 /* Don't use XtGetGC, not read only */
3341 maskGC = XCreateGC(xDisplay, *mask,
3342 GCForeground | GCBackground, &values);
3343 XCopyPlane(xDisplay, temp, *mask, maskGC,
3344 0, 0, squareSize, squareSize, 0, 0, 1);
3345 XFreePixmap(xDisplay, temp);
3350 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3352 void CreateXIMPieces()
3357 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3362 /* The XSynchronize calls were copied from CreatePieces.
3363 Not sure if needed, but can't hurt */
3364 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3367 /* temp needed by loadXIM() */
3368 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3369 0, 0, ss, ss, AllPlanes, XYPixmap);
3371 if (strlen(appData.pixmapDirectory) == 0) {
3375 if (appData.monoMode) {
3376 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3380 fprintf(stderr, _("\nLoading XIMs...\n"));
3382 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3383 fprintf(stderr, "%d", piece+1);
3384 for (kind=0; kind<4; kind++) {
3385 fprintf(stderr, ".");
3386 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3387 ExpandPathName(appData.pixmapDirectory),
3388 piece <= (int) WhiteKing ? "" : "w",
3389 pieceBitmapNames[piece],
3391 ximPieceBitmap[kind][piece] =
3392 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3393 0, 0, ss, ss, AllPlanes, XYPixmap);
3394 if (appData.debugMode)
3395 fprintf(stderr, _("(File:%s:) "), buf);
3396 loadXIM(ximPieceBitmap[kind][piece],
3398 &(xpmPieceBitmap2[kind][piece]),
3399 &(ximMaskPm2[piece]));
3400 if(piece <= (int)WhiteKing)
3401 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3403 fprintf(stderr," ");
3405 /* Load light and dark squares */
3406 /* If the LSQ and DSQ pieces don't exist, we will
3407 draw them with solid squares. */
3408 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3409 if (access(buf, 0) != 0) {
3413 fprintf(stderr, _("light square "));
3415 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3416 0, 0, ss, ss, AllPlanes, XYPixmap);
3417 if (appData.debugMode)
3418 fprintf(stderr, _("(File:%s:) "), buf);
3420 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3421 fprintf(stderr, _("dark square "));
3422 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3423 ExpandPathName(appData.pixmapDirectory), ss);
3424 if (appData.debugMode)
3425 fprintf(stderr, _("(File:%s:) "), buf);
3427 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3428 0, 0, ss, ss, AllPlanes, XYPixmap);
3429 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3430 xpmJailSquare = xpmLightSquare;
3432 fprintf(stderr, _("Done.\n"));
3434 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3437 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3440 void CreateXPMBoard(char *s, int kind)
3444 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3445 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3446 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3450 void FreeXPMPieces()
3451 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3452 // thisroutine has to be called t free the old piece pixmaps
3454 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3455 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3457 XFreePixmap(xDisplay, xpmLightSquare);
3458 XFreePixmap(xDisplay, xpmDarkSquare);
3462 void CreateXPMPieces()
3466 u_int ss = squareSize;
3468 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3469 XpmColorSymbol symbols[4];
3470 static int redo = False;
3472 if(redo) FreeXPMPieces(); else redo = 1;
3474 /* The XSynchronize calls were copied from CreatePieces.
3475 Not sure if needed, but can't hurt */
3476 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3478 /* Setup translations so piece colors match square colors */
3479 symbols[0].name = "light_piece";
3480 symbols[0].value = appData.whitePieceColor;
3481 symbols[1].name = "dark_piece";
3482 symbols[1].value = appData.blackPieceColor;
3483 symbols[2].name = "light_square";
3484 symbols[2].value = appData.lightSquareColor;
3485 symbols[3].name = "dark_square";
3486 symbols[3].value = appData.darkSquareColor;
3488 attr.valuemask = XpmColorSymbols;
3489 attr.colorsymbols = symbols;
3490 attr.numsymbols = 4;
3492 if (appData.monoMode) {
3493 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3497 if (strlen(appData.pixmapDirectory) == 0) {
3498 XpmPieces* pieces = builtInXpms;
3501 while (pieces->size != squareSize && pieces->size) pieces++;
3502 if (!pieces->size) {
3503 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3506 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3507 for (kind=0; kind<4; kind++) {
3509 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3510 pieces->xpm[piece][kind],
3511 &(xpmPieceBitmap2[kind][piece]),
3512 NULL, &attr)) != 0) {
3513 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3517 if(piece <= (int) WhiteKing)
3518 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3522 xpmJailSquare = xpmLightSquare;
3526 fprintf(stderr, _("\nLoading XPMs...\n"));
3529 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3530 fprintf(stderr, "%d ", piece+1);
3531 for (kind=0; kind<4; kind++) {
3532 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3533 ExpandPathName(appData.pixmapDirectory),
3534 piece > (int) WhiteKing ? "w" : "",
3535 pieceBitmapNames[piece],
3537 if (appData.debugMode) {
3538 fprintf(stderr, _("(File:%s:) "), buf);
3540 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3541 &(xpmPieceBitmap2[kind][piece]),
3542 NULL, &attr)) != 0) {
3543 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3544 // [HGM] missing: read of unorthodox piece failed; substitute King.
3545 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3546 ExpandPathName(appData.pixmapDirectory),
3548 if (appData.debugMode) {
3549 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3551 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3552 &(xpmPieceBitmap2[kind][piece]),
3556 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3561 if(piece <= (int) WhiteKing)
3562 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3565 /* Load light and dark squares */
3566 /* If the LSQ and DSQ pieces don't exist, we will
3567 draw them with solid squares. */
3568 fprintf(stderr, _("light square "));
3569 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3570 if (access(buf, 0) != 0) {
3574 if (appData.debugMode)
3575 fprintf(stderr, _("(File:%s:) "), buf);
3577 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3578 &xpmLightSquare, NULL, &attr)) != 0) {
3579 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3582 fprintf(stderr, _("dark square "));
3583 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3584 ExpandPathName(appData.pixmapDirectory), ss);
3585 if (appData.debugMode) {
3586 fprintf(stderr, _("(File:%s:) "), buf);
3588 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3589 &xpmDarkSquare, NULL, &attr)) != 0) {
3590 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3594 xpmJailSquare = xpmLightSquare;
3595 fprintf(stderr, _("Done.\n"));
3597 oldVariant = -1; // kludge to force re-makig of animation masks
3598 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3601 #endif /* HAVE_LIBXPM */
3604 /* No built-in bitmaps */
3609 u_int ss = squareSize;
3611 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3614 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3615 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3616 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3617 pieceBitmapNames[piece],
3618 ss, kind == SOLID ? 's' : 'o');
3619 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3620 if(piece <= (int)WhiteKing)
3621 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3625 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3629 /* With built-in bitmaps */
3632 BuiltInBits* bib = builtInBits;
3635 u_int ss = squareSize;
3637 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3640 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3642 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3643 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3644 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3645 pieceBitmapNames[piece],
3646 ss, kind == SOLID ? 's' : 'o');
3647 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3648 bib->bits[kind][piece], ss, ss);
3649 if(piece <= (int)WhiteKing)
3650 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3654 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3659 void ReadBitmap(pm, name, bits, wreq, hreq)
3662 unsigned char bits[];
3668 char msg[MSG_SIZ], fullname[MSG_SIZ];
3670 if (*appData.bitmapDirectory != NULLCHAR) {
3671 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3672 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3673 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3674 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3675 &w, &h, pm, &x_hot, &y_hot);
3676 fprintf(stderr, "load %s\n", name);
3677 if (errcode != BitmapSuccess) {
3679 case BitmapOpenFailed:
3680 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3682 case BitmapFileInvalid:
3683 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3685 case BitmapNoMemory:
3686 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3690 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3694 fprintf(stderr, _("%s: %s...using built-in\n"),
3696 } else if (w != wreq || h != hreq) {
3698 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3699 programName, fullname, w, h, wreq, hreq);
3705 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3714 if (lineGap == 0) return;
3716 /* [HR] Split this into 2 loops for non-square boards. */
3718 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3719 gridSegments[i].x1 = 0;
3720 gridSegments[i].x2 =
3721 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3722 gridSegments[i].y1 = gridSegments[i].y2
3723 = lineGap / 2 + (i * (squareSize + lineGap));
3726 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3727 gridSegments[j + i].y1 = 0;
3728 gridSegments[j + i].y2 =
3729 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3730 gridSegments[j + i].x1 = gridSegments[j + i].x2
3731 = lineGap / 2 + (j * (squareSize + lineGap));
3735 static void MenuBarSelect(w, addr, index)
3740 XtActionProc proc = (XtActionProc) addr;
3742 (proc)(NULL, NULL, NULL, NULL);
3745 void CreateMenuBarPopup(parent, name, mb)
3755 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3758 XtSetArg(args[j], XtNleftMargin, 20); j++;
3759 XtSetArg(args[j], XtNrightMargin, 20); j++;
3761 while (mi->string != NULL) {
3762 if (strcmp(mi->string, "----") == 0) {
3763 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3766 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3767 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3769 XtAddCallback(entry, XtNcallback,
3770 (XtCallbackProc) MenuBarSelect,
3771 (caddr_t) mi->proc);
3777 Widget CreateMenuBar(mb)
3781 Widget anchor, menuBar;
3783 char menuName[MSG_SIZ];
3786 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3787 XtSetArg(args[j], XtNvSpace, 0); j++;
3788 XtSetArg(args[j], XtNborderWidth, 0); j++;
3789 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3790 formWidget, args, j);
3792 while (mb->name != NULL) {
3793 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3794 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3796 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3799 shortName[0] = mb->name[0];
3800 shortName[1] = NULLCHAR;
3801 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3804 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3807 XtSetArg(args[j], XtNborderWidth, 0); j++;
3808 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3810 CreateMenuBarPopup(menuBar, menuName, mb);
3816 Widget CreateButtonBar(mi)
3820 Widget button, buttonBar;
3824 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3826 XtSetArg(args[j], XtNhSpace, 0); j++;
3828 XtSetArg(args[j], XtNborderWidth, 0); j++;
3829 XtSetArg(args[j], XtNvSpace, 0); j++;
3830 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3831 formWidget, args, j);
3833 while (mi->string != NULL) {
3836 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3837 XtSetArg(args[j], XtNborderWidth, 0); j++;
3839 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3840 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3841 buttonBar, args, j);
3842 XtAddCallback(button, XtNcallback,
3843 (XtCallbackProc) MenuBarSelect,
3844 (caddr_t) mi->proc);
3851 CreatePieceMenu(name, color)
3858 ChessSquare selection;
3860 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3861 boardWidget, args, 0);
3863 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3864 String item = pieceMenuStrings[color][i];
3866 if (strcmp(item, "----") == 0) {
3867 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3870 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3871 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3873 selection = pieceMenuTranslation[color][i];
3874 XtAddCallback(entry, XtNcallback,
3875 (XtCallbackProc) PieceMenuSelect,
3876 (caddr_t) selection);
3877 if (selection == WhitePawn || selection == BlackPawn) {
3878 XtSetArg(args[0], XtNpopupOnEntry, entry);
3879 XtSetValues(menu, args, 1);
3892 ChessSquare selection;
3894 whitePieceMenu = CreatePieceMenu("menuW", 0);
3895 blackPieceMenu = CreatePieceMenu("menuB", 1);
3897 XtRegisterGrabAction(PieceMenuPopup, True,
3898 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3899 GrabModeAsync, GrabModeAsync);
3901 XtSetArg(args[0], XtNlabel, _("Drop"));
3902 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3903 boardWidget, args, 1);
3904 for (i = 0; i < DROP_MENU_SIZE; i++) {
3905 String item = dropMenuStrings[i];
3907 if (strcmp(item, "----") == 0) {
3908 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3911 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3912 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3914 selection = dropMenuTranslation[i];
3915 XtAddCallback(entry, XtNcallback,
3916 (XtCallbackProc) DropMenuSelect,
3917 (caddr_t) selection);
3922 void SetupDropMenu()
3930 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3931 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3932 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3933 dmEnables[i].piece);
3934 XtSetSensitive(entry, p != NULL || !appData.testLegality
3935 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3936 && !appData.icsActive));
3938 while (p && *p++ == dmEnables[i].piece) count++;
3939 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3941 XtSetArg(args[j], XtNlabel, label); j++;
3942 XtSetValues(entry, args, j);
3946 void PieceMenuPopup(w, event, params, num_params)
3950 Cardinal *num_params;
3952 String whichMenu; int menuNr;
3953 if (event->type == ButtonRelease)
3954 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3955 else if (event->type == ButtonPress)
3956 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3958 case 0: whichMenu = params[0]; break;
3959 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3961 case -1: if (errorUp) ErrorPopDown();
3964 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3967 static void PieceMenuSelect(w, piece, junk)
3972 if (pmFromX < 0 || pmFromY < 0) return;
3973 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3976 static void DropMenuSelect(w, piece, junk)
3981 if (pmFromX < 0 || pmFromY < 0) return;
3982 DropMenuEvent(piece, pmFromX, pmFromY);
3985 void WhiteClock(w, event, prms, nprms)
3994 void BlackClock(w, event, prms, nprms)
4005 * If the user selects on a border boundary, return -1; if off the board,
4006 * return -2. Otherwise map the event coordinate to the square.
4008 int EventToSquare(x, limit)
4016 if ((x % (squareSize + lineGap)) >= squareSize)
4018 x /= (squareSize + lineGap);
4024 static void do_flash_delay(msec)
4030 static void drawHighlight(file, rank, gc)
4036 if (lineGap == 0) return;
4039 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4040 (squareSize + lineGap);
4041 y = lineGap/2 + rank * (squareSize + lineGap);
4043 x = lineGap/2 + file * (squareSize + lineGap);
4044 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4045 (squareSize + lineGap);
4048 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4049 squareSize+lineGap, squareSize+lineGap);
4052 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4053 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4056 SetHighlights(fromX, fromY, toX, toY)
4057 int fromX, fromY, toX, toY;
4059 if (hi1X != fromX || hi1Y != fromY) {
4060 if (hi1X >= 0 && hi1Y >= 0) {
4061 drawHighlight(hi1X, hi1Y, lineGC);
4063 } // [HGM] first erase both, then draw new!
4064 if (hi2X != toX || hi2Y != toY) {
4065 if (hi2X >= 0 && hi2Y >= 0) {
4066 drawHighlight(hi2X, hi2Y, lineGC);
4069 if (hi1X != fromX || hi1Y != fromY) {
4070 if (fromX >= 0 && fromY >= 0) {
4071 drawHighlight(fromX, fromY, highlineGC);
4074 if (hi2X != toX || hi2Y != toY) {
4075 if (toX >= 0 && toY >= 0) {
4076 drawHighlight(toX, toY, highlineGC);
4088 SetHighlights(-1, -1, -1, -1);
4093 SetPremoveHighlights(fromX, fromY, toX, toY)
4094 int fromX, fromY, toX, toY;
4096 if (pm1X != fromX || pm1Y != fromY) {
4097 if (pm1X >= 0 && pm1Y >= 0) {
4098 drawHighlight(pm1X, pm1Y, lineGC);
4100 if (fromX >= 0 && fromY >= 0) {
4101 drawHighlight(fromX, fromY, prelineGC);
4104 if (pm2X != toX || pm2Y != toY) {
4105 if (pm2X >= 0 && pm2Y >= 0) {
4106 drawHighlight(pm2X, pm2Y, lineGC);
4108 if (toX >= 0 && toY >= 0) {
4109 drawHighlight(toX, toY, prelineGC);
4119 ClearPremoveHighlights()
4121 SetPremoveHighlights(-1, -1, -1, -1);
4124 static int CutOutSquare(x, y, x0, y0, kind)
4125 int x, y, *x0, *y0, kind;
4127 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4128 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4130 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4131 if(textureW[kind] < W*squareSize)
4132 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4134 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4135 if(textureH[kind] < H*squareSize)
4136 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4138 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4142 static void BlankSquare(x, y, color, piece, dest, fac)
4143 int x, y, color, fac;
4146 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4148 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4149 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4150 squareSize, squareSize, x*fac, y*fac);
4152 if (useImages && useImageSqs) {
4156 pm = xpmLightSquare;
4161 case 2: /* neutral */
4166 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4167 squareSize, squareSize, x*fac, y*fac);
4177 case 2: /* neutral */
4182 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4187 I split out the routines to draw a piece so that I could
4188 make a generic flash routine.
4190 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4192 int square_color, x, y;
4195 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4196 switch (square_color) {
4198 case 2: /* neutral */
4200 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4201 ? *pieceToOutline(piece)
4202 : *pieceToSolid(piece),
4203 dest, bwPieceGC, 0, 0,
4204 squareSize, squareSize, x, y);
4207 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4208 ? *pieceToSolid(piece)
4209 : *pieceToOutline(piece),
4210 dest, wbPieceGC, 0, 0,
4211 squareSize, squareSize, x, y);
4216 static void monoDrawPiece(piece, square_color, x, y, dest)
4218 int square_color, x, y;
4221 switch (square_color) {
4223 case 2: /* neutral */
4225 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4226 ? *pieceToOutline(piece)
4227 : *pieceToSolid(piece),
4228 dest, bwPieceGC, 0, 0,
4229 squareSize, squareSize, x, y, 1);
4232 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4233 ? *pieceToSolid(piece)
4234 : *pieceToOutline(piece),
4235 dest, wbPieceGC, 0, 0,
4236 squareSize, squareSize, x, y, 1);
4241 static void colorDrawPiece(piece, square_color, x, y, dest)
4243 int square_color, x, y;
4246 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4247 switch (square_color) {
4249 XCopyPlane(xDisplay, *pieceToSolid(piece),
4250 dest, (int) piece < (int) BlackPawn
4251 ? wlPieceGC : blPieceGC, 0, 0,
4252 squareSize, squareSize, x, y, 1);
4255 XCopyPlane(xDisplay, *pieceToSolid(piece),
4256 dest, (int) piece < (int) BlackPawn
4257 ? wdPieceGC : bdPieceGC, 0, 0,
4258 squareSize, squareSize, x, y, 1);
4260 case 2: /* neutral */
4262 XCopyPlane(xDisplay, *pieceToSolid(piece),
4263 dest, (int) piece < (int) BlackPawn
4264 ? wjPieceGC : bjPieceGC, 0, 0,
4265 squareSize, squareSize, x, y, 1);
4270 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4272 int square_color, x, y;
4275 int kind, p = piece;
4277 switch (square_color) {
4279 case 2: /* neutral */
4281 if ((int)piece < (int) BlackPawn) {
4289 if ((int)piece < (int) BlackPawn) {
4297 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4298 if(useTexture & square_color+1) {
4299 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4300 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4301 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4302 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4303 XSetClipMask(xDisplay, wlPieceGC, None);
4304 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4306 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4307 dest, wlPieceGC, 0, 0,
4308 squareSize, squareSize, x, y);
4311 typedef void (*DrawFunc)();
4313 DrawFunc ChooseDrawFunc()
4315 if (appData.monoMode) {
4316 if (DefaultDepth(xDisplay, xScreen) == 1) {
4317 return monoDrawPiece_1bit;
4319 return monoDrawPiece;
4323 return colorDrawPieceImage;
4325 return colorDrawPiece;
4329 /* [HR] determine square color depending on chess variant. */
4330 static int SquareColor(row, column)
4335 if (gameInfo.variant == VariantXiangqi) {
4336 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4338 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4340 } else if (row <= 4) {
4346 square_color = ((column + row) % 2) == 1;
4349 /* [hgm] holdings: next line makes all holdings squares light */
4350 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4352 return square_color;
4355 void DrawSquare(row, column, piece, do_flash)
4356 int row, column, do_flash;
4359 int square_color, x, y, direction, font_ascent, font_descent;
4362 XCharStruct overall;
4366 /* Calculate delay in milliseconds (2-delays per complete flash) */
4367 flash_delay = 500 / appData.flashRate;
4370 x = lineGap + ((BOARD_WIDTH-1)-column) *
4371 (squareSize + lineGap);
4372 y = lineGap + row * (squareSize + lineGap);
4374 x = lineGap + column * (squareSize + lineGap);
4375 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4376 (squareSize + lineGap);
4379 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4381 square_color = SquareColor(row, column);
4383 if ( // [HGM] holdings: blank out area between board and holdings
4384 column == BOARD_LEFT-1 || column == BOARD_RGHT
4385 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4386 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4387 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4389 // [HGM] print piece counts next to holdings
4390 string[1] = NULLCHAR;
4391 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4392 string[0] = '0' + piece;
4393 XTextExtents(countFontStruct, string, 1, &direction,
4394 &font_ascent, &font_descent, &overall);
4395 if (appData.monoMode) {
4396 XDrawImageString(xDisplay, xBoardWindow, countGC,
4397 x + squareSize - overall.width - 2,
4398 y + font_ascent + 1, string, 1);
4400 XDrawString(xDisplay, xBoardWindow, countGC,
4401 x + squareSize - overall.width - 2,
4402 y + font_ascent + 1, string, 1);
4405 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4406 string[0] = '0' + piece;
4407 XTextExtents(countFontStruct, string, 1, &direction,
4408 &font_ascent, &font_descent, &overall);
4409 if (appData.monoMode) {
4410 XDrawImageString(xDisplay, xBoardWindow, countGC,
4411 x + 2, y + font_ascent + 1, string, 1);
4413 XDrawString(xDisplay, xBoardWindow, countGC,
4414 x + 2, y + font_ascent + 1, string, 1);
4418 if (piece == EmptySquare || appData.blindfold) {
4419 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4421 drawfunc = ChooseDrawFunc();
4423 if (do_flash && appData.flashCount > 0) {
4424 for (i=0; i<appData.flashCount; ++i) {
4425 drawfunc(piece, square_color, x, y, xBoardWindow);
4426 XSync(xDisplay, False);
4427 do_flash_delay(flash_delay);
4429 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4430 XSync(xDisplay, False);
4431 do_flash_delay(flash_delay);
4434 drawfunc(piece, square_color, x, y, xBoardWindow);
4438 string[1] = NULLCHAR;
4439 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4440 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4441 string[0] = 'a' + column - BOARD_LEFT;
4442 XTextExtents(coordFontStruct, string, 1, &direction,
4443 &font_ascent, &font_descent, &overall);
4444 if (appData.monoMode) {
4445 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4446 x + squareSize - overall.width - 2,
4447 y + squareSize - font_descent - 1, string, 1);
4449 XDrawString(xDisplay, xBoardWindow, coordGC,
4450 x + squareSize - overall.width - 2,
4451 y + squareSize - font_descent - 1, string, 1);
4454 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4455 string[0] = ONE + row;
4456 XTextExtents(coordFontStruct, string, 1, &direction,
4457 &font_ascent, &font_descent, &overall);
4458 if (appData.monoMode) {
4459 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4460 x + 2, y + font_ascent + 1, string, 1);
4462 XDrawString(xDisplay, xBoardWindow, coordGC,
4463 x + 2, y + font_ascent + 1, string, 1);
4466 if(!partnerUp && marker[row][column]) {
4467 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4468 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4473 /* Why is this needed on some versions of X? */
4474 void EventProc(widget, unused, event)
4479 if (!XtIsRealized(widget))
4482 switch (event->type) {
4484 if (event->xexpose.count > 0) return; /* no clipping is done */
4485 XDrawPosition(widget, True, NULL);
4486 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4487 flipView = !flipView; partnerUp = !partnerUp;
4488 XDrawPosition(widget, True, NULL);
4489 flipView = !flipView; partnerUp = !partnerUp;
4493 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4500 void DrawPosition(fullRedraw, board)
4501 /*Boolean*/int fullRedraw;
4504 XDrawPosition(boardWidget, fullRedraw, board);
4507 /* Returns 1 if there are "too many" differences between b1 and b2
4508 (i.e. more than 1 move was made) */
4509 static int too_many_diffs(b1, b2)
4515 for (i=0; i<BOARD_HEIGHT; ++i) {
4516 for (j=0; j<BOARD_WIDTH; ++j) {
4517 if (b1[i][j] != b2[i][j]) {
4518 if (++c > 4) /* Castling causes 4 diffs */
4526 /* Matrix describing castling maneuvers */
4527 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4528 static int castling_matrix[4][5] = {
4529 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4530 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4531 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4532 { 7, 7, 4, 5, 6 } /* 0-0, black */
4535 /* Checks whether castling occurred. If it did, *rrow and *rcol
4536 are set to the destination (row,col) of the rook that moved.
4538 Returns 1 if castling occurred, 0 if not.
4540 Note: Only handles a max of 1 castling move, so be sure
4541 to call too_many_diffs() first.
4543 static int check_castle_draw(newb, oldb, rrow, rcol)
4550 /* For each type of castling... */
4551 for (i=0; i<4; ++i) {
4552 r = castling_matrix[i];
4554 /* Check the 4 squares involved in the castling move */
4556 for (j=1; j<=4; ++j) {
4557 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4564 /* All 4 changed, so it must be a castling move */
4573 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4574 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4576 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4579 void DrawSeekBackground( int left, int top, int right, int bottom )
4581 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4584 void DrawSeekText(char *buf, int x, int y)
4586 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4589 void DrawSeekDot(int x, int y, int colorNr)
4591 int square = colorNr & 0x80;
4594 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4596 XFillRectangle(xDisplay, xBoardWindow, color,
4597 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4599 XFillArc(xDisplay, xBoardWindow, color,
4600 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4603 static int damage[2][BOARD_RANKS][BOARD_FILES];
4606 * event handler for redrawing the board
4608 void XDrawPosition(w, repaint, board)
4610 /*Boolean*/int repaint;
4614 static int lastFlipView = 0;
4615 static int lastBoardValid[2] = {0, 0};
4616 static Board lastBoard[2];
4619 int nr = twoBoards*partnerUp;
4621 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4623 if (board == NULL) {
4624 if (!lastBoardValid[nr]) return;
4625 board = lastBoard[nr];
4627 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4628 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4629 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4634 * It would be simpler to clear the window with XClearWindow()
4635 * but this causes a very distracting flicker.
4638 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4640 if ( lineGap && IsDrawArrowEnabled())
4641 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4642 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4644 /* If too much changes (begin observing new game, etc.), don't
4646 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4648 /* Special check for castling so we don't flash both the king
4649 and the rook (just flash the king). */
4651 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4652 /* Draw rook with NO flashing. King will be drawn flashing later */
4653 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4654 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4658 /* First pass -- Draw (newly) empty squares and repair damage.
4659 This prevents you from having a piece show up twice while it
4660 is flashing on its new square */
4661 for (i = 0; i < BOARD_HEIGHT; i++)
4662 for (j = 0; j < BOARD_WIDTH; j++)
4663 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4664 || damage[nr][i][j]) {
4665 DrawSquare(i, j, board[i][j], 0);
4666 damage[nr][i][j] = False;
4669 /* Second pass -- Draw piece(s) in new position and flash them */
4670 for (i = 0; i < BOARD_HEIGHT; i++)
4671 for (j = 0; j < BOARD_WIDTH; j++)
4672 if (board[i][j] != lastBoard[nr][i][j]) {
4673 DrawSquare(i, j, board[i][j], do_flash);
4677 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4678 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4679 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4681 for (i = 0; i < BOARD_HEIGHT; i++)
4682 for (j = 0; j < BOARD_WIDTH; j++) {
4683 DrawSquare(i, j, board[i][j], 0);
4684 damage[nr][i][j] = False;
4688 CopyBoard(lastBoard[nr], board);
4689 lastBoardValid[nr] = 1;
4690 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4691 lastFlipView = flipView;
4693 /* Draw highlights */
4694 if (pm1X >= 0 && pm1Y >= 0) {
4695 drawHighlight(pm1X, pm1Y, prelineGC);
4697 if (pm2X >= 0 && pm2Y >= 0) {
4698 drawHighlight(pm2X, pm2Y, prelineGC);
4700 if (hi1X >= 0 && hi1Y >= 0) {
4701 drawHighlight(hi1X, hi1Y, highlineGC);
4703 if (hi2X >= 0 && hi2Y >= 0) {
4704 drawHighlight(hi2X, hi2Y, highlineGC);
4706 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4708 /* If piece being dragged around board, must redraw that too */
4711 XSync(xDisplay, False);
4716 * event handler for redrawing the board
4718 void DrawPositionProc(w, event, prms, nprms)
4724 XDrawPosition(w, True, NULL);
4729 * event handler for parsing user moves
4731 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4732 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4733 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4734 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4735 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4736 // and at the end FinishMove() to perform the move after optional promotion popups.
4737 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4738 void HandleUserMove(w, event, prms, nprms)
4744 if (w != boardWidget || errorExitStatus != -1) return;
4745 if(nprms) shiftKey = !strcmp(prms[0], "1");
4748 if (event->type == ButtonPress) {
4749 XtPopdown(promotionShell);
4750 XtDestroyWidget(promotionShell);
4751 promotionUp = False;
4759 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4760 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4761 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4764 void AnimateUserMove (Widget w, XEvent * event,
4765 String * params, Cardinal * nParams)
4767 DragPieceMove(event->xmotion.x, event->xmotion.y);
4770 void HandlePV (Widget w, XEvent * event,
4771 String * params, Cardinal * nParams)
4772 { // [HGM] pv: walk PV
4773 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4776 static int savedIndex; /* gross that this is global */
4778 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4781 XawTextPosition index, dummy;
4784 XawTextGetSelectionPos(w, &index, &dummy);
4785 XtSetArg(arg, XtNstring, &val);
4786 XtGetValues(w, &arg, 1);
4787 ReplaceComment(savedIndex, val);
4788 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4789 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4792 void EditCommentPopUp(index, title, text)
4797 if (text == NULL) text = "";
4798 NewCommentPopup(title, text, index);
4801 void ICSInputBoxPopUp()
4806 extern Option boxOptions[];
4808 void ICSInputSendText()
4815 edit = boxOptions[0].handle;
4817 XtSetArg(args[j], XtNstring, &val); j++;
4818 XtGetValues(edit, args, j);
4820 SendMultiLineToICS(val);
4821 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4822 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4825 void ICSInputBoxPopDown()
4830 void CommentPopUp(title, text)
4833 savedIndex = currentMove; // [HGM] vari
4834 NewCommentPopup(title, text, currentMove);
4837 void CommentPopDown()
4842 void FileNamePopUp(label, def, filter, proc, openMode)
4849 fileProc = proc; /* I can't see a way not */
4850 fileOpenMode = openMode; /* to use globals here */
4851 { // [HGM] use file-selector dialog stolen from Ghostview
4853 int index; // this is not supported yet
4855 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
4856 (def[0] ? def : NULL), filter, openMode, NULL, &name))
4857 (void) (*fileProc)(f, index=0, name);
4861 void FileNamePopDown()
4863 if (!filenameUp) return;
4864 XtPopdown(fileNameShell);
4865 XtDestroyWidget(fileNameShell);
4870 void FileNameCallback(w, client_data, call_data)
4872 XtPointer client_data, call_data;
4877 XtSetArg(args[0], XtNlabel, &name);
4878 XtGetValues(w, args, 1);
4880 if (strcmp(name, _("cancel")) == 0) {
4885 FileNameAction(w, NULL, NULL, NULL);
4888 void FileNameAction(w, event, prms, nprms)
4900 name = XawDialogGetValueString(w = XtParent(w));
4902 if ((name != NULL) && (*name != NULLCHAR)) {
4903 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
4904 XtPopdown(w = XtParent(XtParent(w)));
4908 p = strrchr(buf, ' ');
4915 fullname = ExpandPathName(buf);
4917 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
4920 f = fopen(fullname, fileOpenMode);
4922 DisplayError(_("Failed to open file"), errno);
4924 (void) (*fileProc)(f, index, buf);
4931 XtPopdown(w = XtParent(XtParent(w)));
4937 void PromotionPopUp()
4940 Widget dialog, layout;
4942 Dimension bw_width, pw_width;
4946 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4947 XtGetValues(boardWidget, args, j);
4950 XtSetArg(args[j], XtNresizable, True); j++;
4951 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
4953 XtCreatePopupShell("Promotion", transientShellWidgetClass,
4954 shellWidget, args, j);
4956 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
4957 layoutArgs, XtNumber(layoutArgs));
4960 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
4961 XtSetArg(args[j], XtNborderWidth, 0); j++;
4962 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
4965 if(gameInfo.variant != VariantShogi) {
4966 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
4967 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
4968 (XtPointer) dialog);
4969 XawDialogAddButton(dialog, _("General"), PromotionCallback,
4970 (XtPointer) dialog);
4971 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
4972 (XtPointer) dialog);
4973 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
4974 (XtPointer) dialog);
4976 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
4977 (XtPointer) dialog);
4978 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
4979 (XtPointer) dialog);
4980 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
4981 (XtPointer) dialog);
4982 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
4983 (XtPointer) dialog);
4985 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
4986 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4987 gameInfo.variant == VariantGiveaway) {
4988 XawDialogAddButton(dialog, _("King"), PromotionCallback,
4989 (XtPointer) dialog);
4991 if(gameInfo.variant == VariantCapablanca ||
4992 gameInfo.variant == VariantGothic ||
4993 gameInfo.variant == VariantCapaRandom) {
4994 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
4995 (XtPointer) dialog);
4996 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
4997 (XtPointer) dialog);
4999 } else // [HGM] shogi
5001 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5002 (XtPointer) dialog);
5003 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5004 (XtPointer) dialog);
5006 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5007 (XtPointer) dialog);
5009 XtRealizeWidget(promotionShell);
5010 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5013 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5014 XtGetValues(promotionShell, args, j);
5016 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5017 lineGap + squareSize/3 +
5018 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5019 0 : 6*(squareSize + lineGap)), &x, &y);
5022 XtSetArg(args[j], XtNx, x); j++;
5023 XtSetArg(args[j], XtNy, y); j++;
5024 XtSetValues(promotionShell, args, j);
5026 XtPopup(promotionShell, XtGrabNone);
5031 void PromotionPopDown()
5033 if (!promotionUp) return;
5034 XtPopdown(promotionShell);
5035 XtDestroyWidget(promotionShell);
5036 promotionUp = False;
5039 void PromotionCallback(w, client_data, call_data)
5041 XtPointer client_data, call_data;
5047 XtSetArg(args[0], XtNlabel, &name);
5048 XtGetValues(w, args, 1);
5052 if (fromX == -1) return;
5054 if (strcmp(name, _("cancel")) == 0) {
5058 } else if (strcmp(name, _("Knight")) == 0) {
5060 } else if (strcmp(name, _("Promote")) == 0) {
5062 } else if (strcmp(name, _("Defer")) == 0) {
5065 promoChar = ToLower(name[0]);
5068 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5070 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5071 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5076 void ErrorCallback(w, client_data, call_data)
5078 XtPointer client_data, call_data;
5081 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5083 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5089 if (!errorUp) return;
5091 XtPopdown(errorShell);
5092 XtDestroyWidget(errorShell);
5093 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5096 void ErrorPopUp(title, label, modal)
5097 char *title, *label;
5101 Widget dialog, layout;
5105 Dimension bw_width, pw_width;
5106 Dimension pw_height;
5110 XtSetArg(args[i], XtNresizable, True); i++;
5111 XtSetArg(args[i], XtNtitle, title); i++;
5113 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5114 shellWidget, args, i);
5116 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5117 layoutArgs, XtNumber(layoutArgs));
5120 XtSetArg(args[i], XtNlabel, label); i++;
5121 XtSetArg(args[i], XtNborderWidth, 0); i++;
5122 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5125 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5127 XtRealizeWidget(errorShell);
5128 CatchDeleteWindow(errorShell, "ErrorPopDown");
5131 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5132 XtGetValues(boardWidget, args, i);
5134 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5135 XtSetArg(args[i], XtNheight, &pw_height); i++;
5136 XtGetValues(errorShell, args, i);
5139 /* This code seems to tickle an X bug if it is executed too soon
5140 after xboard starts up. The coordinates get transformed as if
5141 the main window was positioned at (0, 0).
5143 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5144 0 - pw_height + squareSize / 3, &x, &y);
5146 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5147 RootWindowOfScreen(XtScreen(boardWidget)),
5148 (bw_width - pw_width) / 2,
5149 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5153 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5156 XtSetArg(args[i], XtNx, x); i++;
5157 XtSetArg(args[i], XtNy, y); i++;
5158 XtSetValues(errorShell, args, i);
5161 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5164 /* Disable all user input other than deleting the window */
5165 static int frozen = 0;
5169 /* Grab by a widget that doesn't accept input */
5170 XtAddGrab(messageWidget, TRUE, FALSE);
5174 /* Undo a FreezeUI */
5177 if (!frozen) return;
5178 XtRemoveGrab(messageWidget);
5182 char *ModeToWidgetName(mode)
5186 case BeginningOfGame:
5187 if (appData.icsActive)
5188 return "menuMode.ICS Client";
5189 else if (appData.noChessProgram ||
5190 *appData.cmailGameName != NULLCHAR)
5191 return "menuMode.Edit Game";
5193 return "menuMode.Machine Black";
5194 case MachinePlaysBlack:
5195 return "menuMode.Machine Black";
5196 case MachinePlaysWhite:
5197 return "menuMode.Machine White";
5199 return "menuMode.Analysis Mode";
5201 return "menuMode.Analyze File";
5202 case TwoMachinesPlay:
5203 return "menuMode.Two Machines";
5205 return "menuMode.Edit Game";
5206 case PlayFromGameFile:
5207 return "menuFile.Load Game";
5209 return "menuMode.Edit Position";
5211 return "menuMode.Training";
5212 case IcsPlayingWhite:
5213 case IcsPlayingBlack:
5217 return "menuMode.ICS Client";
5224 void ModeHighlight()
5227 static int oldPausing = FALSE;
5228 static GameMode oldmode = (GameMode) -1;
5231 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5233 if (pausing != oldPausing) {
5234 oldPausing = pausing;
5236 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5238 XtSetArg(args[0], XtNleftBitmap, None);
5240 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5243 if (appData.showButtonBar) {
5244 /* Always toggle, don't set. Previous code messes up when
5245 invoked while the button is pressed, as releasing it
5246 toggles the state again. */
5249 XtSetArg(args[0], XtNbackground, &oldbg);
5250 XtSetArg(args[1], XtNforeground, &oldfg);
5251 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5253 XtSetArg(args[0], XtNbackground, oldfg);
5254 XtSetArg(args[1], XtNforeground, oldbg);
5256 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5260 wname = ModeToWidgetName(oldmode);
5261 if (wname != NULL) {
5262 XtSetArg(args[0], XtNleftBitmap, None);
5263 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5265 wname = ModeToWidgetName(gameMode);
5266 if (wname != NULL) {
5267 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5268 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5272 /* Maybe all the enables should be handled here, not just this one */
5273 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5274 gameMode == Training || gameMode == PlayFromGameFile);
5279 * Button/menu procedures
5281 void ResetProc(w, event, prms, nprms)
5290 int LoadGamePopUp(f, gameNumber, title)
5295 cmailMsgLoaded = FALSE;
5296 if (gameNumber == 0) {
5297 int error = GameListBuild(f);
5299 DisplayError(_("Cannot build game list"), error);
5300 } else if (!ListEmpty(&gameList) &&
5301 ((ListGame *) gameList.tailPred)->number > 1) {
5302 GameListPopUp(f, title);
5308 return LoadGame(f, gameNumber, title, FALSE);
5311 void LoadGameProc(w, event, prms, nprms)
5317 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5320 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5323 void LoadNextGameProc(w, event, prms, nprms)
5332 void LoadPrevGameProc(w, event, prms, nprms)
5341 void ReloadGameProc(w, event, prms, nprms)
5350 void LoadNextPositionProc(w, event, prms, nprms)
5359 void LoadPrevPositionProc(w, event, prms, nprms)
5368 void ReloadPositionProc(w, event, prms, nprms)
5377 void LoadPositionProc(w, event, prms, nprms)
5383 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5386 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5389 void SaveGameProc(w, event, prms, nprms)
5395 FileNamePopUp(_("Save game file name?"),
5396 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5397 appData.oldSaveStyle ? ".game" : ".pgn",
5401 void SavePositionProc(w, event, prms, nprms)
5407 FileNamePopUp(_("Save position file name?"),
5408 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5409 appData.oldSaveStyle ? ".pos" : ".fen",
5413 void ReloadCmailMsgProc(w, event, prms, nprms)
5419 ReloadCmailMsgEvent(FALSE);
5422 void MailMoveProc(w, event, prms, nprms)
5431 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5432 char *selected_fen_position=NULL;
5435 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5436 Atom *type_return, XtPointer *value_return,
5437 unsigned long *length_return, int *format_return)
5439 char *selection_tmp;
5441 if (!selected_fen_position) return False; /* should never happen */
5442 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5443 /* note: since no XtSelectionDoneProc was registered, Xt will
5444 * automatically call XtFree on the value returned. So have to
5445 * make a copy of it allocated with XtMalloc */
5446 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5447 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5449 *value_return=selection_tmp;
5450 *length_return=strlen(selection_tmp);
5451 *type_return=*target;
5452 *format_return = 8; /* bits per byte */
5454 } else if (*target == XA_TARGETS(xDisplay)) {
5455 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5456 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5457 targets_tmp[1] = XA_STRING;
5458 *value_return = targets_tmp;
5459 *type_return = XA_ATOM;
5461 *format_return = 8 * sizeof(Atom);
5462 if (*format_return > 32) {
5463 *length_return *= *format_return / 32;
5464 *format_return = 32;
5472 /* note: when called from menu all parameters are NULL, so no clue what the
5473 * Widget which was clicked on was, or what the click event was
5475 void CopyPositionProc(w, event, prms, nprms)
5482 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5483 * have a notion of a position that is selected but not copied.
5484 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5486 if(gameMode == EditPosition) EditPositionDone(TRUE);
5487 if (selected_fen_position) free(selected_fen_position);
5488 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5489 if (!selected_fen_position) return;
5490 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5492 SendPositionSelection,
5493 NULL/* lose_ownership_proc */ ,
5494 NULL/* transfer_done_proc */);
5495 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5497 SendPositionSelection,
5498 NULL/* lose_ownership_proc */ ,
5499 NULL/* transfer_done_proc */);
5502 /* function called when the data to Paste is ready */
5504 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5505 Atom *type, XtPointer value, unsigned long *len, int *format)
5508 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5509 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5510 EditPositionPasteFEN(fenstr);
5514 /* called when Paste Position button is pressed,
5515 * all parameters will be NULL */
5516 void PastePositionProc(w, event, prms, nprms)
5522 XtGetSelectionValue(menuBarWidget,
5523 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5524 /* (XtSelectionCallbackProc) */ PastePositionCB,
5525 NULL, /* client_data passed to PastePositionCB */
5527 /* better to use the time field from the event that triggered the
5528 * call to this function, but that isn't trivial to get
5536 SendGameSelection(Widget w, Atom *selection, Atom *target,
5537 Atom *type_return, XtPointer *value_return,
5538 unsigned long *length_return, int *format_return)
5540 char *selection_tmp;
5542 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5543 FILE* f = fopen(gameCopyFilename, "r");
5546 if (f == NULL) return False;
5550 selection_tmp = XtMalloc(len + 1);
5551 count = fread(selection_tmp, 1, len, f);
5554 XtFree(selection_tmp);
5557 selection_tmp[len] = NULLCHAR;
5558 *value_return = selection_tmp;
5559 *length_return = len;
5560 *type_return = *target;
5561 *format_return = 8; /* bits per byte */
5563 } else if (*target == XA_TARGETS(xDisplay)) {
5564 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5565 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5566 targets_tmp[1] = XA_STRING;
5567 *value_return = targets_tmp;
5568 *type_return = XA_ATOM;
5570 *format_return = 8 * sizeof(Atom);
5571 if (*format_return > 32) {
5572 *length_return *= *format_return / 32;
5573 *format_return = 32;
5581 /* note: when called from menu all parameters are NULL, so no clue what the
5582 * Widget which was clicked on was, or what the click event was
5584 void CopyGameProc(w, event, prms, nprms)
5592 ret = SaveGameToFile(gameCopyFilename, FALSE);
5596 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5597 * have a notion of a game that is selected but not copied.
5598 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5600 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5603 NULL/* lose_ownership_proc */ ,
5604 NULL/* transfer_done_proc */);
5605 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5608 NULL/* lose_ownership_proc */ ,
5609 NULL/* transfer_done_proc */);
5612 /* function called when the data to Paste is ready */
5614 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5615 Atom *type, XtPointer value, unsigned long *len, int *format)
5618 if (value == NULL || *len == 0) {
5619 return; /* nothing had been selected to copy */
5621 f = fopen(gamePasteFilename, "w");
5623 DisplayError(_("Can't open temp file"), errno);
5626 fwrite(value, 1, *len, f);
5629 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5632 /* called when Paste Game button is pressed,
5633 * all parameters will be NULL */
5634 void PasteGameProc(w, event, prms, nprms)
5640 XtGetSelectionValue(menuBarWidget,
5641 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5642 /* (XtSelectionCallbackProc) */ PasteGameCB,
5643 NULL, /* client_data passed to PasteGameCB */
5645 /* better to use the time field from the event that triggered the
5646 * call to this function, but that isn't trivial to get
5656 SaveGameProc(NULL, NULL, NULL, NULL);
5660 void QuitProc(w, event, prms, nprms)
5669 void PauseProc(w, event, prms, nprms)
5679 void MachineBlackProc(w, event, prms, nprms)
5685 MachineBlackEvent();
5688 void MachineWhiteProc(w, event, prms, nprms)
5694 MachineWhiteEvent();
5697 void AnalyzeModeProc(w, event, prms, nprms)
5705 if (!first.analysisSupport) {
5706 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5707 DisplayError(buf, 0);
5710 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5711 if (appData.icsActive) {
5712 if (gameMode != IcsObserving) {
5713 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5714 DisplayError(buf, 0);
5716 if (appData.icsEngineAnalyze) {
5717 if (appData.debugMode)
5718 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5724 /* if enable, use want disable icsEngineAnalyze */
5725 if (appData.icsEngineAnalyze) {
5730 appData.icsEngineAnalyze = TRUE;
5731 if (appData.debugMode)
5732 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5734 #ifndef OPTIONSDIALOG
5735 if (!appData.showThinking)
5736 ShowThinkingProc(w,event,prms,nprms);
5742 void AnalyzeFileProc(w, event, prms, nprms)
5748 if (!first.analysisSupport) {
5750 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5751 DisplayError(buf, 0);
5755 #ifndef OPTIONSDIALOG
5756 if (!appData.showThinking)
5757 ShowThinkingProc(w,event,prms,nprms);
5760 FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5761 AnalysisPeriodicEvent(1);
5764 void TwoMachinesProc(w, event, prms, nprms)
5773 void MatchProc(w, event, prms, nprms)
5779 if(gameMode != BeginningOfGame) { DisplayError(_("You can only start a match from the initial position."), 0); return; }
5780 matchMode = 2; // This is back-end, really
\r
5781 appData.matchGames = appData.defaultMatchGames;
\r
5783 first.matchWins = second.matchWins = 0;
\r
5787 void IcsClientProc(w, event, prms, nprms)
5796 void EditGameProc(w, event, prms, nprms)
5805 void EditPositionProc(w, event, prms, nprms)
5811 EditPositionEvent();
5814 void TrainingProc(w, event, prms, nprms)
5823 void EditCommentProc(w, event, prms, nprms)
5831 if (PopDown(1)) { // popdown succesful
5833 XtSetArg(args[j], XtNleftBitmap, None); j++;
5834 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
5835 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
5836 } else // was not up
5840 void IcsInputBoxProc(w, event, prms, nprms)
5846 if (!PopDown(4)) ICSInputBoxPopUp();
5849 void AcceptProc(w, event, prms, nprms)
5858 void DeclineProc(w, event, prms, nprms)
5867 void RematchProc(w, event, prms, nprms)
5876 void CallFlagProc(w, event, prms, nprms)
5885 void DrawProc(w, event, prms, nprms)
5894 void AbortProc(w, event, prms, nprms)
5903 void AdjournProc(w, event, prms, nprms)
5912 void ResignProc(w, event, prms, nprms)
5921 void AdjuWhiteProc(w, event, prms, nprms)
5927 UserAdjudicationEvent(+1);
5930 void AdjuBlackProc(w, event, prms, nprms)
5936 UserAdjudicationEvent(-1);
5939 void AdjuDrawProc(w, event, prms, nprms)
5945 UserAdjudicationEvent(0);
5948 void EnterKeyProc(w, event, prms, nprms)
5954 if (shellUp[4] == True)
5958 void UpKeyProc(w, event, prms, nprms)
5963 { // [HGM] input: let up-arrow recall previous line from history
5970 if (!shellUp[4]) return;
5971 edit = boxOptions[0].handle;
5973 XtSetArg(args[j], XtNstring, &val); j++;
5974 XtGetValues(edit, args, j);
5975 val = PrevInHistory(val);
5976 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5977 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5979 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
5980 XawTextReplace(edit, 0, 0, &t);
5981 XawTextSetInsertionPoint(edit, 9999);
5985 void DownKeyProc(w, event, prms, nprms)
5990 { // [HGM] input: let down-arrow recall next line from history
5995 if (!shellUp[4]) return;
5996 edit = boxOptions[0].handle;
5997 val = NextInHistory();
5998 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5999 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6001 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6002 XawTextReplace(edit, 0, 0, &t);
6003 XawTextSetInsertionPoint(edit, 9999);
6007 void StopObservingProc(w, event, prms, nprms)
6013 StopObservingEvent();
6016 void StopExaminingProc(w, event, prms, nprms)
6022 StopExaminingEvent();
6025 void UploadProc(w, event, prms, nprms)
6035 void ForwardProc(w, event, prms, nprms)
6045 void BackwardProc(w, event, prms, nprms)
6054 void ToStartProc(w, event, prms, nprms)
6063 void ToEndProc(w, event, prms, nprms)
6072 void RevertProc(w, event, prms, nprms)
6081 void AnnotateProc(w, event, prms, nprms)
6090 void TruncateGameProc(w, event, prms, nprms)
6096 TruncateGameEvent();
6098 void RetractMoveProc(w, event, prms, nprms)
6107 void MoveNowProc(w, event, prms, nprms)
6116 void FlipViewProc(w, event, prms, nprms)
6122 flipView = !flipView;
6123 DrawPosition(True, NULL);
6126 void PonderNextMoveProc(w, event, prms, nprms)
6134 PonderNextMoveEvent(!appData.ponderNextMove);
6135 #ifndef OPTIONSDIALOG
6136 if (appData.ponderNextMove) {
6137 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6139 XtSetArg(args[0], XtNleftBitmap, None);
6141 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6146 #ifndef OPTIONSDIALOG
6147 void AlwaysQueenProc(w, event, prms, nprms)
6155 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6157 if (appData.alwaysPromoteToQueen) {
6158 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6160 XtSetArg(args[0], XtNleftBitmap, None);
6162 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6166 void AnimateDraggingProc(w, event, prms, nprms)
6174 appData.animateDragging = !appData.animateDragging;
6176 if (appData.animateDragging) {
6177 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6180 XtSetArg(args[0], XtNleftBitmap, None);
6182 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6186 void AnimateMovingProc(w, event, prms, nprms)
6194 appData.animate = !appData.animate;
6196 if (appData.animate) {
6197 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6200 XtSetArg(args[0], XtNleftBitmap, None);
6202 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6206 void AutoflagProc(w, event, prms, nprms)
6214 appData.autoCallFlag = !appData.autoCallFlag;
6216 if (appData.autoCallFlag) {
6217 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6219 XtSetArg(args[0], XtNleftBitmap, None);
6221 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6225 void AutoflipProc(w, event, prms, nprms)
6233 appData.autoFlipView = !appData.autoFlipView;
6235 if (appData.autoFlipView) {
6236 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6238 XtSetArg(args[0], XtNleftBitmap, None);
6240 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6244 void BlindfoldProc(w, event, prms, nprms)
6252 appData.blindfold = !appData.blindfold;
6254 if (appData.blindfold) {
6255 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6257 XtSetArg(args[0], XtNleftBitmap, None);
6259 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6262 DrawPosition(True, NULL);
6265 void TestLegalityProc(w, event, prms, nprms)
6273 appData.testLegality = !appData.testLegality;
6275 if (appData.testLegality) {
6276 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6278 XtSetArg(args[0], XtNleftBitmap, None);
6280 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6285 void FlashMovesProc(w, event, prms, nprms)
6293 if (appData.flashCount == 0) {
6294 appData.flashCount = 3;
6296 appData.flashCount = -appData.flashCount;
6299 if (appData.flashCount > 0) {
6300 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6302 XtSetArg(args[0], XtNleftBitmap, None);
6304 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6309 void HighlightDraggingProc(w, event, prms, nprms)
6317 appData.highlightDragging = !appData.highlightDragging;
6319 if (appData.highlightDragging) {
6320 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6322 XtSetArg(args[0], XtNleftBitmap, None);
6324 XtSetValues(XtNameToWidget(menuBarWidget,
6325 "menuOptions.Highlight Dragging"), args, 1);
6329 void HighlightLastMoveProc(w, event, prms, nprms)
6337 appData.highlightLastMove = !appData.highlightLastMove;
6339 if (appData.highlightLastMove) {
6340 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6342 XtSetArg(args[0], XtNleftBitmap, None);
6344 XtSetValues(XtNameToWidget(menuBarWidget,
6345 "menuOptions.Highlight Last Move"), args, 1);
6348 void HighlightArrowProc(w, event, prms, nprms)
6356 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6358 if (appData.highlightMoveWithArrow) {
6359 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6361 XtSetArg(args[0], XtNleftBitmap, None);
6363 XtSetValues(XtNameToWidget(menuBarWidget,
6364 "menuOptions.Arrow"), args, 1);
6368 void IcsAlarmProc(w, event, prms, nprms)
6376 appData.icsAlarm = !appData.icsAlarm;
6378 if (appData.icsAlarm) {
6379 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6381 XtSetArg(args[0], XtNleftBitmap, None);
6383 XtSetValues(XtNameToWidget(menuBarWidget,
6384 "menuOptions.ICS Alarm"), args, 1);
6388 void MoveSoundProc(w, event, prms, nprms)
6396 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6398 if (appData.ringBellAfterMoves) {
6399 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6401 XtSetArg(args[0], XtNleftBitmap, None);
6403 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6407 void OneClickProc(w, event, prms, nprms)
6415 appData.oneClick = !appData.oneClick;
6417 if (appData.oneClick) {
6418 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6420 XtSetArg(args[0], XtNleftBitmap, None);
6422 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6426 void PeriodicUpdatesProc(w, event, prms, nprms)
6434 PeriodicUpdatesEvent(!appData.periodicUpdates);
6436 if (appData.periodicUpdates) {
6437 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6439 XtSetArg(args[0], XtNleftBitmap, None);
6441 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6445 void PopupExitMessageProc(w, event, prms, nprms)
6453 appData.popupExitMessage = !appData.popupExitMessage;
6455 if (appData.popupExitMessage) {
6456 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6458 XtSetArg(args[0], XtNleftBitmap, None);
6460 XtSetValues(XtNameToWidget(menuBarWidget,
6461 "menuOptions.Popup Exit Message"), args, 1);
6464 void PopupMoveErrorsProc(w, event, prms, nprms)
6472 appData.popupMoveErrors = !appData.popupMoveErrors;
6474 if (appData.popupMoveErrors) {
6475 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6477 XtSetArg(args[0], XtNleftBitmap, None);
6479 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6484 void PremoveProc(w, event, prms, nprms)
6492 appData.premove = !appData.premove;
6494 if (appData.premove) {
6495 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6497 XtSetArg(args[0], XtNleftBitmap, None);
6499 XtSetValues(XtNameToWidget(menuBarWidget,
6500 "menuOptions.Premove"), args, 1);
6504 void ShowCoordsProc(w, event, prms, nprms)
6512 appData.showCoords = !appData.showCoords;
6514 if (appData.showCoords) {
6515 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6517 XtSetArg(args[0], XtNleftBitmap, None);
6519 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6522 DrawPosition(True, NULL);
6525 void ShowThinkingProc(w, event, prms, nprms)
6531 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6532 ShowThinkingEvent();
6535 void HideThinkingProc(w, event, prms, nprms)
6543 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6544 ShowThinkingEvent();
6546 if (appData.hideThinkingFromHuman) {
6547 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6549 XtSetArg(args[0], XtNleftBitmap, None);
6551 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6556 void SaveOnExitProc(w, event, prms, nprms)
6564 saveSettingsOnExit = !saveSettingsOnExit;
6566 if (saveSettingsOnExit) {
6567 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6569 XtSetArg(args[0], XtNleftBitmap, None);
6571 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6575 void SaveSettingsProc(w, event, prms, nprms)
6581 SaveSettings(settingsFileName);
6584 void InfoProc(w, event, prms, nprms)
6591 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6596 void ManProc(w, event, prms, nprms)
6604 if (nprms && *nprms > 0)
6608 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6612 void HintProc(w, event, prms, nprms)
6621 void BookProc(w, event, prms, nprms)
6630 void AboutProc(w, event, prms, nprms)
6638 char *zippy = " (with Zippy code)";
6642 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6643 programVersion, zippy,
6644 "Copyright 1991 Digital Equipment Corporation",
6645 "Enhancements Copyright 1992-2009 Free Software Foundation",
6646 "Enhancements Copyright 2005 Alessandro Scotti",
6647 PACKAGE, " is free software and carries NO WARRANTY;",
6648 "see the file COPYING for more information.");
6649 ErrorPopUp(_("About XBoard"), buf, FALSE);
6652 void DebugProc(w, event, prms, nprms)
6658 appData.debugMode = !appData.debugMode;
6661 void AboutGameProc(w, event, prms, nprms)
6670 void NothingProc(w, event, prms, nprms)
6679 void Iconify(w, event, prms, nprms)
6688 XtSetArg(args[0], XtNiconic, True);
6689 XtSetValues(shellWidget, args, 1);
6692 void DisplayMessage(message, extMessage)
6693 char *message, *extMessage;
6695 /* display a message in the message widget */
6704 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6709 message = extMessage;
6713 /* need to test if messageWidget already exists, since this function
6714 can also be called during the startup, if for example a Xresource
6715 is not set up correctly */
6718 XtSetArg(arg, XtNlabel, message);
6719 XtSetValues(messageWidget, &arg, 1);
6725 void DisplayTitle(text)
6730 char title[MSG_SIZ];
6733 if (text == NULL) text = "";
6735 if (appData.titleInWindow) {
6737 XtSetArg(args[i], XtNlabel, text); i++;
6738 XtSetValues(titleWidget, args, i);
6741 if (*text != NULLCHAR) {
6742 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6743 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6744 } else if (appData.icsActive) {
6745 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6746 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6747 } else if (appData.cmailGameName[0] != NULLCHAR) {
6748 snprintf(icon, sizeof(icon), "%s", "CMail");
6749 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6751 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6752 } else if (gameInfo.variant == VariantGothic) {
6753 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6754 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6757 } else if (gameInfo.variant == VariantFalcon) {
6758 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6759 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6761 } else if (appData.noChessProgram) {
6762 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6763 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6765 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6766 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6769 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6770 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6771 XtSetValues(shellWidget, args, i);
6776 DisplayError(message, error)
6783 if (appData.debugMode || appData.matchMode) {
6784 fprintf(stderr, "%s: %s\n", programName, message);
6787 if (appData.debugMode || appData.matchMode) {
6788 fprintf(stderr, "%s: %s: %s\n",
6789 programName, message, strerror(error));
6791 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6794 ErrorPopUp(_("Error"), message, FALSE);
6798 void DisplayMoveError(message)
6803 DrawPosition(FALSE, NULL);
6804 if (appData.debugMode || appData.matchMode) {
6805 fprintf(stderr, "%s: %s\n", programName, message);
6807 if (appData.popupMoveErrors) {
6808 ErrorPopUp(_("Error"), message, FALSE);
6810 DisplayMessage(message, "");
6815 void DisplayFatalError(message, error, status)
6821 errorExitStatus = status;
6823 fprintf(stderr, "%s: %s\n", programName, message);
6825 fprintf(stderr, "%s: %s: %s\n",
6826 programName, message, strerror(error));
6827 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6830 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6831 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6837 void DisplayInformation(message)
6841 ErrorPopUp(_("Information"), message, TRUE);
6844 void DisplayNote(message)
6848 ErrorPopUp(_("Note"), message, FALSE);
6852 NullXErrorCheck(dpy, error_event)
6854 XErrorEvent *error_event;
6859 void DisplayIcsInteractionTitle(message)
6862 if (oldICSInteractionTitle == NULL) {
6863 /* Magic to find the old window title, adapted from vim */
6864 char *wina = getenv("WINDOWID");
6866 Window win = (Window) atoi(wina);
6867 Window root, parent, *children;
6868 unsigned int nchildren;
6869 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6871 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6872 if (!XQueryTree(xDisplay, win, &root, &parent,
6873 &children, &nchildren)) break;
6874 if (children) XFree((void *)children);
6875 if (parent == root || parent == 0) break;
6878 XSetErrorHandler(oldHandler);
6880 if (oldICSInteractionTitle == NULL) {
6881 oldICSInteractionTitle = "xterm";
6884 printf("\033]0;%s\007", message);
6888 char pendingReplyPrefix[MSG_SIZ];
6889 ProcRef pendingReplyPR;
6891 void AskQuestionProc(w, event, prms, nprms)
6898 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6902 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6905 void AskQuestionPopDown()
6907 if (!askQuestionUp) return;
6908 XtPopdown(askQuestionShell);
6909 XtDestroyWidget(askQuestionShell);
6910 askQuestionUp = False;
6913 void AskQuestionReplyAction(w, event, prms, nprms)
6923 reply = XawDialogGetValueString(w = XtParent(w));
6924 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
6925 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
6926 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
6927 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
6928 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6929 AskQuestionPopDown();
6931 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
6934 void AskQuestionCallback(w, client_data, call_data)
6936 XtPointer client_data, call_data;
6941 XtSetArg(args[0], XtNlabel, &name);
6942 XtGetValues(w, args, 1);
6944 if (strcmp(name, _("cancel")) == 0) {
6945 AskQuestionPopDown();
6947 AskQuestionReplyAction(w, NULL, NULL, NULL);
6951 void AskQuestion(title, question, replyPrefix, pr)
6952 char *title, *question, *replyPrefix;
6956 Widget popup, layout, dialog, edit;
6962 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
6963 pendingReplyPR = pr;
6966 XtSetArg(args[i], XtNresizable, True); i++;
6967 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
6968 askQuestionShell = popup =
6969 XtCreatePopupShell(title, transientShellWidgetClass,
6970 shellWidget, args, i);
6973 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
6974 layoutArgs, XtNumber(layoutArgs));
6977 XtSetArg(args[i], XtNlabel, question); i++;
6978 XtSetArg(args[i], XtNvalue, ""); i++;
6979 XtSetArg(args[i], XtNborderWidth, 0); i++;
6980 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
6983 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
6984 (XtPointer) dialog);
6985 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
6986 (XtPointer) dialog);
6988 XtRealizeWidget(popup);
6989 CatchDeleteWindow(popup, "AskQuestionPopDown");
6991 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
6992 &x, &y, &win_x, &win_y, &mask);
6994 XtSetArg(args[0], XtNx, x - 10);
6995 XtSetArg(args[1], XtNy, y - 30);
6996 XtSetValues(popup, args, 2);
6998 XtPopup(popup, XtGrabExclusive);
6999 askQuestionUp = True;
7001 edit = XtNameToWidget(dialog, "*value");
7002 XtSetKeyboardFocus(popup, edit);
7010 if (*name == NULLCHAR) {
7012 } else if (strcmp(name, "$") == 0) {
7013 putc(BELLCHAR, stderr);
7016 char *prefix = "", *sep = "";
7017 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7018 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7026 PlaySound(appData.soundMove);
7032 PlaySound(appData.soundIcsWin);
7038 PlaySound(appData.soundIcsLoss);
7044 PlaySound(appData.soundIcsDraw);
7048 PlayIcsUnfinishedSound()
7050 PlaySound(appData.soundIcsUnfinished);
7056 PlaySound(appData.soundIcsAlarm);
7062 system("stty echo");
7068 system("stty -echo");
7072 Colorize(cc, continuation)
7077 int count, outCount, error;
7079 if (textColors[(int)cc].bg > 0) {
7080 if (textColors[(int)cc].fg > 0) {
7081 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7082 textColors[(int)cc].fg, textColors[(int)cc].bg);
7084 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7085 textColors[(int)cc].bg);
7088 if (textColors[(int)cc].fg > 0) {
7089 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7090 textColors[(int)cc].fg);
7092 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7095 count = strlen(buf);
7096 outCount = OutputToProcess(NoProc, buf, count, &error);
7097 if (outCount < count) {
7098 DisplayFatalError(_("Error writing to display"), error, 1);
7101 if (continuation) return;
7104 PlaySound(appData.soundShout);
7107 PlaySound(appData.soundSShout);
7110 PlaySound(appData.soundChannel1);
7113 PlaySound(appData.soundChannel);
7116 PlaySound(appData.soundKibitz);
7119 PlaySound(appData.soundTell);
7121 case ColorChallenge:
7122 PlaySound(appData.soundChallenge);
7125 PlaySound(appData.soundRequest);
7128 PlaySound(appData.soundSeek);
7139 return getpwuid(getuid())->pw_name;
7143 ExpandPathName(path)
7146 static char static_buf[4*MSG_SIZ];
7147 char *d, *s, buf[4*MSG_SIZ];
7153 while (*s && isspace(*s))
7162 if (*(s+1) == '/') {
7163 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7167 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7168 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7169 pwd = getpwnam(buf);
7172 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7176 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7177 strcat(d, strchr(s+1, '/'));
7181 safeStrCpy(d, s, 4*MSG_SIZ );
7188 static char host_name[MSG_SIZ];
7190 #if HAVE_GETHOSTNAME
7191 gethostname(host_name, MSG_SIZ);
7193 #else /* not HAVE_GETHOSTNAME */
7194 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7195 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7197 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7199 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7200 #endif /* not HAVE_GETHOSTNAME */
7203 XtIntervalId delayedEventTimerXID = 0;
7204 DelayedEventCallback delayedEventCallback = 0;
7209 delayedEventTimerXID = 0;
7210 delayedEventCallback();
7214 ScheduleDelayedEvent(cb, millisec)
7215 DelayedEventCallback cb; long millisec;
7217 if(delayedEventTimerXID && delayedEventCallback == cb)
7218 // [HGM] alive: replace, rather than add or flush identical event
7219 XtRemoveTimeOut(delayedEventTimerXID);
7220 delayedEventCallback = cb;
7221 delayedEventTimerXID =
7222 XtAppAddTimeOut(appContext, millisec,
7223 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7226 DelayedEventCallback
7229 if (delayedEventTimerXID) {
7230 return delayedEventCallback;
7237 CancelDelayedEvent()
7239 if (delayedEventTimerXID) {
7240 XtRemoveTimeOut(delayedEventTimerXID);
7241 delayedEventTimerXID = 0;
7245 XtIntervalId loadGameTimerXID = 0;
7247 int LoadGameTimerRunning()
7249 return loadGameTimerXID != 0;
7252 int StopLoadGameTimer()
7254 if (loadGameTimerXID != 0) {
7255 XtRemoveTimeOut(loadGameTimerXID);
7256 loadGameTimerXID = 0;
7264 LoadGameTimerCallback(arg, id)
7268 loadGameTimerXID = 0;
7273 StartLoadGameTimer(millisec)
7277 XtAppAddTimeOut(appContext, millisec,
7278 (XtTimerCallbackProc) LoadGameTimerCallback,
7282 XtIntervalId analysisClockXID = 0;
7285 AnalysisClockCallback(arg, id)
7289 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7290 || appData.icsEngineAnalyze) { // [DM]
7291 AnalysisPeriodicEvent(0);
7292 StartAnalysisClock();
7297 StartAnalysisClock()
7300 XtAppAddTimeOut(appContext, 2000,
7301 (XtTimerCallbackProc) AnalysisClockCallback,
7305 XtIntervalId clockTimerXID = 0;
7307 int ClockTimerRunning()
7309 return clockTimerXID != 0;
7312 int StopClockTimer()
7314 if (clockTimerXID != 0) {
7315 XtRemoveTimeOut(clockTimerXID);
7324 ClockTimerCallback(arg, id)
7333 StartClockTimer(millisec)
7337 XtAppAddTimeOut(appContext, millisec,
7338 (XtTimerCallbackProc) ClockTimerCallback,
7343 DisplayTimerLabel(w, color, timer, highlight)
7352 /* check for low time warning */
7353 Pixel foregroundOrWarningColor = timerForegroundPixel;
7356 appData.lowTimeWarning &&
7357 (timer / 1000) < appData.icsAlarmTime)
7358 foregroundOrWarningColor = lowTimeWarningColor;
7360 if (appData.clockMode) {
7361 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7362 XtSetArg(args[0], XtNlabel, buf);
7364 snprintf(buf, MSG_SIZ, "%s ", color);
7365 XtSetArg(args[0], XtNlabel, buf);
7370 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7371 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7373 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7374 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7377 XtSetValues(w, args, 3);
7381 DisplayWhiteClock(timeRemaining, highlight)
7387 if(appData.noGUI) return;
7388 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7389 if (highlight && iconPixmap == bIconPixmap) {
7390 iconPixmap = wIconPixmap;
7391 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7392 XtSetValues(shellWidget, args, 1);
7397 DisplayBlackClock(timeRemaining, highlight)
7403 if(appData.noGUI) return;
7404 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7405 if (highlight && iconPixmap == wIconPixmap) {
7406 iconPixmap = bIconPixmap;
7407 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7408 XtSetValues(shellWidget, args, 1);
7426 int StartChildProcess(cmdLine, dir, pr)
7433 int to_prog[2], from_prog[2];
7437 if (appData.debugMode) {
7438 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7441 /* We do NOT feed the cmdLine to the shell; we just
7442 parse it into blank-separated arguments in the
7443 most simple-minded way possible.
7446 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7449 while(*p == ' ') p++;
7451 if(*p == '"' || *p == '\'')
7452 p = strchr(++argv[i-1], *p);
7453 else p = strchr(p, ' ');
7454 if (p == NULL) break;
7459 SetUpChildIO(to_prog, from_prog);
7461 if ((pid = fork()) == 0) {
7463 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7464 close(to_prog[1]); // first close the unused pipe ends
7465 close(from_prog[0]);
7466 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7467 dup2(from_prog[1], 1);
7468 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7469 close(from_prog[1]); // and closing again loses one of the pipes!
7470 if(fileno(stderr) >= 2) // better safe than sorry...
7471 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7473 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7478 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7480 execvp(argv[0], argv);
7482 /* If we get here, exec failed */
7487 /* Parent process */
7489 close(from_prog[1]);
7491 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7494 cp->fdFrom = from_prog[0];
7495 cp->fdTo = to_prog[1];
7500 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7501 static RETSIGTYPE AlarmCallBack(int n)
7507 DestroyChildProcess(pr, signalType)
7511 ChildProc *cp = (ChildProc *) pr;
7513 if (cp->kind != CPReal) return;
7515 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7516 signal(SIGALRM, AlarmCallBack);
7518 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7519 kill(cp->pid, SIGKILL); // kill it forcefully
7520 wait((int *) 0); // and wait again
7524 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7526 /* Process is exiting either because of the kill or because of
7527 a quit command sent by the backend; either way, wait for it to die.
7536 InterruptChildProcess(pr)
7539 ChildProc *cp = (ChildProc *) pr;
7541 if (cp->kind != CPReal) return;
7542 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7545 int OpenTelnet(host, port, pr)
7550 char cmdLine[MSG_SIZ];
7552 if (port[0] == NULLCHAR) {
7553 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7555 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7557 return StartChildProcess(cmdLine, "", pr);
7560 int OpenTCP(host, port, pr)
7566 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7567 #else /* !OMIT_SOCKETS */
7569 struct sockaddr_in sa;
7571 unsigned short uport;
7574 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7578 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7579 sa.sin_family = AF_INET;
7580 sa.sin_addr.s_addr = INADDR_ANY;
7581 uport = (unsigned short) 0;
7582 sa.sin_port = htons(uport);
7583 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7587 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7588 if (!(hp = gethostbyname(host))) {
7590 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7591 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7592 hp->h_addrtype = AF_INET;
7594 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7595 hp->h_addr_list[0] = (char *) malloc(4);
7596 hp->h_addr_list[0][0] = b0;
7597 hp->h_addr_list[0][1] = b1;
7598 hp->h_addr_list[0][2] = b2;
7599 hp->h_addr_list[0][3] = b3;
7604 sa.sin_family = hp->h_addrtype;
7605 uport = (unsigned short) atoi(port);
7606 sa.sin_port = htons(uport);
7607 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7609 if (connect(s, (struct sockaddr *) &sa,
7610 sizeof(struct sockaddr_in)) < 0) {
7614 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7621 #endif /* !OMIT_SOCKETS */
7626 int OpenCommPort(name, pr)
7633 fd = open(name, 2, 0);
7634 if (fd < 0) return errno;
7636 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7646 int OpenLoopback(pr)
7652 SetUpChildIO(to, from);
7654 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7657 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7664 int OpenRcmd(host, user, cmd, pr)
7665 char *host, *user, *cmd;
7668 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7672 #define INPUT_SOURCE_BUF_SIZE 8192
7681 char buf[INPUT_SOURCE_BUF_SIZE];
7686 DoInputCallback(closure, source, xid)
7691 InputSource *is = (InputSource *) closure;
7696 if (is->lineByLine) {
7697 count = read(is->fd, is->unused,
7698 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7700 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7703 is->unused += count;
7705 while (p < is->unused) {
7706 q = memchr(p, '\n', is->unused - p);
7707 if (q == NULL) break;
7709 (is->func)(is, is->closure, p, q - p, 0);
7713 while (p < is->unused) {
7718 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7723 (is->func)(is, is->closure, is->buf, count, error);
7727 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7734 ChildProc *cp = (ChildProc *) pr;
7736 is = (InputSource *) calloc(1, sizeof(InputSource));
7737 is->lineByLine = lineByLine;
7741 is->fd = fileno(stdin);
7743 is->kind = cp->kind;
7744 is->fd = cp->fdFrom;
7747 is->unused = is->buf;
7750 is->xid = XtAppAddInput(appContext, is->fd,
7751 (XtPointer) (XtInputReadMask),
7752 (XtInputCallbackProc) DoInputCallback,
7754 is->closure = closure;
7755 return (InputSourceRef) is;
7759 RemoveInputSource(isr)
7762 InputSource *is = (InputSource *) isr;
7764 if (is->xid == 0) return;
7765 XtRemoveInput(is->xid);
7769 int OutputToProcess(pr, message, count, outError)
7775 static int line = 0;
7776 ChildProc *cp = (ChildProc *) pr;
7781 if (appData.noJoin || !appData.useInternalWrap)
7782 outCount = fwrite(message, 1, count, stdout);
7785 int width = get_term_width();
7786 int len = wrap(NULL, message, count, width, &line);
7787 char *msg = malloc(len);
7791 outCount = fwrite(message, 1, count, stdout);
7794 dbgchk = wrap(msg, message, count, width, &line);
7795 if (dbgchk != len && appData.debugMode)
7796 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7797 outCount = fwrite(msg, 1, dbgchk, stdout);
7803 outCount = write(cp->fdTo, message, count);
7813 /* Output message to process, with "ms" milliseconds of delay
7814 between each character. This is needed when sending the logon
7815 script to ICC, which for some reason doesn't like the
7816 instantaneous send. */
7817 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7824 ChildProc *cp = (ChildProc *) pr;
7829 r = write(cp->fdTo, message++, 1);
7842 /**** Animation code by Hugh Fisher, DCS, ANU.
7844 Known problem: if a window overlapping the board is
7845 moved away while a piece is being animated underneath,
7846 the newly exposed area won't be updated properly.
7847 I can live with this.
7849 Known problem: if you look carefully at the animation
7850 of pieces in mono mode, they are being drawn as solid
7851 shapes without interior detail while moving. Fixing
7852 this would be a major complication for minimal return.
7855 /* Masks for XPM pieces. Black and white pieces can have
7856 different shapes, but in the interest of retaining my
7857 sanity pieces must have the same outline on both light
7858 and dark squares, and all pieces must use the same
7859 background square colors/images. */
7861 static int xpmDone = 0;
7864 CreateAnimMasks (pieceDepth)
7871 unsigned long plane;
7874 /* Need a bitmap just to get a GC with right depth */
7875 buf = XCreatePixmap(xDisplay, xBoardWindow,
7877 values.foreground = 1;
7878 values.background = 0;
7879 /* Don't use XtGetGC, not read only */
7880 maskGC = XCreateGC(xDisplay, buf,
7881 GCForeground | GCBackground, &values);
7882 XFreePixmap(xDisplay, buf);
7884 buf = XCreatePixmap(xDisplay, xBoardWindow,
7885 squareSize, squareSize, pieceDepth);
7886 values.foreground = XBlackPixel(xDisplay, xScreen);
7887 values.background = XWhitePixel(xDisplay, xScreen);
7888 bufGC = XCreateGC(xDisplay, buf,
7889 GCForeground | GCBackground, &values);
7891 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7892 /* Begin with empty mask */
7893 if(!xpmDone) // [HGM] pieces: keep using existing
7894 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7895 squareSize, squareSize, 1);
7896 XSetFunction(xDisplay, maskGC, GXclear);
7897 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7898 0, 0, squareSize, squareSize);
7900 /* Take a copy of the piece */
7905 XSetFunction(xDisplay, bufGC, GXcopy);
7906 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7908 0, 0, squareSize, squareSize, 0, 0);
7910 /* XOR the background (light) over the piece */
7911 XSetFunction(xDisplay, bufGC, GXxor);
7913 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7914 0, 0, squareSize, squareSize, 0, 0);
7916 XSetForeground(xDisplay, bufGC, lightSquareColor);
7917 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7920 /* We now have an inverted piece image with the background
7921 erased. Construct mask by just selecting all the non-zero
7922 pixels - no need to reconstruct the original image. */
7923 XSetFunction(xDisplay, maskGC, GXor);
7925 /* Might be quicker to download an XImage and create bitmap
7926 data from it rather than this N copies per piece, but it
7927 only takes a fraction of a second and there is a much
7928 longer delay for loading the pieces. */
7929 for (n = 0; n < pieceDepth; n ++) {
7930 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7931 0, 0, squareSize, squareSize,
7937 XFreePixmap(xDisplay, buf);
7938 XFreeGC(xDisplay, bufGC);
7939 XFreeGC(xDisplay, maskGC);
7943 InitAnimState (anim, info)
7945 XWindowAttributes * info;
7950 /* Each buffer is square size, same depth as window */
7951 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
7952 squareSize, squareSize, info->depth);
7953 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
7954 squareSize, squareSize, info->depth);
7956 /* Create a plain GC for blitting */
7957 mask = GCForeground | GCBackground | GCFunction |
7958 GCPlaneMask | GCGraphicsExposures;
7959 values.foreground = XBlackPixel(xDisplay, xScreen);
7960 values.background = XWhitePixel(xDisplay, xScreen);
7961 values.function = GXcopy;
7962 values.plane_mask = AllPlanes;
7963 values.graphics_exposures = False;
7964 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
7966 /* Piece will be copied from an existing context at
7967 the start of each new animation/drag. */
7968 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
7970 /* Outline will be a read-only copy of an existing */
7971 anim->outlineGC = None;
7977 XWindowAttributes info;
7979 if (xpmDone && gameInfo.variant == oldVariant) return;
7980 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
7981 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
7983 InitAnimState(&game, &info);
7984 InitAnimState(&player, &info);
7986 /* For XPM pieces, we need bitmaps to use as masks. */
7988 CreateAnimMasks(info.depth);
7994 static Boolean frameWaiting;
7996 static RETSIGTYPE FrameAlarm (sig)
7999 frameWaiting = False;
8000 /* In case System-V style signals. Needed?? */
8001 signal(SIGALRM, FrameAlarm);
8008 struct itimerval delay;
8010 XSync(xDisplay, False);
8013 frameWaiting = True;
8014 signal(SIGALRM, FrameAlarm);
8015 delay.it_interval.tv_sec =
8016 delay.it_value.tv_sec = time / 1000;
8017 delay.it_interval.tv_usec =
8018 delay.it_value.tv_usec = (time % 1000) * 1000;
8019 setitimer(ITIMER_REAL, &delay, NULL);
8020 while (frameWaiting) pause();
8021 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8022 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8023 setitimer(ITIMER_REAL, &delay, NULL);
8033 XSync(xDisplay, False);
8035 usleep(time * 1000);
8040 /* Convert board position to corner of screen rect and color */
8043 ScreenSquare(column, row, pt, color)
8044 int column; int row; XPoint * pt; int * color;
8047 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8048 pt->y = lineGap + row * (squareSize + lineGap);
8050 pt->x = lineGap + column * (squareSize + lineGap);
8051 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8053 *color = SquareColor(row, column);
8056 /* Convert window coords to square */
8059 BoardSquare(x, y, column, row)
8060 int x; int y; int * column; int * row;
8062 *column = EventToSquare(x, BOARD_WIDTH);
8063 if (flipView && *column >= 0)
8064 *column = BOARD_WIDTH - 1 - *column;
8065 *row = EventToSquare(y, BOARD_HEIGHT);
8066 if (!flipView && *row >= 0)
8067 *row = BOARD_HEIGHT - 1 - *row;
8072 #undef Max /* just in case */
8074 #define Max(a, b) ((a) > (b) ? (a) : (b))
8075 #define Min(a, b) ((a) < (b) ? (a) : (b))
8078 SetRect(rect, x, y, width, height)
8079 XRectangle * rect; int x; int y; int width; int height;
8083 rect->width = width;
8084 rect->height = height;
8087 /* Test if two frames overlap. If they do, return
8088 intersection rect within old and location of
8089 that rect within new. */
8092 Intersect(old, new, size, area, pt)
8093 XPoint * old; XPoint * new;
8094 int size; XRectangle * area; XPoint * pt;
8096 if (old->x > new->x + size || new->x > old->x + size ||
8097 old->y > new->y + size || new->y > old->y + size) {
8100 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8101 size - abs(old->x - new->x), size - abs(old->y - new->y));
8102 pt->x = Max(old->x - new->x, 0);
8103 pt->y = Max(old->y - new->y, 0);
8108 /* For two overlapping frames, return the rect(s)
8109 in the old that do not intersect with the new. */
8112 CalcUpdateRects(old, new, size, update, nUpdates)
8113 XPoint * old; XPoint * new; int size;
8114 XRectangle update[]; int * nUpdates;
8118 /* If old = new (shouldn't happen) then nothing to draw */
8119 if (old->x == new->x && old->y == new->y) {
8123 /* Work out what bits overlap. Since we know the rects
8124 are the same size we don't need a full intersect calc. */
8126 /* Top or bottom edge? */
8127 if (new->y > old->y) {
8128 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8130 } else if (old->y > new->y) {
8131 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8132 size, old->y - new->y);
8135 /* Left or right edge - don't overlap any update calculated above. */
8136 if (new->x > old->x) {
8137 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8138 new->x - old->x, size - abs(new->y - old->y));
8140 } else if (old->x > new->x) {
8141 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8142 old->x - new->x, size - abs(new->y - old->y));
8149 /* Generate a series of frame coords from start->mid->finish.
8150 The movement rate doubles until the half way point is
8151 reached, then halves back down to the final destination,
8152 which gives a nice slow in/out effect. The algorithmn
8153 may seem to generate too many intermediates for short
8154 moves, but remember that the purpose is to attract the
8155 viewers attention to the piece about to be moved and
8156 then to where it ends up. Too few frames would be less
8160 Tween(start, mid, finish, factor, frames, nFrames)
8161 XPoint * start; XPoint * mid;
8162 XPoint * finish; int factor;
8163 XPoint frames[]; int * nFrames;
8165 int fraction, n, count;
8169 /* Slow in, stepping 1/16th, then 1/8th, ... */
8171 for (n = 0; n < factor; n++)
8173 for (n = 0; n < factor; n++) {
8174 frames[count].x = start->x + (mid->x - start->x) / fraction;
8175 frames[count].y = start->y + (mid->y - start->y) / fraction;
8177 fraction = fraction / 2;
8181 frames[count] = *mid;
8184 /* Slow out, stepping 1/2, then 1/4, ... */
8186 for (n = 0; n < factor; n++) {
8187 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8188 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8190 fraction = fraction * 2;
8195 /* Draw a piece on the screen without disturbing what's there */
8198 SelectGCMask(piece, clip, outline, mask)
8199 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8203 /* Bitmap for piece being moved. */
8204 if (appData.monoMode) {
8205 *mask = *pieceToSolid(piece);
8206 } else if (useImages) {
8208 *mask = xpmMask[piece];
8210 *mask = ximMaskPm[piece];
8213 *mask = *pieceToSolid(piece);
8216 /* GC for piece being moved. Square color doesn't matter, but
8217 since it gets modified we make a copy of the original. */
8219 if (appData.monoMode)
8224 if (appData.monoMode)
8229 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8231 /* Outline only used in mono mode and is not modified */
8233 *outline = bwPieceGC;
8235 *outline = wbPieceGC;
8239 OverlayPiece(piece, clip, outline, dest)
8240 ChessSquare piece; GC clip; GC outline; Drawable dest;
8245 /* Draw solid rectangle which will be clipped to shape of piece */
8246 XFillRectangle(xDisplay, dest, clip,
8247 0, 0, squareSize, squareSize);
8248 if (appData.monoMode)
8249 /* Also draw outline in contrasting color for black
8250 on black / white on white cases */
8251 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8252 0, 0, squareSize, squareSize, 0, 0, 1);
8254 /* Copy the piece */
8259 if(appData.upsideDown && flipView) kind ^= 2;
8260 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8262 0, 0, squareSize, squareSize,
8267 /* Animate the movement of a single piece */
8270 BeginAnimation(anim, piece, startColor, start)
8278 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8279 /* The old buffer is initialised with the start square (empty) */
8280 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8281 anim->prevFrame = *start;
8283 /* The piece will be drawn using its own bitmap as a matte */
8284 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8285 XSetClipMask(xDisplay, anim->pieceGC, mask);
8289 AnimationFrame(anim, frame, piece)
8294 XRectangle updates[4];
8299 /* Save what we are about to draw into the new buffer */
8300 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8301 frame->x, frame->y, squareSize, squareSize,
8304 /* Erase bits of the previous frame */
8305 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8306 /* Where the new frame overlapped the previous,
8307 the contents in newBuf are wrong. */
8308 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8309 overlap.x, overlap.y,
8310 overlap.width, overlap.height,
8312 /* Repaint the areas in the old that don't overlap new */
8313 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8314 for (i = 0; i < count; i++)
8315 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8316 updates[i].x - anim->prevFrame.x,
8317 updates[i].y - anim->prevFrame.y,
8318 updates[i].width, updates[i].height,
8319 updates[i].x, updates[i].y);
8321 /* Easy when no overlap */
8322 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8323 0, 0, squareSize, squareSize,
8324 anim->prevFrame.x, anim->prevFrame.y);
8327 /* Save this frame for next time round */
8328 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8329 0, 0, squareSize, squareSize,
8331 anim->prevFrame = *frame;
8333 /* Draw piece over original screen contents, not current,
8334 and copy entire rect. Wipes out overlapping piece images. */
8335 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8336 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8337 0, 0, squareSize, squareSize,
8338 frame->x, frame->y);
8342 EndAnimation (anim, finish)
8346 XRectangle updates[4];
8351 /* The main code will redraw the final square, so we
8352 only need to erase the bits that don't overlap. */
8353 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8354 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8355 for (i = 0; i < count; i++)
8356 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8357 updates[i].x - anim->prevFrame.x,
8358 updates[i].y - anim->prevFrame.y,
8359 updates[i].width, updates[i].height,
8360 updates[i].x, updates[i].y);
8362 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8363 0, 0, squareSize, squareSize,
8364 anim->prevFrame.x, anim->prevFrame.y);
8369 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8371 ChessSquare piece; int startColor;
8372 XPoint * start; XPoint * finish;
8373 XPoint frames[]; int nFrames;
8377 BeginAnimation(anim, piece, startColor, start);
8378 for (n = 0; n < nFrames; n++) {
8379 AnimationFrame(anim, &(frames[n]), piece);
8380 FrameDelay(appData.animSpeed);
8382 EndAnimation(anim, finish);
8386 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8389 ChessSquare piece = board[fromY][toY];
8390 board[fromY][toY] = EmptySquare;
8391 DrawPosition(FALSE, board);
8393 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8394 y = lineGap + toY * (squareSize + lineGap);
8396 x = lineGap + toX * (squareSize + lineGap);
8397 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8399 for(i=1; i<4*kFactor; i++) {
8400 int r = squareSize * 9 * i/(20*kFactor - 5);
8401 XFillArc(xDisplay, xBoardWindow, highlineGC,
8402 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8403 FrameDelay(appData.animSpeed);
8405 board[fromY][toY] = piece;
8408 /* Main control logic for deciding what to animate and how */
8411 AnimateMove(board, fromX, fromY, toX, toY)
8420 XPoint start, finish, mid;
8421 XPoint frames[kFactor * 2 + 1];
8422 int nFrames, startColor, endColor;
8424 /* Are we animating? */
8425 if (!appData.animate || appData.blindfold)
8428 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8429 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8430 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8432 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8433 piece = board[fromY][fromX];
8434 if (piece >= EmptySquare) return;
8439 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8442 if (appData.debugMode) {
8443 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8444 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8445 piece, fromX, fromY, toX, toY); }
8447 ScreenSquare(fromX, fromY, &start, &startColor);
8448 ScreenSquare(toX, toY, &finish, &endColor);
8451 /* Knight: make straight movement then diagonal */
8452 if (abs(toY - fromY) < abs(toX - fromX)) {
8453 mid.x = start.x + (finish.x - start.x) / 2;
8457 mid.y = start.y + (finish.y - start.y) / 2;
8460 mid.x = start.x + (finish.x - start.x) / 2;
8461 mid.y = start.y + (finish.y - start.y) / 2;
8464 /* Don't use as many frames for very short moves */
8465 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8466 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8468 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8469 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8470 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8472 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8473 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8476 /* Be sure end square is redrawn */
8477 damage[0][toY][toX] = True;
8481 DragPieceBegin(x, y)
8484 int boardX, boardY, color;
8487 /* Are we animating? */
8488 if (!appData.animateDragging || appData.blindfold)
8491 /* Figure out which square we start in and the
8492 mouse position relative to top left corner. */
8493 BoardSquare(x, y, &boardX, &boardY);
8494 player.startBoardX = boardX;
8495 player.startBoardY = boardY;
8496 ScreenSquare(boardX, boardY, &corner, &color);
8497 player.startSquare = corner;
8498 player.startColor = color;
8499 /* As soon as we start dragging, the piece will jump slightly to
8500 be centered over the mouse pointer. */
8501 player.mouseDelta.x = squareSize/2;
8502 player.mouseDelta.y = squareSize/2;
8503 /* Initialise animation */
8504 player.dragPiece = PieceForSquare(boardX, boardY);
8506 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8507 player.dragActive = True;
8508 BeginAnimation(&player, player.dragPiece, color, &corner);
8509 /* Mark this square as needing to be redrawn. Note that
8510 we don't remove the piece though, since logically (ie
8511 as seen by opponent) the move hasn't been made yet. */
8512 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8513 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8514 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8515 corner.x, corner.y, squareSize, squareSize,
8516 0, 0); // [HGM] zh: unstack in stead of grab
8517 if(gatingPiece != EmptySquare) {
8518 /* Kludge alert: When gating we want the introduced
8519 piece to appear on the from square. To generate an
8520 image of it, we draw it on the board, copy the image,
8521 and draw the original piece again. */
8522 ChessSquare piece = boards[currentMove][boardY][boardX];
8523 DrawSquare(boardY, boardX, gatingPiece, 0);
8524 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8525 corner.x, corner.y, squareSize, squareSize, 0, 0);
8526 DrawSquare(boardY, boardX, piece, 0);
8528 damage[0][boardY][boardX] = True;
8530 player.dragActive = False;
8540 /* Are we animating? */
8541 if (!appData.animateDragging || appData.blindfold)
8545 if (! player.dragActive)
8547 /* Move piece, maintaining same relative position
8548 of mouse within square */
8549 corner.x = x - player.mouseDelta.x;
8550 corner.y = y - player.mouseDelta.y;
8551 AnimationFrame(&player, &corner, player.dragPiece);
8553 if (appData.highlightDragging) {
8555 BoardSquare(x, y, &boardX, &boardY);
8556 SetHighlights(fromX, fromY, boardX, boardY);
8565 int boardX, boardY, color;
8568 /* Are we animating? */
8569 if (!appData.animateDragging || appData.blindfold)
8573 if (! player.dragActive)
8575 /* Last frame in sequence is square piece is
8576 placed on, which may not match mouse exactly. */
8577 BoardSquare(x, y, &boardX, &boardY);
8578 ScreenSquare(boardX, boardY, &corner, &color);
8579 EndAnimation(&player, &corner);
8581 /* Be sure end square is redrawn */
8582 damage[0][boardY][boardX] = True;
8584 /* This prevents weird things happening with fast successive
8585 clicks which on my Sun at least can cause motion events
8586 without corresponding press/release. */
8587 player.dragActive = False;
8590 /* Handle expose event while piece being dragged */
8595 if (!player.dragActive || appData.blindfold)
8598 /* What we're doing: logically, the move hasn't been made yet,
8599 so the piece is still in it's original square. But visually
8600 it's being dragged around the board. So we erase the square
8601 that the piece is on and draw it at the last known drag point. */
8602 BlankSquare(player.startSquare.x, player.startSquare.y,
8603 player.startColor, EmptySquare, xBoardWindow, 1);
8604 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8605 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8608 #include <sys/ioctl.h>
8609 int get_term_width()
8611 int fd, default_width;
8614 default_width = 79; // this is FICS default anyway...
8616 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8618 if (!ioctl(fd, TIOCGSIZE, &win))
8619 default_width = win.ts_cols;
8620 #elif defined(TIOCGWINSZ)
8622 if (!ioctl(fd, TIOCGWINSZ, &win))
8623 default_width = win.ws_col;
8625 return default_width;
8631 static int old_width = 0;
8632 int new_width = get_term_width();
8634 if (old_width != new_width)
8635 ics_printf("set width %d\n", new_width);
8636 old_width = new_width;
8639 void NotifyFrontendLogin()
8644 /* [AS] Arrow highlighting support */
8646 static double A_WIDTH = 5; /* Width of arrow body */
8648 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8649 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8651 static double Sqr( double x )
8656 static int Round( double x )
8658 return (int) (x + 0.5);
8661 void SquareToPos(int rank, int file, int *x, int *y)
8664 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8665 *y = lineGap + rank * (squareSize + lineGap);
8667 *x = lineGap + file * (squareSize + lineGap);
8668 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8672 /* Draw an arrow between two points using current settings */
8673 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8676 double dx, dy, j, k, x, y;
8679 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8681 arrow[0].x = s_x + A_WIDTH + 0.5;
8684 arrow[1].x = s_x + A_WIDTH + 0.5;
8685 arrow[1].y = d_y - h;
8687 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8688 arrow[2].y = d_y - h;
8693 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8694 arrow[5].y = d_y - h;
8696 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8697 arrow[4].y = d_y - h;
8699 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8702 else if( d_y == s_y ) {
8703 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8706 arrow[0].y = s_y + A_WIDTH + 0.5;
8708 arrow[1].x = d_x - w;
8709 arrow[1].y = s_y + A_WIDTH + 0.5;
8711 arrow[2].x = d_x - w;
8712 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8717 arrow[5].x = d_x - w;
8718 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8720 arrow[4].x = d_x - w;
8721 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8724 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8727 /* [AS] Needed a lot of paper for this! :-) */
8728 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8729 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8731 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8733 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8738 arrow[0].x = Round(x - j);
8739 arrow[0].y = Round(y + j*dx);
8741 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8742 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8745 x = (double) d_x - k;
8746 y = (double) d_y - k*dy;
8749 x = (double) d_x + k;
8750 y = (double) d_y + k*dy;
8753 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8755 arrow[6].x = Round(x - j);
8756 arrow[6].y = Round(y + j*dx);
8758 arrow[2].x = Round(arrow[6].x + 2*j);
8759 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8761 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8762 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8767 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8768 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8771 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8772 // Polygon( hdc, arrow, 7 );
8775 /* [AS] Draw an arrow between two squares */
8776 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
8778 int s_x, s_y, d_x, d_y, hor, vert, i;
8780 if( s_col == d_col && s_row == d_row ) {
8784 /* Get source and destination points */
8785 SquareToPos( s_row, s_col, &s_x, &s_y);
8786 SquareToPos( d_row, d_col, &d_x, &d_y);
8789 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8791 else if( d_y < s_y ) {
8792 d_y += squareSize / 2 + squareSize / 4;
8795 d_y += squareSize / 2;
8799 d_x += squareSize / 2 - squareSize / 4;
8801 else if( d_x < s_x ) {
8802 d_x += squareSize / 2 + squareSize / 4;
8805 d_x += squareSize / 2;
8808 s_x += squareSize / 2;
8809 s_y += squareSize / 2;
8812 A_WIDTH = squareSize / 14.; //[HGM] make float
8814 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8816 hor = 64*s_col + 32; vert = 64*s_row + 32;
8817 for(i=0; i<= 64; i++) {
8818 damage[0][vert+6>>6][hor+6>>6] = True;
8819 damage[0][vert-6>>6][hor+6>>6] = True;
8820 damage[0][vert+6>>6][hor-6>>6] = True;
8821 damage[0][vert-6>>6][hor-6>>6] = True;
8822 hor += d_col - s_col; vert += d_row - s_row;
8826 Boolean IsDrawArrowEnabled()
8828 return appData.highlightMoveWithArrow && squareSize >= 32;
8831 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
8833 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
8834 DrawArrowBetweenSquares(fromX, fromY, toX, toY);