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 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>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
194 #include "backendz.h"
198 #include "xgamelist.h"
199 #include "xhistory.h"
200 #include "xedittags.h"
203 // must be moved to xengineoutput.h
205 void EngineOutputProc P((Widget w, XEvent *event,
206 String *prms, Cardinal *nprms));
207 void EvalGraphProc P((Widget w, XEvent *event,
208 String *prms, Cardinal *nprms));
215 #define usleep(t) _sleep2(((t)+500)/1000)
219 # define _(s) gettext (s)
220 # define N_(s) gettext_noop (s)
236 int main P((int argc, char **argv));
237 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
238 char *init_path, char *mode, int (*show_entry)(), char **name_return));
239 RETSIGTYPE CmailSigHandler P((int sig));
240 RETSIGTYPE IntSigHandler P((int sig));
241 RETSIGTYPE TermSizeSigHandler P((int sig));
242 void CreateGCs P((void));
243 void CreateXIMPieces P((void));
244 void CreateXPMPieces P((void));
245 void CreateXPMBoard P((char *s, int n));
246 void CreatePieces P((void));
247 void CreatePieceMenus P((void));
248 Widget CreateMenuBar P((Menu *mb));
249 Widget CreateButtonBar P ((MenuItem *mi));
250 char *FindFont P((char *pattern, int targetPxlSize));
251 void PieceMenuPopup P((Widget w, XEvent *event,
252 String *params, Cardinal *num_params));
253 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
254 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
255 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
256 u_int wreq, u_int hreq));
257 void CreateGrid P((void));
258 int EventToSquare P((int x, int limit));
259 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
260 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
261 void HandleUserMove P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void AnimateUserMove P((Widget w, XEvent * event,
264 String * params, Cardinal * nParams));
265 void HandlePV P((Widget w, XEvent * event,
266 String * params, Cardinal * nParams));
267 void SelectPV P((Widget w, XEvent * event,
268 String * params, Cardinal * nParams));
269 void StopPV P((Widget w, XEvent * event,
270 String * params, Cardinal * nParams));
271 void WhiteClock P((Widget w, XEvent *event,
272 String *prms, Cardinal *nprms));
273 void BlackClock P((Widget w, XEvent *event,
274 String *prms, Cardinal *nprms));
275 void DrawPositionProc P((Widget w, XEvent *event,
276 String *prms, Cardinal *nprms));
277 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
279 void CommentClick P((Widget w, XEvent * event,
280 String * params, Cardinal * nParams));
281 void CommentPopUp P((char *title, char *label));
282 void CommentPopDown P((void));
283 void CommentCallback P((Widget w, XtPointer client_data,
284 XtPointer call_data));
285 void ICSInputBoxPopUp P((void));
286 void ICSInputBoxPopDown P((void));
287 void FileNamePopUp P((char *label, char *def,
288 FileProc proc, char *openMode));
289 void FileNamePopDown P((void));
290 void FileNameCallback P((Widget w, XtPointer client_data,
291 XtPointer call_data));
292 void FileNameAction P((Widget w, XEvent *event,
293 String *prms, Cardinal *nprms));
294 void AskQuestionReplyAction P((Widget w, XEvent *event,
295 String *prms, Cardinal *nprms));
296 void AskQuestionProc P((Widget w, XEvent *event,
297 String *prms, Cardinal *nprms));
298 void AskQuestionPopDown P((void));
299 void PromotionPopDown P((void));
300 void PromotionCallback P((Widget w, XtPointer client_data,
301 XtPointer call_data));
302 void EditCommentPopDown P((void));
303 void EditCommentCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
306 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
307 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
308 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
310 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
312 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
314 void LoadPositionProc P((Widget w, XEvent *event,
315 String *prms, Cardinal *nprms));
316 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
318 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
320 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
322 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
324 void PastePositionProc P((Widget w, XEvent *event, String *prms,
326 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
329 void SavePositionProc P((Widget w, XEvent *event,
330 String *prms, Cardinal *nprms));
331 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
334 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
338 void MachineWhiteProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AnalyzeModeProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AnalyzeFileProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
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 AutocommProc P((Widget w, XEvent *event, String *prms,
394 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void AutobsProc P((Widget w, XEvent *event, String *prms,
398 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
403 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
406 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
408 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
410 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
412 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
414 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
416 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
418 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
420 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
422 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
426 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
428 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
430 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
432 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void DisplayMove P((int moveNumber));
444 void DisplayTitle P((char *title));
445 void ICSInitScript P((void));
446 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
447 void ErrorPopUp P((char *title, char *text, int modal));
448 void ErrorPopDown P((void));
449 static char *ExpandPathName P((char *path));
450 static void CreateAnimVars P((void));
451 static void DragPieceMove P((int x, int y));
452 static void DrawDragPiece P((void));
453 char *ModeToWidgetName P((GameMode mode));
454 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void GameListOptionsPopDown P(());
463 void ShufflePopDown P(());
464 void EnginePopDown P(());
465 void UciPopDown P(());
466 void TimeControlPopDown P(());
467 void NewVariantPopDown P(());
468 void SettingsPopDown P(());
469 void update_ics_width P(());
470 int get_term_width P(());
471 int CopyMemoProc P(());
473 * XBoard depends on Xt R4 or higher
475 int xtVersion = XtSpecificationRelease;
480 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
481 jailSquareColor, highlightSquareColor, premoveHighlightColor;
482 Pixel lowTimeWarningColor;
483 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
484 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
485 wjPieceGC, bjPieceGC, prelineGC, countGC;
486 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
487 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
488 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
489 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
490 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
491 ICSInputShell, fileNameShell, askQuestionShell;
492 Widget historyShell, evalGraphShell, gameListShell;
493 int hOffset; // [HGM] dual
494 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
495 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
496 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
497 Font clockFontID, coordFontID, countFontID;
498 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
499 XtAppContext appContext;
501 char *oldICSInteractionTitle;
505 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
507 Position commentX = -1, commentY = -1;
508 Dimension commentW, commentH;
509 typedef unsigned int BoardSize;
511 Boolean chessProgram;
513 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
514 int squareSize, smallLayout = 0, tinyLayout = 0,
515 marginW, marginH, // [HGM] for run-time resizing
516 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
517 ICSInputBoxUp = False, askQuestionUp = False,
518 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
519 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
520 Pixel timerForegroundPixel, timerBackgroundPixel;
521 Pixel buttonForegroundPixel, buttonBackgroundPixel;
522 char *chessDir, *programName, *programVersion,
523 *gameCopyFilename, *gamePasteFilename;
524 Boolean alwaysOnTop = False;
525 Boolean saveSettingsOnExit;
526 char *settingsFileName;
527 char *icsTextMenuString;
529 char *firstChessProgramNames;
530 char *secondChessProgramNames;
532 WindowPlacement wpMain;
533 WindowPlacement wpConsole;
534 WindowPlacement wpComment;
535 WindowPlacement wpMoveHistory;
536 WindowPlacement wpEvalGraph;
537 WindowPlacement wpEngineOutput;
538 WindowPlacement wpGameList;
539 WindowPlacement wpTags;
543 Pixmap pieceBitmap[2][(int)BlackPawn];
544 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
545 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
546 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
547 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
548 Pixmap xpmBoardBitmap[2];
549 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
550 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
551 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
552 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
553 XImage *ximLightSquare, *ximDarkSquare;
556 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
557 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
559 #define White(piece) ((int)(piece) < (int)BlackPawn)
561 /* Variables for doing smooth animation. This whole thing
562 would be much easier if the board was double-buffered,
563 but that would require a fairly major rewrite. */
568 GC blitGC, pieceGC, outlineGC;
569 XPoint startSquare, prevFrame, mouseDelta;
573 int startBoardX, startBoardY;
576 /* There can be two pieces being animated at once: a player
577 can begin dragging a piece before the remote opponent has moved. */
579 static AnimState game, player;
581 /* Bitmaps for use as masks when drawing XPM pieces.
582 Need one for each black and white piece. */
583 static Pixmap xpmMask[BlackKing + 1];
585 /* This magic number is the number of intermediate frames used
586 in each half of the animation. For short moves it's reduced
587 by 1. The total number of frames will be factor * 2 + 1. */
590 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
592 MenuItem fileMenu[] = {
593 {"New Game", ResetProc},
594 {"New Shuffle Game ...", ShuffleMenuProc},
595 {"New Variant ...", NewVariantProc}, // [HGM] variant: not functional yet
596 {"----", NothingProc},
597 {"Load Game", LoadGameProc},
598 {"Load Position", LoadPositionProc},
599 // {"Load Next Game", LoadNextGameProc},
600 // {"Load Previous Game", LoadPrevGameProc},
601 // {"Reload Same Game", ReloadGameProc},
602 {"----", NothingProc},
603 // {"Load Next Position", LoadNextPositionProc},
604 // {"Load Previous Position", LoadPrevPositionProc},
605 // {"Reload Same Position", ReloadPositionProc},
606 {"Save Game", SaveGameProc},
607 {"Save Position", SavePositionProc},
608 {"----", NothingProc},
609 {"Mail Move", MailMoveProc},
610 {"Reload CMail Message", ReloadCmailMsgProc},
611 {"----", NothingProc},
616 MenuItem editMenu[] = {
617 {"Copy Game", CopyGameProc},
618 {"Copy Position", CopyPositionProc},
619 {"----", NothingProc},
620 {"Paste Game", PasteGameProc},
621 {"Paste Position", PastePositionProc},
622 {"----", NothingProc},
623 {"Edit Game", EditGameProc},
624 {"Edit Position", EditPositionProc},
625 {"----", NothingProc},
626 {"Edit Tags", EditTagsProc},
627 {"Edit Comment", EditCommentProc},
628 {"----", NothingProc},
629 {"Revert", RevertProc},
630 {"Annotate", AnnotateProc},
631 {"Truncate Game", TruncateGameProc},
632 {"----", NothingProc},
633 {"Backward", BackwardProc},
634 {"Forward", ForwardProc},
635 {"Back to Start", ToStartProc},
636 {"Forward to End", ToEndProc},
640 MenuItem viewMenu[] = {
641 {"Flip View", FlipViewProc},
642 {"----", NothingProc},
643 {"Show Engine Output", EngineOutputProc},
644 {"Show Evaluation Graph", EvalGraphProc},
645 {"Show Game List", ShowGameListProc},
646 {"Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
647 {"----", NothingProc},
648 {"Show Tags", EditTagsProc},
649 {"Show Comments", EditCommentProc},
650 {"ICS Input Box", IcsInputBoxProc},
654 MenuItem modeMenu[] = {
655 {"Machine White", MachineWhiteProc},
656 {"Machine Black", MachineBlackProc},
657 {"Two Machines", TwoMachinesProc},
658 {"Analysis Mode", AnalyzeModeProc},
659 {"Analyze File", AnalyzeFileProc },
660 {"Edit Game", EditGameProc},
661 {"Edit Position", EditPositionProc},
662 {"Training", TrainingProc},
663 {"ICS Client", IcsClientProc},
664 {"----", NothingProc},
665 {"Pause", PauseProc},
669 MenuItem actionMenu[] = {
670 {"Accept", AcceptProc},
671 {"Decline", DeclineProc},
672 {"Rematch", RematchProc},
673 {"----", NothingProc},
674 {"Call Flag", CallFlagProc},
676 {"Adjourn", AdjournProc},
677 {"Abort", AbortProc},
678 {"Resign", ResignProc},
679 {"----", NothingProc},
680 {"Stop Observing", StopObservingProc},
681 {"Stop Examining", StopExaminingProc},
682 {"Upload to Examine", UploadProc},
683 {"----", NothingProc},
684 {"Adjudicate to White", AdjuWhiteProc},
685 {"Adjudicate to Black", AdjuBlackProc},
686 {"Adjudicate Draw", AdjuDrawProc},
690 MenuItem engineMenu[] = {
691 {"Engine #1 Settings", FirstSettingsProc},
692 {"Engine #2 Settings", SecondSettingsProc},
693 {"----", NothingProc},
694 {"Move Now", MoveNowProc},
695 {"Retract Move", RetractMoveProc},
699 MenuItem optionsMenu[] = {
700 {"Time Control ...", TimeControlProc},
701 {"Common Engine ...", UciMenuProc},
702 {"Adjudications ...", EngineMenuProc},
703 {"Game List ...", GameListOptionsPopUp},
704 {"----", NothingProc},
705 {"Always Queen", AlwaysQueenProc},
706 {"Animate Dragging", AnimateDraggingProc},
707 {"Animate Moving", AnimateMovingProc},
708 {"Auto Comment", AutocommProc},
709 {"Auto Flag", AutoflagProc},
710 {"Auto Flip View", AutoflipProc},
711 {"Auto Observe", AutobsProc},
712 {"Auto Raise Board", AutoraiseProc},
713 {"Auto Save", AutosaveProc},
714 {"Blindfold", BlindfoldProc},
715 {"Flash Moves", FlashMovesProc},
716 {"Get Move List", GetMoveListProc},
718 {"Highlight Dragging", HighlightDraggingProc},
720 {"Highlight Last Move", HighlightLastMoveProc},
721 {"Move Sound", MoveSoundProc},
722 {"ICS Alarm", IcsAlarmProc},
723 {"Old Save Style", OldSaveStyleProc},
724 {"Periodic Updates", PeriodicUpdatesProc},
725 {"Ponder Next Move", PonderNextMoveProc},
726 {"Popup Exit Message", PopupExitMessageProc},
727 {"Popup Move Errors", PopupMoveErrorsProc},
728 {"Premove", PremoveProc},
729 {"Quiet Play", QuietPlayProc},
730 {"Show Coords", ShowCoordsProc},
731 {"Hide Thinking", HideThinkingProc},
732 {"Test Legality", TestLegalityProc},
733 {"----", NothingProc},
734 {"Save Settings Now", SaveSettingsProc},
735 {"Save Settings on Exit", SaveOnExitProc},
739 MenuItem helpMenu[] = {
740 {"Info XBoard", InfoProc},
741 {"Man XBoard", ManProc},
742 {"----", NothingProc},
745 {"----", NothingProc},
746 {"About XBoard", AboutProc},
755 {"Action", actionMenu},
756 {"Engine", engineMenu},
757 {"Options", optionsMenu},
762 #define PAUSE_BUTTON "P"
763 MenuItem buttonBar[] = {
766 {PAUSE_BUTTON, PauseProc},
772 #define PIECE_MENU_SIZE 18
773 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
774 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
775 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
776 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
777 N_("Empty square"), N_("Clear board") },
778 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
779 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
780 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
781 N_("Empty square"), N_("Clear board") }
783 /* must be in same order as PieceMenuStrings! */
784 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
785 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
786 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
787 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
788 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
789 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
790 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
791 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
792 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
795 #define DROP_MENU_SIZE 6
796 String dropMenuStrings[DROP_MENU_SIZE] = {
797 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
799 /* must be in same order as PieceMenuStrings! */
800 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
801 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
802 WhiteRook, WhiteQueen
810 DropMenuEnables dmEnables[] = {
828 { XtNborderWidth, 0 },
829 { XtNdefaultDistance, 0 },
833 { XtNborderWidth, 0 },
834 { XtNresizable, (XtArgVal) True },
838 { XtNborderWidth, 0 },
844 { XtNjustify, (XtArgVal) XtJustifyRight },
845 { XtNlabel, (XtArgVal) "..." },
846 { XtNresizable, (XtArgVal) True },
847 { XtNresize, (XtArgVal) False }
850 Arg messageArgs[] = {
851 { XtNjustify, (XtArgVal) XtJustifyLeft },
852 { XtNlabel, (XtArgVal) "..." },
853 { XtNresizable, (XtArgVal) True },
854 { XtNresize, (XtArgVal) False }
858 { XtNborderWidth, 0 },
859 { XtNjustify, (XtArgVal) XtJustifyLeft }
862 XtResource clientResources[] = {
863 { "flashCount", "flashCount", XtRInt, sizeof(int),
864 XtOffset(AppDataPtr, flashCount), XtRImmediate,
865 (XtPointer) FLASH_COUNT },
868 XrmOptionDescRec shellOptions[] = {
869 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
870 { "-flash", "flashCount", XrmoptionNoArg, "3" },
871 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
874 XtActionsRec boardActions[] = {
875 { "DrawPosition", DrawPositionProc },
876 { "HandleUserMove", HandleUserMove },
877 { "AnimateUserMove", AnimateUserMove },
878 { "HandlePV", HandlePV },
879 { "SelectPV", SelectPV },
880 { "StopPV", StopPV },
881 { "FileNameAction", FileNameAction },
882 { "AskQuestionProc", AskQuestionProc },
883 { "AskQuestionReplyAction", AskQuestionReplyAction },
884 { "PieceMenuPopup", PieceMenuPopup },
885 { "WhiteClock", WhiteClock },
886 { "BlackClock", BlackClock },
887 { "Iconify", Iconify },
888 { "ResetProc", ResetProc },
889 { "NewVariantProc", NewVariantProc },
890 { "LoadGameProc", LoadGameProc },
891 { "LoadNextGameProc", LoadNextGameProc },
892 { "LoadPrevGameProc", LoadPrevGameProc },
893 { "LoadSelectedProc", LoadSelectedProc },
894 { "SetFilterProc", SetFilterProc },
895 { "ReloadGameProc", ReloadGameProc },
896 { "LoadPositionProc", LoadPositionProc },
897 { "LoadNextPositionProc", LoadNextPositionProc },
898 { "LoadPrevPositionProc", LoadPrevPositionProc },
899 { "ReloadPositionProc", ReloadPositionProc },
900 { "CopyPositionProc", CopyPositionProc },
901 { "PastePositionProc", PastePositionProc },
902 { "CopyGameProc", CopyGameProc },
903 { "PasteGameProc", PasteGameProc },
904 { "SaveGameProc", SaveGameProc },
905 { "SavePositionProc", SavePositionProc },
906 { "MailMoveProc", MailMoveProc },
907 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
908 { "QuitProc", QuitProc },
909 { "MachineWhiteProc", MachineWhiteProc },
910 { "MachineBlackProc", MachineBlackProc },
911 { "AnalysisModeProc", AnalyzeModeProc },
912 { "AnalyzeFileProc", AnalyzeFileProc },
913 { "TwoMachinesProc", TwoMachinesProc },
914 { "IcsClientProc", IcsClientProc },
915 { "EditGameProc", EditGameProc },
916 { "EditPositionProc", EditPositionProc },
917 { "TrainingProc", EditPositionProc },
918 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
919 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
920 { "ShowGameListProc", ShowGameListProc },
921 { "ShowMoveListProc", HistoryShowProc},
922 { "EditTagsProc", EditCommentProc },
923 { "EditCommentProc", EditCommentProc },
924 { "IcsAlarmProc", IcsAlarmProc },
925 { "IcsInputBoxProc", IcsInputBoxProc },
926 { "PauseProc", PauseProc },
927 { "AcceptProc", AcceptProc },
928 { "DeclineProc", DeclineProc },
929 { "RematchProc", RematchProc },
930 { "CallFlagProc", CallFlagProc },
931 { "DrawProc", DrawProc },
932 { "AdjournProc", AdjournProc },
933 { "AbortProc", AbortProc },
934 { "ResignProc", ResignProc },
935 { "AdjuWhiteProc", AdjuWhiteProc },
936 { "AdjuBlackProc", AdjuBlackProc },
937 { "AdjuDrawProc", AdjuDrawProc },
938 { "EnterKeyProc", EnterKeyProc },
939 { "UpKeyProc", UpKeyProc },
940 { "DownKeyProc", DownKeyProc },
941 { "StopObservingProc", StopObservingProc },
942 { "StopExaminingProc", StopExaminingProc },
943 { "UploadProc", UploadProc },
944 { "BackwardProc", BackwardProc },
945 { "ForwardProc", ForwardProc },
946 { "ToStartProc", ToStartProc },
947 { "ToEndProc", ToEndProc },
948 { "RevertProc", RevertProc },
949 { "AnnotateProc", AnnotateProc },
950 { "TruncateGameProc", TruncateGameProc },
951 { "MoveNowProc", MoveNowProc },
952 { "RetractMoveProc", RetractMoveProc },
953 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
954 { "UciMenuProc", (XtActionProc) UciMenuProc },
955 { "TimeControlProc", (XtActionProc) TimeControlProc },
956 { "AlwaysQueenProc", AlwaysQueenProc },
957 { "AnimateDraggingProc", AnimateDraggingProc },
958 { "AnimateMovingProc", AnimateMovingProc },
959 { "AutoflagProc", AutoflagProc },
960 { "AutoflipProc", AutoflipProc },
961 { "AutobsProc", AutobsProc },
962 { "AutoraiseProc", AutoraiseProc },
963 { "AutosaveProc", AutosaveProc },
964 { "BlindfoldProc", BlindfoldProc },
965 { "FlashMovesProc", FlashMovesProc },
966 { "FlipViewProc", FlipViewProc },
967 { "GetMoveListProc", GetMoveListProc },
969 { "HighlightDraggingProc", HighlightDraggingProc },
971 { "HighlightLastMoveProc", HighlightLastMoveProc },
972 { "IcsAlarmProc", IcsAlarmProc },
973 { "MoveSoundProc", MoveSoundProc },
974 { "OldSaveStyleProc", OldSaveStyleProc },
975 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
976 { "PonderNextMoveProc", PonderNextMoveProc },
977 { "PopupExitMessageProc", PopupExitMessageProc },
978 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
979 { "PremoveProc", PremoveProc },
980 { "QuietPlayProc", QuietPlayProc },
981 { "ShowCoordsProc", ShowCoordsProc },
982 { "ShowThinkingProc", ShowThinkingProc },
983 { "HideThinkingProc", HideThinkingProc },
984 { "TestLegalityProc", TestLegalityProc },
985 { "SaveSettingsProc", SaveSettingsProc },
986 { "SaveOnExitProc", SaveOnExitProc },
987 { "InfoProc", InfoProc },
988 { "ManProc", ManProc },
989 { "HintProc", HintProc },
990 { "BookProc", BookProc },
991 { "AboutGameProc", AboutGameProc },
992 { "AboutProc", AboutProc },
993 { "DebugProc", DebugProc },
994 { "NothingProc", NothingProc },
995 { "CommentClick", (XtActionProc) CommentClick },
996 { "CommentPopDown", (XtActionProc) CommentPopDown },
997 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
998 { "TagsPopDown", (XtActionProc) TagsPopDown },
999 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1000 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1001 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1002 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1003 { "GameListPopDown", (XtActionProc) GameListPopDown },
1004 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1005 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1006 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1007 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1008 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1009 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1010 { "EnginePopDown", (XtActionProc) EnginePopDown },
1011 { "UciPopDown", (XtActionProc) UciPopDown },
1012 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1013 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1014 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1015 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1018 char globalTranslations[] =
1019 ":<Key>F9: ResignProc() \n \
1020 :Ctrl<Key>n: ResetProc() \n \
1021 :Meta<Key>V: NewVariantProc() \n \
1022 :Ctrl<Key>o: LoadGameProc() \n \
1023 :Meta<Key>Next: LoadNextGameProc() \n \
1024 :Meta<Key>Prior: LoadPrevGameProc() \n \
1025 :Ctrl<Key>s: SaveGameProc() \n \
1026 :Ctrl<Key>c: CopyGameProc() \n \
1027 :Ctrl<Key>v: PasteGameProc() \n \
1028 :Ctrl<Key>O: LoadPositionProc() \n \
1029 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1030 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1031 :Ctrl<Key>S: SavePositionProc() \n \
1032 :Ctrl<Key>C: CopyPositionProc() \n \
1033 :Ctrl<Key>V: PastePositionProc() \n \
1034 :Ctrl<Key>q: QuitProc() \n \
1035 :Ctrl<Key>w: MachineWhiteProc() \n \
1036 :Ctrl<Key>b: MachineBlackProc() \n \
1037 :Ctrl<Key>t: TwoMachinesProc() \n \
1038 :Ctrl<Key>a: AnalysisModeProc() \n \
1039 :Ctrl<Key>f: AnalyzeFileProc() \n \
1040 :Ctrl<Key>e: EditGameProc() \n \
1041 :Ctrl<Key>E: EditPositionProc() \n \
1042 :Meta<Key>O: EngineOutputProc() \n \
1043 :Meta<Key>E: EvalGraphProc() \n \
1044 :Meta<Key>G: ShowGameListProc() \n \
1045 :Meta<Key>H: ShowMoveListProc() \n \
1046 :<Key>Pause: PauseProc() \n \
1047 :<Key>F3: AcceptProc() \n \
1048 :<Key>F4: DeclineProc() \n \
1049 :<Key>F12: RematchProc() \n \
1050 :<Key>F5: CallFlagProc() \n \
1051 :<Key>F6: DrawProc() \n \
1052 :<Key>F7: AdjournProc() \n \
1053 :<Key>F8: AbortProc() \n \
1054 :<Key>F10: StopObservingProc() \n \
1055 :<Key>F11: StopExaminingProc() \n \
1056 :Meta Ctrl<Key>F12: DebugProc() \n \
1057 :Meta<Key>End: ToEndProc() \n \
1058 :Meta<Key>Right: ForwardProc() \n \
1059 :Meta<Key>Home: ToStartProc() \n \
1060 :Meta<Key>Left: BackwardProc() \n \
1061 :Ctrl<Key>m: MoveNowProc() \n \
1062 :Ctrl<Key>x: RetractMoveProc() \n \
1063 :Meta<Key>J: EngineMenuProc() \n \
1064 :Meta<Key>U: UciMenuProc() \n \
1065 :Meta<Key>T: TimeControlProc() \n \
1066 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1067 :Ctrl<Key>F: AutoflagProc() \n \
1068 :Ctrl<Key>A: AnimateMovingProc() \n \
1069 :Ctrl<Key>P: PonderNextMoveProc() \n \
1070 :Ctrl<Key>L: TestLegalityProc() \n \
1071 :Ctrl<Key>H: HideThinkingProc() \n \
1072 :<Key>-: Iconify() \n \
1073 :<Key>F1: ManProc() \n \
1074 :<Key>F2: FlipViewProc() \n \
1075 <KeyDown>.: BackwardProc() \n \
1076 <KeyUp>.: ForwardProc() \n \
1077 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1078 \"Send to chess program:\",,1) \n \
1079 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1080 \"Send to second chess program:\",,2) \n";
1082 char boardTranslations[] =
1083 "<Btn1Down>: HandleUserMove(0) \n \
1084 Shift<Btn1Up>: HandleUserMove(1) \n \
1085 <Btn1Up>: HandleUserMove(0) \n \
1086 <Btn1Motion>: AnimateUserMove() \n \
1087 <Btn3Motion>: HandlePV() \n \
1088 <Btn3Up>: PieceMenuPopup(menuB) \n \
1089 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1090 PieceMenuPopup(menuB) \n \
1091 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1092 PieceMenuPopup(menuW) \n \
1093 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1094 PieceMenuPopup(menuW) \n \
1095 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1096 PieceMenuPopup(menuB) \n";
1098 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1099 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1101 char ICSInputTranslations[] =
1102 "<Key>Up: UpKeyProc() \n "
1103 "<Key>Down: DownKeyProc() \n "
1104 "<Key>Return: EnterKeyProc() \n";
1106 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1107 // as the widget is destroyed before the up-click can call extend-end
1108 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1110 String xboardResources[] = {
1111 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1112 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1113 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1118 /* Max possible square size */
1119 #define MAXSQSIZE 256
1121 static int xpm_avail[MAXSQSIZE];
1123 #ifdef HAVE_DIR_STRUCT
1125 /* Extract piece size from filename */
1127 xpm_getsize(name, len, ext)
1138 if ((p=strchr(name, '.')) == NULL ||
1139 StrCaseCmp(p+1, ext) != 0)
1145 while (*p && isdigit(*p))
1152 /* Setup xpm_avail */
1154 xpm_getavail(dirname, ext)
1162 for (i=0; i<MAXSQSIZE; ++i)
1165 if (appData.debugMode)
1166 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1168 dir = opendir(dirname);
1171 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1172 programName, dirname);
1176 while ((ent=readdir(dir)) != NULL) {
1177 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1178 if (i > 0 && i < MAXSQSIZE)
1188 xpm_print_avail(fp, ext)
1194 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1195 for (i=1; i<MAXSQSIZE; ++i) {
1201 /* Return XPM piecesize closest to size */
1203 xpm_closest_to(dirname, size, ext)
1209 int sm_diff = MAXSQSIZE;
1213 xpm_getavail(dirname, ext);
1215 if (appData.debugMode)
1216 xpm_print_avail(stderr, ext);
1218 for (i=1; i<MAXSQSIZE; ++i) {
1221 diff = (diff<0) ? -diff : diff;
1222 if (diff < sm_diff) {
1230 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1236 #else /* !HAVE_DIR_STRUCT */
1237 /* If we are on a system without a DIR struct, we can't
1238 read the directory, so we can't collect a list of
1239 filenames, etc., so we can't do any size-fitting. */
1241 xpm_closest_to(dirname, size, ext)
1246 fprintf(stderr, _("\
1247 Warning: No DIR structure found on this system --\n\
1248 Unable to autosize for XPM/XIM pieces.\n\
1249 Please report this error to frankm@hiwaay.net.\n\
1250 Include system type & operating system in message.\n"));
1253 #endif /* HAVE_DIR_STRUCT */
1255 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1256 "magenta", "cyan", "white" };
1260 TextColors textColors[(int)NColorClasses];
1262 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1264 parse_color(str, which)
1268 char *p, buf[100], *d;
1271 if (strlen(str) > 99) /* watch bounds on buf */
1276 for (i=0; i<which; ++i) {
1283 /* Could be looking at something like:
1285 .. in which case we want to stop on a comma also */
1286 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1290 return -1; /* Use default for empty field */
1293 if (which == 2 || isdigit(*p))
1296 while (*p && isalpha(*p))
1301 for (i=0; i<8; ++i) {
1302 if (!StrCaseCmp(buf, cnames[i]))
1303 return which? (i+40) : (i+30);
1305 if (!StrCaseCmp(buf, "default")) return -1;
1307 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1312 parse_cpair(cc, str)
1316 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1317 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1322 /* bg and attr are optional */
1323 textColors[(int)cc].bg = parse_color(str, 1);
1324 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1325 textColors[(int)cc].attr = 0;
1331 /* Arrange to catch delete-window events */
1332 Atom wm_delete_window;
1334 CatchDeleteWindow(Widget w, String procname)
1337 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1338 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1339 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1346 XtSetArg(args[0], XtNiconic, False);
1347 XtSetValues(shellWidget, args, 1);
1349 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1352 //---------------------------------------------------------------------------------------------------------
1353 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1356 #define CW_USEDEFAULT (1<<31)
1357 #define ICS_TEXT_MENU_SIZE 90
1358 #define DEBUG_FILE "xboard.debug"
1359 #define SetCurrentDirectory chdir
1360 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1364 // these two must some day move to frontend.h, when they are implemented
1365 Boolean GameListIsUp();
1367 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1370 // front-end part of option handling
1372 // [HGM] This platform-dependent table provides the location for storing the color info
1373 extern char *crWhite, * crBlack;
1377 &appData.whitePieceColor,
1378 &appData.blackPieceColor,
1379 &appData.lightSquareColor,
1380 &appData.darkSquareColor,
1381 &appData.highlightSquareColor,
1382 &appData.premoveHighlightColor,
1383 &appData.lowTimeWarningColor,
1394 // [HGM] font: keep a font for each square size, even non-stndard ones
1395 #define NUM_SIZES 18
1396 #define MAX_SIZE 130
1397 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1398 char *fontTable[NUM_FONTS][MAX_SIZE];
1401 ParseFont(char *name, int number)
1402 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1404 if(sscanf(name, "size%d:", &size)) {
1405 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1406 // defer processing it until we know if it matches our board size
1407 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1408 fontTable[number][size] = strdup(strchr(name, ':')+1);
1409 fontValid[number][size] = True;
1414 case 0: // CLOCK_FONT
1415 appData.clockFont = strdup(name);
1417 case 1: // MESSAGE_FONT
1418 appData.font = strdup(name);
1420 case 2: // COORD_FONT
1421 appData.coordFont = strdup(name);
1426 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1431 { // only 2 fonts currently
1432 appData.clockFont = CLOCK_FONT_NAME;
1433 appData.coordFont = COORD_FONT_NAME;
1434 appData.font = DEFAULT_FONT_NAME;
1439 { // no-op, until we identify the code for this already in XBoard and move it here
1443 ParseColor(int n, char *name)
1444 { // in XBoard, just copy the color-name string
1445 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1449 ParseTextAttribs(ColorClass cc, char *s)
1451 (&appData.colorShout)[cc] = strdup(s);
1455 ParseBoardSize(void *addr, char *name)
1457 appData.boardSize = strdup(name);
1462 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1466 SetCommPortDefaults()
1467 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1470 // [HGM] args: these three cases taken out to stay in front-end
1472 SaveFontArg(FILE *f, ArgDescriptor *ad)
1475 int i, n = (int)ad->argLoc;
1477 case 0: // CLOCK_FONT
1478 name = appData.clockFont;
1480 case 1: // MESSAGE_FONT
1481 name = appData.font;
1483 case 2: // COORD_FONT
1484 name = appData.coordFont;
1489 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1490 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1491 fontTable[n][squareSize] = strdup(name);
1492 fontValid[n][squareSize] = True;
1495 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1496 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1501 { // nothing to do, as the sounds are at all times represented by their text-string names already
1505 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1506 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1507 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1511 SaveColor(FILE *f, ArgDescriptor *ad)
1512 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1513 if(colorVariable[(int)ad->argLoc])
1514 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1518 SaveBoardSize(FILE *f, char *name, void *addr)
1519 { // wrapper to shield back-end from BoardSize & sizeInfo
1520 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1524 ParseCommPortSettings(char *s)
1525 { // no such option in XBoard (yet)
1528 extern Widget engineOutputShell;
1529 extern Widget tagsShell, editTagsShell;
1531 GetActualPlacement(Widget wg, WindowPlacement *wp)
1541 XtSetArg(args[i], XtNx, &x); i++;
1542 XtSetArg(args[i], XtNy, &y); i++;
1543 XtSetArg(args[i], XtNwidth, &w); i++;
1544 XtSetArg(args[i], XtNheight, &h); i++;
1545 XtGetValues(wg, args, i);
1554 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1555 // In XBoard this will have to wait until awareness of window parameters is implemented
1556 GetActualPlacement(shellWidget, &wpMain);
1557 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1558 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1559 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1560 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1561 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1562 else GetActualPlacement(editShell, &wpComment);
1563 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1564 else GetActualPlacement(editTagsShell, &wpTags);
1568 PrintCommPortSettings(FILE *f, char *name)
1569 { // This option does not exist in XBoard
1573 MySearchPath(char *installDir, char *name, char *fullname)
1574 { // just append installDir and name. Perhaps ExpandPath should be used here?
1575 name = ExpandPathName(name);
1576 if(name && name[0] == '/')
1577 safeStrCpy(fullname, name, MSG_SIZ );
1579 sprintf(fullname, "%s%c%s", installDir, '/', name);
1585 MyGetFullPathName(char *name, char *fullname)
1586 { // should use ExpandPath?
1587 name = ExpandPathName(name);
1588 safeStrCpy(fullname, name, MSG_SIZ );
1593 EnsureOnScreen(int *x, int *y, int minX, int minY)
1600 { // [HGM] args: allows testing if main window is realized from back-end
1601 return xBoardWindow != 0;
1605 PopUpStartupDialog()
1606 { // start menu not implemented in XBoard
1610 ConvertToLine(int argc, char **argv)
1612 static char line[128*1024], buf[1024];
1616 for(i=1; i<argc; i++)
1618 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1619 && argv[i][0] != '{' )
1620 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1622 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1623 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1626 line[strlen(line)-1] = NULLCHAR;
1630 //--------------------------------------------------------------------------------------------
1632 extern Boolean twoBoards, partnerUp;
1635 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1637 #define BoardSize int
1638 void InitDrawingSizes(BoardSize boardSize, int flags)
1639 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1640 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1642 XtGeometryResult gres;
1645 if(!formWidget) return;
1648 * Enable shell resizing.
1650 shellArgs[0].value = (XtArgVal) &w;
1651 shellArgs[1].value = (XtArgVal) &h;
1652 XtGetValues(shellWidget, shellArgs, 2);
1654 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1655 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1656 XtSetValues(shellWidget, &shellArgs[2], 4);
1658 XtSetArg(args[0], XtNdefaultDistance, &sep);
1659 XtGetValues(formWidget, args, 1);
1661 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1662 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1664 hOffset = boardWidth + 10;
1665 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1666 secondSegments[i] = gridSegments[i];
1667 secondSegments[i].x1 += hOffset;
1668 secondSegments[i].x2 += hOffset;
1671 XtSetArg(args[0], XtNwidth, boardWidth);
1672 XtSetArg(args[1], XtNheight, boardHeight);
1673 XtSetValues(boardWidget, args, 2);
1675 timerWidth = (boardWidth - sep) / 2;
1676 XtSetArg(args[0], XtNwidth, timerWidth);
1677 XtSetValues(whiteTimerWidget, args, 1);
1678 XtSetValues(blackTimerWidget, args, 1);
1680 XawFormDoLayout(formWidget, False);
1682 if (appData.titleInWindow) {
1684 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1685 XtSetArg(args[i], XtNheight, &h); i++;
1686 XtGetValues(titleWidget, args, i);
1688 w = boardWidth - 2*bor;
1690 XtSetArg(args[0], XtNwidth, &w);
1691 XtGetValues(menuBarWidget, args, 1);
1692 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1695 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1696 if (gres != XtGeometryYes && appData.debugMode) {
1698 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1699 programName, gres, w, h, wr, hr);
1703 XawFormDoLayout(formWidget, True);
1706 * Inhibit shell resizing.
1708 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1709 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1710 shellArgs[4].value = shellArgs[2].value = w;
1711 shellArgs[5].value = shellArgs[3].value = h;
1712 XtSetValues(shellWidget, &shellArgs[0], 6);
1714 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1717 for(i=0; i<4; i++) {
1719 for(p=0; p<=(int)WhiteKing; p++)
1720 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1721 if(gameInfo.variant == VariantShogi) {
1722 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1723 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1724 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1725 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1726 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1729 if(gameInfo.variant == VariantGothic) {
1730 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1733 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1734 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1735 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1738 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1739 for(p=0; p<=(int)WhiteKing; p++)
1740 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1741 if(gameInfo.variant == VariantShogi) {
1742 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1743 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1744 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1745 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1746 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1749 if(gameInfo.variant == VariantGothic) {
1750 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1753 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1754 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1755 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1760 for(i=0; i<2; i++) {
1762 for(p=0; p<=(int)WhiteKing; p++)
1763 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1764 if(gameInfo.variant == VariantShogi) {
1765 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1766 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1767 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1768 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1769 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1772 if(gameInfo.variant == VariantGothic) {
1773 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1776 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1777 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1778 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1793 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1794 XSetWindowAttributes window_attributes;
1796 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1797 XrmValue vFrom, vTo;
1798 XtGeometryResult gres;
1801 int forceMono = False;
1803 srandom(time(0)); // [HGM] book: make random truly random
1805 setbuf(stdout, NULL);
1806 setbuf(stderr, NULL);
1809 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1810 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1814 programName = strrchr(argv[0], '/');
1815 if (programName == NULL)
1816 programName = argv[0];
1821 XtSetLanguageProc(NULL, NULL, NULL);
1822 bindtextdomain(PACKAGE, LOCALEDIR);
1823 textdomain(PACKAGE);
1827 XtAppInitialize(&appContext, "XBoard", shellOptions,
1828 XtNumber(shellOptions),
1829 &argc, argv, xboardResources, NULL, 0);
1830 appData.boardSize = "";
1831 InitAppData(ConvertToLine(argc, argv));
1833 if (p == NULL) p = "/tmp";
1834 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1835 gameCopyFilename = (char*) malloc(i);
1836 gamePasteFilename = (char*) malloc(i);
1837 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1838 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1840 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1841 clientResources, XtNumber(clientResources),
1844 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1845 static char buf[MSG_SIZ];
1846 EscapeExpand(buf, appData.initString);
1847 appData.initString = strdup(buf);
1848 EscapeExpand(buf, appData.secondInitString);
1849 appData.secondInitString = strdup(buf);
1850 EscapeExpand(buf, appData.firstComputerString);
1851 appData.firstComputerString = strdup(buf);
1852 EscapeExpand(buf, appData.secondComputerString);
1853 appData.secondComputerString = strdup(buf);
1856 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1859 if (chdir(chessDir) != 0) {
1860 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1866 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1867 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1868 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1869 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1872 setbuf(debugFP, NULL);
1875 /* [HGM,HR] make sure board size is acceptable */
1876 if(appData.NrFiles > BOARD_FILES ||
1877 appData.NrRanks > BOARD_RANKS )
1878 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1881 /* This feature does not work; animation needs a rewrite */
1882 appData.highlightDragging = FALSE;
1886 xDisplay = XtDisplay(shellWidget);
1887 xScreen = DefaultScreen(xDisplay);
1888 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1890 gameInfo.variant = StringToVariant(appData.variant);
1891 InitPosition(FALSE);
1894 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1896 if (isdigit(appData.boardSize[0])) {
1897 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1898 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1899 &fontPxlSize, &smallLayout, &tinyLayout);
1901 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1902 programName, appData.boardSize);
1906 /* Find some defaults; use the nearest known size */
1907 SizeDefaults *szd, *nearest;
1908 int distance = 99999;
1909 nearest = szd = sizeDefaults;
1910 while (szd->name != NULL) {
1911 if (abs(szd->squareSize - squareSize) < distance) {
1913 distance = abs(szd->squareSize - squareSize);
1914 if (distance == 0) break;
1918 if (i < 2) lineGap = nearest->lineGap;
1919 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1920 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1921 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1922 if (i < 6) smallLayout = nearest->smallLayout;
1923 if (i < 7) tinyLayout = nearest->tinyLayout;
1926 SizeDefaults *szd = sizeDefaults;
1927 if (*appData.boardSize == NULLCHAR) {
1928 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1929 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1932 if (szd->name == NULL) szd--;
1933 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1935 while (szd->name != NULL &&
1936 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1937 if (szd->name == NULL) {
1938 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1939 programName, appData.boardSize);
1943 squareSize = szd->squareSize;
1944 lineGap = szd->lineGap;
1945 clockFontPxlSize = szd->clockFontPxlSize;
1946 coordFontPxlSize = szd->coordFontPxlSize;
1947 fontPxlSize = szd->fontPxlSize;
1948 smallLayout = szd->smallLayout;
1949 tinyLayout = szd->tinyLayout;
1950 // [HGM] font: use defaults from settings file if available and not overruled
1952 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1953 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1954 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1955 appData.font = fontTable[MESSAGE_FONT][squareSize];
1956 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1957 appData.coordFont = fontTable[COORD_FONT][squareSize];
1959 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1960 if (strlen(appData.pixmapDirectory) > 0) {
1961 p = ExpandPathName(appData.pixmapDirectory);
1963 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1964 appData.pixmapDirectory);
1967 if (appData.debugMode) {
1968 fprintf(stderr, _("\
1969 XBoard square size (hint): %d\n\
1970 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1972 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1973 if (appData.debugMode) {
1974 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1977 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1979 /* [HR] height treated separately (hacked) */
1980 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1981 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1982 if (appData.showJail == 1) {
1983 /* Jail on top and bottom */
1984 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1985 XtSetArg(boardArgs[2], XtNheight,
1986 boardHeight + 2*(lineGap + squareSize));
1987 } else if (appData.showJail == 2) {
1989 XtSetArg(boardArgs[1], XtNwidth,
1990 boardWidth + 2*(lineGap + squareSize));
1991 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1994 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1995 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1999 * Determine what fonts to use.
2001 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2002 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2003 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2004 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2005 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2006 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2007 appData.font = FindFont(appData.font, fontPxlSize);
2008 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2009 countFontStruct = XQueryFont(xDisplay, countFontID);
2010 // appData.font = FindFont(appData.font, fontPxlSize);
2012 xdb = XtDatabase(xDisplay);
2013 XrmPutStringResource(&xdb, "*font", appData.font);
2016 * Detect if there are not enough colors available and adapt.
2018 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2019 appData.monoMode = True;
2022 if (!appData.monoMode) {
2023 vFrom.addr = (caddr_t) appData.lightSquareColor;
2024 vFrom.size = strlen(appData.lightSquareColor);
2025 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2026 if (vTo.addr == NULL) {
2027 appData.monoMode = True;
2030 lightSquareColor = *(Pixel *) vTo.addr;
2033 if (!appData.monoMode) {
2034 vFrom.addr = (caddr_t) appData.darkSquareColor;
2035 vFrom.size = strlen(appData.darkSquareColor);
2036 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2037 if (vTo.addr == NULL) {
2038 appData.monoMode = True;
2041 darkSquareColor = *(Pixel *) vTo.addr;
2044 if (!appData.monoMode) {
2045 vFrom.addr = (caddr_t) appData.whitePieceColor;
2046 vFrom.size = strlen(appData.whitePieceColor);
2047 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2048 if (vTo.addr == NULL) {
2049 appData.monoMode = True;
2052 whitePieceColor = *(Pixel *) vTo.addr;
2055 if (!appData.monoMode) {
2056 vFrom.addr = (caddr_t) appData.blackPieceColor;
2057 vFrom.size = strlen(appData.blackPieceColor);
2058 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2059 if (vTo.addr == NULL) {
2060 appData.monoMode = True;
2063 blackPieceColor = *(Pixel *) vTo.addr;
2067 if (!appData.monoMode) {
2068 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2069 vFrom.size = strlen(appData.highlightSquareColor);
2070 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2071 if (vTo.addr == NULL) {
2072 appData.monoMode = True;
2075 highlightSquareColor = *(Pixel *) vTo.addr;
2079 if (!appData.monoMode) {
2080 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2081 vFrom.size = strlen(appData.premoveHighlightColor);
2082 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2083 if (vTo.addr == NULL) {
2084 appData.monoMode = True;
2087 premoveHighlightColor = *(Pixel *) vTo.addr;
2092 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2095 if (appData.bitmapDirectory == NULL ||
2096 appData.bitmapDirectory[0] == NULLCHAR)
2097 appData.bitmapDirectory = DEF_BITMAP_DIR;
2100 if (appData.lowTimeWarning && !appData.monoMode) {
2101 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2102 vFrom.size = strlen(appData.lowTimeWarningColor);
2103 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2104 if (vTo.addr == NULL)
2105 appData.monoMode = True;
2107 lowTimeWarningColor = *(Pixel *) vTo.addr;
2110 if (appData.monoMode && appData.debugMode) {
2111 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2112 (unsigned long) XWhitePixel(xDisplay, xScreen),
2113 (unsigned long) XBlackPixel(xDisplay, xScreen));
2116 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2117 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2118 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2119 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2120 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2121 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2122 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2123 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2124 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2125 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2127 if (appData.colorize) {
2129 _("%s: can't parse color names; disabling colorization\n"),
2132 appData.colorize = FALSE;
2134 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2135 textColors[ColorNone].attr = 0;
2137 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2143 layoutName = "tinyLayout";
2144 } else if (smallLayout) {
2145 layoutName = "smallLayout";
2147 layoutName = "normalLayout";
2149 /* Outer layoutWidget is there only to provide a name for use in
2150 resources that depend on the layout style */
2152 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2153 layoutArgs, XtNumber(layoutArgs));
2155 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2156 formArgs, XtNumber(formArgs));
2157 XtSetArg(args[0], XtNdefaultDistance, &sep);
2158 XtGetValues(formWidget, args, 1);
2161 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2162 XtSetArg(args[0], XtNtop, XtChainTop);
2163 XtSetArg(args[1], XtNbottom, XtChainTop);
2164 XtSetArg(args[2], XtNright, XtChainLeft);
2165 XtSetValues(menuBarWidget, args, 3);
2167 widgetList[j++] = whiteTimerWidget =
2168 XtCreateWidget("whiteTime", labelWidgetClass,
2169 formWidget, timerArgs, XtNumber(timerArgs));
2170 XtSetArg(args[0], XtNfont, clockFontStruct);
2171 XtSetArg(args[1], XtNtop, XtChainTop);
2172 XtSetArg(args[2], XtNbottom, XtChainTop);
2173 XtSetValues(whiteTimerWidget, args, 3);
2175 widgetList[j++] = blackTimerWidget =
2176 XtCreateWidget("blackTime", labelWidgetClass,
2177 formWidget, timerArgs, XtNumber(timerArgs));
2178 XtSetArg(args[0], XtNfont, clockFontStruct);
2179 XtSetArg(args[1], XtNtop, XtChainTop);
2180 XtSetArg(args[2], XtNbottom, XtChainTop);
2181 XtSetValues(blackTimerWidget, args, 3);
2183 if (appData.titleInWindow) {
2184 widgetList[j++] = titleWidget =
2185 XtCreateWidget("title", labelWidgetClass, formWidget,
2186 titleArgs, XtNumber(titleArgs));
2187 XtSetArg(args[0], XtNtop, XtChainTop);
2188 XtSetArg(args[1], XtNbottom, XtChainTop);
2189 XtSetValues(titleWidget, args, 2);
2192 if (appData.showButtonBar) {
2193 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2194 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2195 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2196 XtSetArg(args[2], XtNtop, XtChainTop);
2197 XtSetArg(args[3], XtNbottom, XtChainTop);
2198 XtSetValues(buttonBarWidget, args, 4);
2201 widgetList[j++] = messageWidget =
2202 XtCreateWidget("message", labelWidgetClass, formWidget,
2203 messageArgs, XtNumber(messageArgs));
2204 XtSetArg(args[0], XtNtop, XtChainTop);
2205 XtSetArg(args[1], XtNbottom, XtChainTop);
2206 XtSetValues(messageWidget, args, 2);
2208 widgetList[j++] = boardWidget =
2209 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2210 XtNumber(boardArgs));
2212 XtManageChildren(widgetList, j);
2214 timerWidth = (boardWidth - sep) / 2;
2215 XtSetArg(args[0], XtNwidth, timerWidth);
2216 XtSetValues(whiteTimerWidget, args, 1);
2217 XtSetValues(blackTimerWidget, args, 1);
2219 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2220 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2221 XtGetValues(whiteTimerWidget, args, 2);
2223 if (appData.showButtonBar) {
2224 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2225 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2226 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2230 * formWidget uses these constraints but they are stored
2234 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2235 XtSetValues(menuBarWidget, args, i);
2236 if (appData.titleInWindow) {
2239 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2240 XtSetValues(whiteTimerWidget, args, i);
2242 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2243 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2244 XtSetValues(blackTimerWidget, args, i);
2246 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2247 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2248 XtSetValues(titleWidget, args, i);
2250 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2251 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2252 XtSetValues(messageWidget, args, i);
2253 if (appData.showButtonBar) {
2255 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2256 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2257 XtSetValues(buttonBarWidget, args, i);
2261 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2262 XtSetValues(whiteTimerWidget, args, i);
2264 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2265 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2266 XtSetValues(blackTimerWidget, args, i);
2268 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2269 XtSetValues(titleWidget, args, i);
2271 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2272 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2273 XtSetValues(messageWidget, args, i);
2274 if (appData.showButtonBar) {
2276 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2277 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2278 XtSetValues(buttonBarWidget, args, i);
2283 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2284 XtSetValues(whiteTimerWidget, args, i);
2286 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2287 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2288 XtSetValues(blackTimerWidget, args, i);
2290 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2291 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2292 XtSetValues(messageWidget, args, i);
2293 if (appData.showButtonBar) {
2295 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2296 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2297 XtSetValues(buttonBarWidget, args, i);
2301 XtSetArg(args[0], XtNfromVert, messageWidget);
2302 XtSetArg(args[1], XtNtop, XtChainTop);
2303 XtSetArg(args[2], XtNbottom, XtChainBottom);
2304 XtSetArg(args[3], XtNleft, XtChainLeft);
2305 XtSetArg(args[4], XtNright, XtChainRight);
2306 XtSetValues(boardWidget, args, 5);
2308 XtRealizeWidget(shellWidget);
2311 XtSetArg(args[0], XtNx, wpMain.x);
2312 XtSetArg(args[1], XtNy, wpMain.y);
2313 XtSetValues(shellWidget, args, 2);
2317 * Correct the width of the message and title widgets.
2318 * It is not known why some systems need the extra fudge term.
2319 * The value "2" is probably larger than needed.
2321 XawFormDoLayout(formWidget, False);
2323 #define WIDTH_FUDGE 2
2325 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2326 XtSetArg(args[i], XtNheight, &h); i++;
2327 XtGetValues(messageWidget, args, i);
2328 if (appData.showButtonBar) {
2330 XtSetArg(args[i], XtNwidth, &w); i++;
2331 XtGetValues(buttonBarWidget, args, i);
2332 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2334 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2337 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2338 if (gres != XtGeometryYes && appData.debugMode) {
2339 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2340 programName, gres, w, h, wr, hr);
2343 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2344 /* The size used for the child widget in layout lags one resize behind
2345 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2347 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2348 if (gres != XtGeometryYes && appData.debugMode) {
2349 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2350 programName, gres, w, h, wr, hr);
2353 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2354 XtSetArg(args[1], XtNright, XtChainRight);
2355 XtSetValues(messageWidget, args, 2);
2357 if (appData.titleInWindow) {
2359 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2360 XtSetArg(args[i], XtNheight, &h); i++;
2361 XtGetValues(titleWidget, args, i);
2363 w = boardWidth - 2*bor;
2365 XtSetArg(args[0], XtNwidth, &w);
2366 XtGetValues(menuBarWidget, args, 1);
2367 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2370 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2371 if (gres != XtGeometryYes && appData.debugMode) {
2373 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2374 programName, gres, w, h, wr, hr);
2377 XawFormDoLayout(formWidget, True);
2379 xBoardWindow = XtWindow(boardWidget);
2381 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2382 // not need to go into InitDrawingSizes().
2386 * Create X checkmark bitmap and initialize option menu checks.
2388 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2389 checkmark_bits, checkmark_width, checkmark_height);
2390 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2391 if (appData.alwaysPromoteToQueen) {
2392 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2395 if (appData.animateDragging) {
2396 XtSetValues(XtNameToWidget(menuBarWidget,
2397 "menuOptions.Animate Dragging"),
2400 if (appData.animate) {
2401 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2404 if (appData.autoComment) {
2405 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2408 if (appData.autoCallFlag) {
2409 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2412 if (appData.autoFlipView) {
2413 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2416 if (appData.autoObserve) {
2417 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2420 if (appData.autoRaiseBoard) {
2421 XtSetValues(XtNameToWidget(menuBarWidget,
2422 "menuOptions.Auto Raise Board"), args, 1);
2424 if (appData.autoSaveGames) {
2425 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2428 if (appData.saveGameFile[0] != NULLCHAR) {
2429 /* Can't turn this off from menu */
2430 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2432 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
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"),
2445 if (appData.getMoveList) {
2446 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2450 if (appData.highlightDragging) {
2451 XtSetValues(XtNameToWidget(menuBarWidget,
2452 "menuOptions.Highlight Dragging"),
2456 if (appData.highlightLastMove) {
2457 XtSetValues(XtNameToWidget(menuBarWidget,
2458 "menuOptions.Highlight Last Move"),
2461 if (appData.icsAlarm) {
2462 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2465 if (appData.ringBellAfterMoves) {
2466 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2469 if (appData.oldSaveStyle) {
2470 XtSetValues(XtNameToWidget(menuBarWidget,
2471 "menuOptions.Old Save Style"), args, 1);
2473 if (appData.periodicUpdates) {
2474 XtSetValues(XtNameToWidget(menuBarWidget,
2475 "menuOptions.Periodic Updates"), args, 1);
2477 if (appData.ponderNextMove) {
2478 XtSetValues(XtNameToWidget(menuBarWidget,
2479 "menuOptions.Ponder Next Move"), args, 1);
2481 if (appData.popupExitMessage) {
2482 XtSetValues(XtNameToWidget(menuBarWidget,
2483 "menuOptions.Popup Exit Message"), args, 1);
2485 if (appData.popupMoveErrors) {
2486 XtSetValues(XtNameToWidget(menuBarWidget,
2487 "menuOptions.Popup Move Errors"), args, 1);
2489 if (appData.premove) {
2490 XtSetValues(XtNameToWidget(menuBarWidget,
2491 "menuOptions.Premove"), args, 1);
2493 if (appData.quietPlay) {
2494 XtSetValues(XtNameToWidget(menuBarWidget,
2495 "menuOptions.Quiet Play"), args, 1);
2497 if (appData.showCoords) {
2498 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2501 if (appData.hideThinkingFromHuman) {
2502 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2505 if (appData.testLegality) {
2506 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2509 if (saveSettingsOnExit) {
2510 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2517 ReadBitmap(&wIconPixmap, "icon_white.bm",
2518 icon_white_bits, icon_white_width, icon_white_height);
2519 ReadBitmap(&bIconPixmap, "icon_black.bm",
2520 icon_black_bits, icon_black_width, icon_black_height);
2521 iconPixmap = wIconPixmap;
2523 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2524 XtSetValues(shellWidget, args, i);
2527 * Create a cursor for the board widget.
2529 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2530 XChangeWindowAttributes(xDisplay, xBoardWindow,
2531 CWCursor, &window_attributes);
2534 * Inhibit shell resizing.
2536 shellArgs[0].value = (XtArgVal) &w;
2537 shellArgs[1].value = (XtArgVal) &h;
2538 XtGetValues(shellWidget, shellArgs, 2);
2539 shellArgs[4].value = shellArgs[2].value = w;
2540 shellArgs[5].value = shellArgs[3].value = h;
2541 XtSetValues(shellWidget, &shellArgs[2], 4);
2542 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2543 marginH = h - boardHeight;
2545 CatchDeleteWindow(shellWidget, "QuitProc");
2550 if (appData.bitmapDirectory[0] != NULLCHAR) {
2554 CreateXPMBoard(appData.liteBackTextureFile, 1);
2555 CreateXPMBoard(appData.darkBackTextureFile, 0);
2559 /* Create regular pieces */
2560 if (!useImages) CreatePieces();
2565 if (appData.animate || appData.animateDragging)
2568 XtAugmentTranslations(formWidget,
2569 XtParseTranslationTable(globalTranslations));
2570 XtAugmentTranslations(boardWidget,
2571 XtParseTranslationTable(boardTranslations));
2572 XtAugmentTranslations(whiteTimerWidget,
2573 XtParseTranslationTable(whiteTranslations));
2574 XtAugmentTranslations(blackTimerWidget,
2575 XtParseTranslationTable(blackTranslations));
2577 /* Why is the following needed on some versions of X instead
2578 * of a translation? */
2579 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2580 (XtEventHandler) EventProc, NULL);
2583 /* [AS] Restore layout */
2584 if( wpMoveHistory.visible ) {
2588 if( wpEvalGraph.visible )
2593 if( wpEngineOutput.visible ) {
2594 EngineOutputPopUp();
2599 if (errorExitStatus == -1) {
2600 if (appData.icsActive) {
2601 /* We now wait until we see "login:" from the ICS before
2602 sending the logon script (problems with timestamp otherwise) */
2603 /*ICSInitScript();*/
2604 if (appData.icsInputBox) ICSInputBoxPopUp();
2608 signal(SIGWINCH, TermSizeSigHandler);
2610 signal(SIGINT, IntSigHandler);
2611 signal(SIGTERM, IntSigHandler);
2612 if (*appData.cmailGameName != NULLCHAR) {
2613 signal(SIGUSR1, CmailSigHandler);
2616 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2618 XtSetKeyboardFocus(shellWidget, formWidget);
2620 XtAppMainLoop(appContext);
2621 if (appData.debugMode) fclose(debugFP); // [DM] debug
2628 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2629 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2631 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2632 unlink(gameCopyFilename);
2633 unlink(gamePasteFilename);
2636 RETSIGTYPE TermSizeSigHandler(int sig)
2649 CmailSigHandler(sig)
2655 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2657 /* Activate call-back function CmailSigHandlerCallBack() */
2658 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2660 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2664 CmailSigHandlerCallBack(isr, closure, message, count, error)
2672 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2674 /**** end signal code ****/
2680 /* try to open the icsLogon script, either in the location given
2681 * or in the users HOME directory
2688 f = fopen(appData.icsLogon, "r");
2691 homedir = getenv("HOME");
2692 if (homedir != NULL)
2694 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2695 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2696 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2697 f = fopen(buf, "r");
2702 ProcessICSInitScript(f);
2704 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2713 EditCommentPopDown();
2728 if (!menuBarWidget) return;
2729 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2731 DisplayError("menuEdit.Revert", 0);
2733 XtSetSensitive(w, !grey);
2735 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2737 DisplayError("menuEdit.Annotate", 0);
2739 XtSetSensitive(w, !grey);
2744 SetMenuEnables(enab)
2748 if (!menuBarWidget) return;
2749 while (enab->name != NULL) {
2750 w = XtNameToWidget(menuBarWidget, enab->name);
2752 DisplayError(enab->name, 0);
2754 XtSetSensitive(w, enab->value);
2760 Enables icsEnables[] = {
2761 { "menuFile.Mail Move", False },
2762 { "menuFile.Reload CMail Message", False },
2763 { "menuMode.Machine Black", False },
2764 { "menuMode.Machine White", False },
2765 { "menuMode.Analysis Mode", False },
2766 { "menuMode.Analyze File", False },
2767 { "menuMode.Two Machines", False },
2769 { "menuHelp.Hint", False },
2770 { "menuHelp.Book", False },
2771 { "menuEngine.Move Now", False },
2772 { "menuOptions.Periodic Updates", False },
2773 { "menuOptions.Hide Thinking", False },
2774 { "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.ICS Client", False },
2791 { "menuView.ICS Input Box", False },
2792 { "Action", False },
2793 { "menuEdit.Revert", False },
2794 { "menuEdit.Annotate", False },
2795 { "menuEngine.Engine #1 Settings", False },
2796 { "menuEngine.Engine #2 Settings", False },
2797 { "menuEngine.Move Now", False },
2798 { "menuEngine.Retract Move", False },
2799 { "menuOptions.Auto Comment", False },
2800 { "menuOptions.Auto Flag", False },
2801 { "menuOptions.Auto Flip View", False },
2802 { "menuOptions.Auto Observe", False },
2803 { "menuOptions.Auto Raise Board", False },
2804 { "menuOptions.Get Move List", False },
2805 { "menuOptions.ICS Alarm", False },
2806 { "menuOptions.Move Sound", False },
2807 { "menuOptions.Quiet Play", False },
2808 { "menuOptions.Hide Thinking", False },
2809 { "menuOptions.Periodic Updates", False },
2810 { "menuOptions.Ponder Next Move", False },
2811 { "menuHelp.Hint", False },
2812 { "menuHelp.Book", False },
2816 Enables gnuEnables[] = {
2817 { "menuMode.ICS Client", False },
2818 { "menuView.ICS Input Box", False },
2819 { "menuAction.Accept", False },
2820 { "menuAction.Decline", False },
2821 { "menuAction.Rematch", False },
2822 { "menuAction.Adjourn", False },
2823 { "menuAction.Stop Examining", False },
2824 { "menuAction.Stop Observing", False },
2825 { "menuAction.Upload to Examine", False },
2826 { "menuEdit.Revert", False },
2827 { "menuEdit.Annotate", False },
2828 { "menuOptions.Auto Comment", False },
2829 { "menuOptions.Auto Observe", False },
2830 { "menuOptions.Auto Raise Board", False },
2831 { "menuOptions.Get Move List", False },
2832 { "menuOptions.Premove", False },
2833 { "menuOptions.Quiet Play", False },
2835 /* The next two options rely on SetCmailMode being called *after* */
2836 /* SetGNUMode so that when GNU is being used to give hints these */
2837 /* menu options are still available */
2839 { "menuFile.Mail Move", False },
2840 { "menuFile.Reload CMail Message", False },
2844 Enables cmailEnables[] = {
2846 { "menuAction.Call Flag", False },
2847 { "menuAction.Draw", True },
2848 { "menuAction.Adjourn", False },
2849 { "menuAction.Abort", False },
2850 { "menuAction.Stop Observing", False },
2851 { "menuAction.Stop Examining", False },
2852 { "menuFile.Mail Move", True },
2853 { "menuFile.Reload CMail Message", True },
2857 Enables trainingOnEnables[] = {
2858 { "menuMode.Edit Comment", False },
2859 { "menuMode.Pause", False },
2860 { "menuEdit.Forward", False },
2861 { "menuEdit.Backward", False },
2862 { "menuEdit.Forward to End", False },
2863 { "menuEdit.Back to Start", False },
2864 { "menuEngine.Move Now", False },
2865 { "menuEdit.Truncate Game", False },
2869 Enables trainingOffEnables[] = {
2870 { "menuMode.Edit Comment", True },
2871 { "menuMode.Pause", True },
2872 { "menuEdit.Forward", True },
2873 { "menuEdit.Backward", True },
2874 { "menuEdit.Forward to End", True },
2875 { "menuEdit.Back to Start", True },
2876 { "menuEngine.Move Now", True },
2877 { "menuEdit.Truncate Game", True },
2881 Enables machineThinkingEnables[] = {
2882 { "menuFile.Load Game", False },
2883 // { "menuFile.Load Next Game", False },
2884 // { "menuFile.Load Previous Game", False },
2885 // { "menuFile.Reload Same Game", False },
2886 { "menuEdit.Paste Game", False },
2887 { "menuFile.Load Position", False },
2888 // { "menuFile.Load Next Position", False },
2889 // { "menuFile.Load Previous Position", False },
2890 // { "menuFile.Reload Same Position", False },
2891 { "menuEdit.Paste Position", False },
2892 { "menuMode.Machine White", False },
2893 { "menuMode.Machine Black", False },
2894 { "menuMode.Two Machines", False },
2895 { "menuEngine.Retract Move", False },
2899 Enables userThinkingEnables[] = {
2900 { "menuFile.Load Game", True },
2901 // { "menuFile.Load Next Game", True },
2902 // { "menuFile.Load Previous Game", True },
2903 // { "menuFile.Reload Same Game", True },
2904 { "menuEdit.Paste Game", True },
2905 { "menuFile.Load Position", True },
2906 // { "menuFile.Load Next Position", True },
2907 // { "menuFile.Load Previous Position", True },
2908 // { "menuFile.Reload Same Position", True },
2909 { "menuEdit.Paste Position", True },
2910 { "menuMode.Machine White", True },
2911 { "menuMode.Machine Black", True },
2912 { "menuMode.Two Machines", True },
2913 { "menuEngine.Retract Move", True },
2919 SetMenuEnables(icsEnables);
2922 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2923 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2930 SetMenuEnables(ncpEnables);
2936 SetMenuEnables(gnuEnables);
2942 SetMenuEnables(cmailEnables);
2948 SetMenuEnables(trainingOnEnables);
2949 if (appData.showButtonBar) {
2950 XtSetSensitive(buttonBarWidget, False);
2956 SetTrainingModeOff()
2958 SetMenuEnables(trainingOffEnables);
2959 if (appData.showButtonBar) {
2960 XtSetSensitive(buttonBarWidget, True);
2965 SetUserThinkingEnables()
2967 if (appData.noChessProgram) return;
2968 SetMenuEnables(userThinkingEnables);
2972 SetMachineThinkingEnables()
2974 if (appData.noChessProgram) return;
2975 SetMenuEnables(machineThinkingEnables);
2977 case MachinePlaysBlack:
2978 case MachinePlaysWhite:
2979 case TwoMachinesPlay:
2980 XtSetSensitive(XtNameToWidget(menuBarWidget,
2981 ModeToWidgetName(gameMode)), True);
2988 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2989 #define HISTORY_SIZE 64
\r
2990 static char *history[HISTORY_SIZE];
\r
2991 int histIn = 0, histP = 0;
\r
2994 SaveInHistory(char *cmd)
\r
2996 if (history[histIn] != NULL) {
\r
2997 free(history[histIn]);
\r
2998 history[histIn] = NULL;
\r
3000 if (*cmd == NULLCHAR) return;
\r
3001 history[histIn] = StrSave(cmd);
\r
3002 histIn = (histIn + 1) % HISTORY_SIZE;
\r
3003 if (history[histIn] != NULL) {
\r
3004 free(history[histIn]);
\r
3005 history[histIn] = NULL;
\r
3011 PrevInHistory(char *cmd)
\r
3014 if (histP == histIn) {
\r
3015 if (history[histIn] != NULL) free(history[histIn]);
\r
3016 history[histIn] = StrSave(cmd);
\r
3018 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
3019 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3021 return history[histP];
\r
3027 if (histP == histIn) return NULL;
\r
3028 histP = (histP + 1) % HISTORY_SIZE;
\r
3029 return history[histP];
\r
3031 // end of borrowed code
\r
3033 #define Abs(n) ((n)<0 ? -(n) : (n))
3036 * Find a font that matches "pattern" that is as close as
3037 * possible to the targetPxlSize. Prefer fonts that are k
3038 * pixels smaller to fonts that are k pixels larger. The
3039 * pattern must be in the X Consortium standard format,
3040 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3041 * The return value should be freed with XtFree when no
3045 FindFont(pattern, targetPxlSize)
3049 char **fonts, *p, *best, *scalable, *scalableTail;
3050 int i, j, nfonts, minerr, err, pxlSize;
3053 char **missing_list;
3055 char *def_string, *base_fnt_lst, strInt[3];
3057 XFontStruct **fnt_list;
3059 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3060 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3061 p = strstr(pattern, "--");
3062 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3063 strcat(base_fnt_lst, strInt);
3064 strcat(base_fnt_lst, strchr(p + 2, '-'));
3066 if ((fntSet = XCreateFontSet(xDisplay,
3070 &def_string)) == NULL) {
3072 fprintf(stderr, _("Unable to create font set.\n"));
3076 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3078 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3080 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3081 programName, pattern);
3089 for (i=0; i<nfonts; i++) {
3092 if (*p != '-') continue;
3094 if (*p == NULLCHAR) break;
3095 if (*p++ == '-') j++;
3097 if (j < 7) continue;
3100 scalable = fonts[i];
3103 err = pxlSize - targetPxlSize;
3104 if (Abs(err) < Abs(minerr) ||
3105 (minerr > 0 && err < 0 && -err == minerr)) {
3111 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3112 /* If the error is too big and there is a scalable font,
3113 use the scalable font. */
3114 int headlen = scalableTail - scalable;
3115 p = (char *) XtMalloc(strlen(scalable) + 10);
3116 while (isdigit(*scalableTail)) scalableTail++;
3117 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3119 p = (char *) XtMalloc(strlen(best) + 2);
3120 safeStrCpy(p, best, strlen(best)+1 );
3122 if (appData.debugMode) {
3123 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3124 pattern, targetPxlSize, p);
3127 if (missing_count > 0)
3128 XFreeStringList(missing_list);
3129 XFreeFontSet(xDisplay, fntSet);
3131 XFreeFontNames(fonts);
3138 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3139 | GCBackground | GCFunction | GCPlaneMask;
3140 XGCValues gc_values;
3143 gc_values.plane_mask = AllPlanes;
3144 gc_values.line_width = lineGap;
3145 gc_values.line_style = LineSolid;
3146 gc_values.function = GXcopy;
3148 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3149 gc_values.background = XBlackPixel(xDisplay, xScreen);
3150 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3152 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3153 gc_values.background = XWhitePixel(xDisplay, xScreen);
3154 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3155 XSetFont(xDisplay, coordGC, coordFontID);
3157 // [HGM] make font for holdings counts (white on black0
3158 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3159 gc_values.background = XBlackPixel(xDisplay, xScreen);
3160 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3161 XSetFont(xDisplay, countGC, countFontID);
3163 if (appData.monoMode) {
3164 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3165 gc_values.background = XWhitePixel(xDisplay, xScreen);
3166 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3168 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3169 gc_values.background = XBlackPixel(xDisplay, xScreen);
3170 lightSquareGC = wbPieceGC
3171 = XtGetGC(shellWidget, value_mask, &gc_values);
3173 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3174 gc_values.background = XWhitePixel(xDisplay, xScreen);
3175 darkSquareGC = bwPieceGC
3176 = XtGetGC(shellWidget, value_mask, &gc_values);
3178 if (DefaultDepth(xDisplay, xScreen) == 1) {
3179 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3180 gc_values.function = GXcopyInverted;
3181 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3182 gc_values.function = GXcopy;
3183 if (XBlackPixel(xDisplay, xScreen) == 1) {
3184 bwPieceGC = darkSquareGC;
3185 wbPieceGC = copyInvertedGC;
3187 bwPieceGC = copyInvertedGC;
3188 wbPieceGC = lightSquareGC;
3192 gc_values.foreground = highlightSquareColor;
3193 gc_values.background = highlightSquareColor;
3194 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3196 gc_values.foreground = premoveHighlightColor;
3197 gc_values.background = premoveHighlightColor;
3198 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3200 gc_values.foreground = lightSquareColor;
3201 gc_values.background = darkSquareColor;
3202 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3204 gc_values.foreground = darkSquareColor;
3205 gc_values.background = lightSquareColor;
3206 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3208 gc_values.foreground = jailSquareColor;
3209 gc_values.background = jailSquareColor;
3210 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3212 gc_values.foreground = whitePieceColor;
3213 gc_values.background = darkSquareColor;
3214 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3216 gc_values.foreground = whitePieceColor;
3217 gc_values.background = lightSquareColor;
3218 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3220 gc_values.foreground = whitePieceColor;
3221 gc_values.background = jailSquareColor;
3222 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3224 gc_values.foreground = blackPieceColor;
3225 gc_values.background = darkSquareColor;
3226 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3228 gc_values.foreground = blackPieceColor;
3229 gc_values.background = lightSquareColor;
3230 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3232 gc_values.foreground = blackPieceColor;
3233 gc_values.background = jailSquareColor;
3234 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3238 void loadXIM(xim, xmask, filename, dest, mask)
3251 fp = fopen(filename, "rb");
3253 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3260 for (y=0; y<h; ++y) {
3261 for (x=0; x<h; ++x) {
3266 XPutPixel(xim, x, y, blackPieceColor);
3268 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3271 XPutPixel(xim, x, y, darkSquareColor);
3273 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3276 XPutPixel(xim, x, y, whitePieceColor);
3278 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3281 XPutPixel(xim, x, y, lightSquareColor);
3283 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3289 /* create Pixmap of piece */
3290 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3292 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3295 /* create Pixmap of clipmask
3296 Note: We assume the white/black pieces have the same
3297 outline, so we make only 6 masks. This is okay
3298 since the XPM clipmask routines do the same. */
3300 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3302 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3305 /* now create the 1-bit version */
3306 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3309 values.foreground = 1;
3310 values.background = 0;
3312 /* Don't use XtGetGC, not read only */
3313 maskGC = XCreateGC(xDisplay, *mask,
3314 GCForeground | GCBackground, &values);
3315 XCopyPlane(xDisplay, temp, *mask, maskGC,
3316 0, 0, squareSize, squareSize, 0, 0, 1);
3317 XFreePixmap(xDisplay, temp);
3322 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3324 void CreateXIMPieces()
3329 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3334 /* The XSynchronize calls were copied from CreatePieces.
3335 Not sure if needed, but can't hurt */
3336 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3339 /* temp needed by loadXIM() */
3340 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3341 0, 0, ss, ss, AllPlanes, XYPixmap);
3343 if (strlen(appData.pixmapDirectory) == 0) {
3347 if (appData.monoMode) {
3348 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3352 fprintf(stderr, _("\nLoading XIMs...\n"));
3354 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3355 fprintf(stderr, "%d", piece+1);
3356 for (kind=0; kind<4; kind++) {
3357 fprintf(stderr, ".");
3358 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3359 ExpandPathName(appData.pixmapDirectory),
3360 piece <= (int) WhiteKing ? "" : "w",
3361 pieceBitmapNames[piece],
3363 ximPieceBitmap[kind][piece] =
3364 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3365 0, 0, ss, ss, AllPlanes, XYPixmap);
3366 if (appData.debugMode)
3367 fprintf(stderr, _("(File:%s:) "), buf);
3368 loadXIM(ximPieceBitmap[kind][piece],
3370 &(xpmPieceBitmap2[kind][piece]),
3371 &(ximMaskPm2[piece]));
3372 if(piece <= (int)WhiteKing)
3373 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3375 fprintf(stderr," ");
3377 /* Load light and dark squares */
3378 /* If the LSQ and DSQ pieces don't exist, we will
3379 draw them with solid squares. */
3380 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3381 if (access(buf, 0) != 0) {
3385 fprintf(stderr, _("light square "));
3387 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3388 0, 0, ss, ss, AllPlanes, XYPixmap);
3389 if (appData.debugMode)
3390 fprintf(stderr, _("(File:%s:) "), buf);
3392 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3393 fprintf(stderr, _("dark square "));
3394 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3395 ExpandPathName(appData.pixmapDirectory), ss);
3396 if (appData.debugMode)
3397 fprintf(stderr, _("(File:%s:) "), buf);
3399 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3400 0, 0, ss, ss, AllPlanes, XYPixmap);
3401 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3402 xpmJailSquare = xpmLightSquare;
3404 fprintf(stderr, _("Done.\n"));
3406 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3410 void CreateXPMBoard(char *s, int kind)
3414 if(s == NULL || *s == 0 || *s == '*') return;
3415 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3416 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3420 void CreateXPMPieces()
3424 u_int ss = squareSize;
3426 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3427 XpmColorSymbol symbols[4];
3429 /* The XSynchronize calls were copied from CreatePieces.
3430 Not sure if needed, but can't hurt */
3431 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3433 /* Setup translations so piece colors match square colors */
3434 symbols[0].name = "light_piece";
3435 symbols[0].value = appData.whitePieceColor;
3436 symbols[1].name = "dark_piece";
3437 symbols[1].value = appData.blackPieceColor;
3438 symbols[2].name = "light_square";
3439 symbols[2].value = appData.lightSquareColor;
3440 symbols[3].name = "dark_square";
3441 symbols[3].value = appData.darkSquareColor;
3443 attr.valuemask = XpmColorSymbols;
3444 attr.colorsymbols = symbols;
3445 attr.numsymbols = 4;
3447 if (appData.monoMode) {
3448 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3452 if (strlen(appData.pixmapDirectory) == 0) {
3453 XpmPieces* pieces = builtInXpms;
3456 while (pieces->size != squareSize && pieces->size) pieces++;
3457 if (!pieces->size) {
3458 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3461 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3462 for (kind=0; kind<4; kind++) {
3464 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3465 pieces->xpm[piece][kind],
3466 &(xpmPieceBitmap2[kind][piece]),
3467 NULL, &attr)) != 0) {
3468 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3472 if(piece <= (int) WhiteKing)
3473 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3477 xpmJailSquare = xpmLightSquare;
3481 fprintf(stderr, _("\nLoading XPMs...\n"));
3484 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3485 fprintf(stderr, "%d ", piece+1);
3486 for (kind=0; kind<4; kind++) {
3487 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3488 ExpandPathName(appData.pixmapDirectory),
3489 piece > (int) WhiteKing ? "w" : "",
3490 pieceBitmapNames[piece],
3492 if (appData.debugMode) {
3493 fprintf(stderr, _("(File:%s:) "), buf);
3495 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3496 &(xpmPieceBitmap2[kind][piece]),
3497 NULL, &attr)) != 0) {
3498 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3499 // [HGM] missing: read of unorthodox piece failed; substitute King.
3500 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3501 ExpandPathName(appData.pixmapDirectory),
3503 if (appData.debugMode) {
3504 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3506 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3507 &(xpmPieceBitmap2[kind][piece]),
3511 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3516 if(piece <= (int) WhiteKing)
3517 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3520 /* Load light and dark squares */
3521 /* If the LSQ and DSQ pieces don't exist, we will
3522 draw them with solid squares. */
3523 fprintf(stderr, _("light square "));
3524 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3525 if (access(buf, 0) != 0) {
3529 if (appData.debugMode)
3530 fprintf(stderr, _("(File:%s:) "), buf);
3532 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3533 &xpmLightSquare, NULL, &attr)) != 0) {
3534 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3537 fprintf(stderr, _("dark square "));
3538 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3539 ExpandPathName(appData.pixmapDirectory), ss);
3540 if (appData.debugMode) {
3541 fprintf(stderr, _("(File:%s:) "), buf);
3543 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3544 &xpmDarkSquare, NULL, &attr)) != 0) {
3545 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3549 xpmJailSquare = xpmLightSquare;
3550 fprintf(stderr, _("Done.\n"));
3552 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3555 #endif /* HAVE_LIBXPM */
3558 /* No built-in bitmaps */
3563 u_int ss = squareSize;
3565 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3568 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3569 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3570 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3571 pieceBitmapNames[piece],
3572 ss, kind == SOLID ? 's' : 'o');
3573 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3574 if(piece <= (int)WhiteKing)
3575 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3579 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3583 /* With built-in bitmaps */
3586 BuiltInBits* bib = builtInBits;
3589 u_int ss = squareSize;
3591 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3594 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3596 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3597 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3598 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3599 pieceBitmapNames[piece],
3600 ss, kind == SOLID ? 's' : 'o');
3601 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3602 bib->bits[kind][piece], ss, ss);
3603 if(piece <= (int)WhiteKing)
3604 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3608 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3613 void ReadBitmap(pm, name, bits, wreq, hreq)
3616 unsigned char bits[];
3622 char msg[MSG_SIZ], fullname[MSG_SIZ];
3624 if (*appData.bitmapDirectory != NULLCHAR) {
3625 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3626 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3627 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3628 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3629 &w, &h, pm, &x_hot, &y_hot);
3630 fprintf(stderr, "load %s\n", name);
3631 if (errcode != BitmapSuccess) {
3633 case BitmapOpenFailed:
3634 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3636 case BitmapFileInvalid:
3637 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3639 case BitmapNoMemory:
3640 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3644 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3648 fprintf(stderr, _("%s: %s...using built-in\n"),
3650 } else if (w != wreq || h != hreq) {
3652 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3653 programName, fullname, w, h, wreq, hreq);
3659 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3668 if (lineGap == 0) return;
3670 /* [HR] Split this into 2 loops for non-square boards. */
3672 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3673 gridSegments[i].x1 = 0;
3674 gridSegments[i].x2 =
3675 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3676 gridSegments[i].y1 = gridSegments[i].y2
3677 = lineGap / 2 + (i * (squareSize + lineGap));
3680 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3681 gridSegments[j + i].y1 = 0;
3682 gridSegments[j + i].y2 =
3683 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3684 gridSegments[j + i].x1 = gridSegments[j + i].x2
3685 = lineGap / 2 + (j * (squareSize + lineGap));
3689 static void MenuBarSelect(w, addr, index)
3694 XtActionProc proc = (XtActionProc) addr;
3696 (proc)(NULL, NULL, NULL, NULL);
3699 void CreateMenuBarPopup(parent, name, mb)
3709 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3712 XtSetArg(args[j], XtNleftMargin, 20); j++;
3713 XtSetArg(args[j], XtNrightMargin, 20); j++;
3715 while (mi->string != NULL) {
3716 if (strcmp(mi->string, "----") == 0) {
3717 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3720 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3721 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3723 XtAddCallback(entry, XtNcallback,
3724 (XtCallbackProc) MenuBarSelect,
3725 (caddr_t) mi->proc);
3731 Widget CreateMenuBar(mb)
3735 Widget anchor, menuBar;
3737 char menuName[MSG_SIZ];
3740 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3741 XtSetArg(args[j], XtNvSpace, 0); j++;
3742 XtSetArg(args[j], XtNborderWidth, 0); j++;
3743 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3744 formWidget, args, j);
3746 while (mb->name != NULL) {
3747 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3748 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3750 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3753 shortName[0] = _(mb->name)[0];
3754 shortName[1] = NULLCHAR;
3755 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3758 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3761 XtSetArg(args[j], XtNborderWidth, 0); j++;
3762 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3764 CreateMenuBarPopup(menuBar, menuName, mb);
3770 Widget CreateButtonBar(mi)
3774 Widget button, buttonBar;
3778 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3780 XtSetArg(args[j], XtNhSpace, 0); j++;
3782 XtSetArg(args[j], XtNborderWidth, 0); j++;
3783 XtSetArg(args[j], XtNvSpace, 0); j++;
3784 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3785 formWidget, args, j);
3787 while (mi->string != NULL) {
3790 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3791 XtSetArg(args[j], XtNborderWidth, 0); j++;
3793 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3794 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3795 buttonBar, args, j);
3796 XtAddCallback(button, XtNcallback,
3797 (XtCallbackProc) MenuBarSelect,
3798 (caddr_t) mi->proc);
3805 CreatePieceMenu(name, color)
3812 ChessSquare selection;
3814 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3815 boardWidget, args, 0);
3817 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3818 String item = pieceMenuStrings[color][i];
3820 if (strcmp(item, "----") == 0) {
3821 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3824 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3825 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3827 selection = pieceMenuTranslation[color][i];
3828 XtAddCallback(entry, XtNcallback,
3829 (XtCallbackProc) PieceMenuSelect,
3830 (caddr_t) selection);
3831 if (selection == WhitePawn || selection == BlackPawn) {
3832 XtSetArg(args[0], XtNpopupOnEntry, entry);
3833 XtSetValues(menu, args, 1);
3846 ChessSquare selection;
3848 whitePieceMenu = CreatePieceMenu("menuW", 0);
3849 blackPieceMenu = CreatePieceMenu("menuB", 1);
3851 XtRegisterGrabAction(PieceMenuPopup, True,
3852 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3853 GrabModeAsync, GrabModeAsync);
3855 XtSetArg(args[0], XtNlabel, _("Drop"));
3856 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3857 boardWidget, args, 1);
3858 for (i = 0; i < DROP_MENU_SIZE; i++) {
3859 String item = dropMenuStrings[i];
3861 if (strcmp(item, "----") == 0) {
3862 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3865 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3866 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3868 selection = dropMenuTranslation[i];
3869 XtAddCallback(entry, XtNcallback,
3870 (XtCallbackProc) DropMenuSelect,
3871 (caddr_t) selection);
3876 void SetupDropMenu()
3884 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3885 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3886 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3887 dmEnables[i].piece);
3888 XtSetSensitive(entry, p != NULL || !appData.testLegality
3889 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3890 && !appData.icsActive));
3892 while (p && *p++ == dmEnables[i].piece) count++;
3893 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3895 XtSetArg(args[j], XtNlabel, label); j++;
3896 XtSetValues(entry, args, j);
3900 void PieceMenuPopup(w, event, params, num_params)
3904 Cardinal *num_params;
3906 String whichMenu; int menuNr;
3907 if (event->type == ButtonRelease)
3908 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3909 else if (event->type == ButtonPress)
3910 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3912 case 0: whichMenu = params[0]; break;
3913 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3915 case -1: if (errorUp) ErrorPopDown();
3918 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3921 static void PieceMenuSelect(w, piece, junk)
3926 if (pmFromX < 0 || pmFromY < 0) return;
3927 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3930 static void DropMenuSelect(w, piece, junk)
3935 if (pmFromX < 0 || pmFromY < 0) return;
3936 DropMenuEvent(piece, pmFromX, pmFromY);
3939 void WhiteClock(w, event, prms, nprms)
3945 if (gameMode == EditPosition || gameMode == IcsExamining) {
3946 SetWhiteToPlayEvent();
3947 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3952 void BlackClock(w, event, prms, nprms)
3958 if (gameMode == EditPosition || gameMode == IcsExamining) {
3959 SetBlackToPlayEvent();
3960 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3967 * If the user selects on a border boundary, return -1; if off the board,
3968 * return -2. Otherwise map the event coordinate to the square.
3970 int EventToSquare(x, limit)
3978 if ((x % (squareSize + lineGap)) >= squareSize)
3980 x /= (squareSize + lineGap);
3986 static void do_flash_delay(msec)
3992 static void drawHighlight(file, rank, gc)
3998 if (lineGap == 0 || appData.blindfold) return;
4001 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4002 (squareSize + lineGap);
4003 y = lineGap/2 + rank * (squareSize + lineGap);
4005 x = lineGap/2 + file * (squareSize + lineGap);
4006 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4007 (squareSize + lineGap);
4010 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4011 squareSize+lineGap, squareSize+lineGap);
4014 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4015 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4018 SetHighlights(fromX, fromY, toX, toY)
4019 int fromX, fromY, toX, toY;
4021 if (hi1X != fromX || hi1Y != fromY) {
4022 if (hi1X >= 0 && hi1Y >= 0) {
4023 drawHighlight(hi1X, hi1Y, lineGC);
4025 } // [HGM] first erase both, then draw new!
4026 if (hi2X != toX || hi2Y != toY) {
4027 if (hi2X >= 0 && hi2Y >= 0) {
4028 drawHighlight(hi2X, hi2Y, lineGC);
4031 if (hi1X != fromX || hi1Y != fromY) {
4032 if (fromX >= 0 && fromY >= 0) {
4033 drawHighlight(fromX, fromY, highlineGC);
4036 if (hi2X != toX || hi2Y != toY) {
4037 if (toX >= 0 && toY >= 0) {
4038 drawHighlight(toX, toY, highlineGC);
4050 SetHighlights(-1, -1, -1, -1);
4055 SetPremoveHighlights(fromX, fromY, toX, toY)
4056 int fromX, fromY, toX, toY;
4058 if (pm1X != fromX || pm1Y != fromY) {
4059 if (pm1X >= 0 && pm1Y >= 0) {
4060 drawHighlight(pm1X, pm1Y, lineGC);
4062 if (fromX >= 0 && fromY >= 0) {
4063 drawHighlight(fromX, fromY, prelineGC);
4066 if (pm2X != toX || pm2Y != toY) {
4067 if (pm2X >= 0 && pm2Y >= 0) {
4068 drawHighlight(pm2X, pm2Y, lineGC);
4070 if (toX >= 0 && toY >= 0) {
4071 drawHighlight(toX, toY, prelineGC);
4081 ClearPremoveHighlights()
4083 SetPremoveHighlights(-1, -1, -1, -1);
4086 static int CutOutSquare(x, y, x0, y0, kind)
4087 int x, y, *x0, *y0, kind;
4089 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4090 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4092 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4093 if(textureW[kind] < W*squareSize)
4094 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4096 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4097 if(textureH[kind] < H*squareSize)
4098 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4100 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4104 static void BlankSquare(x, y, color, piece, dest, fac)
4105 int x, y, color, fac;
4108 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4110 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4111 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4112 squareSize, squareSize, x*fac, y*fac);
4114 if (useImages && useImageSqs) {
4118 pm = xpmLightSquare;
4123 case 2: /* neutral */
4128 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4129 squareSize, squareSize, x*fac, y*fac);
4139 case 2: /* neutral */
4144 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4149 I split out the routines to draw a piece so that I could
4150 make a generic flash routine.
4152 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4154 int square_color, x, y;
4157 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4158 switch (square_color) {
4160 case 2: /* neutral */
4162 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4163 ? *pieceToOutline(piece)
4164 : *pieceToSolid(piece),
4165 dest, bwPieceGC, 0, 0,
4166 squareSize, squareSize, x, y);
4169 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4170 ? *pieceToSolid(piece)
4171 : *pieceToOutline(piece),
4172 dest, wbPieceGC, 0, 0,
4173 squareSize, squareSize, x, y);
4178 static void monoDrawPiece(piece, square_color, x, y, dest)
4180 int square_color, x, y;
4183 switch (square_color) {
4185 case 2: /* neutral */
4187 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4188 ? *pieceToOutline(piece)
4189 : *pieceToSolid(piece),
4190 dest, bwPieceGC, 0, 0,
4191 squareSize, squareSize, x, y, 1);
4194 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4195 ? *pieceToSolid(piece)
4196 : *pieceToOutline(piece),
4197 dest, wbPieceGC, 0, 0,
4198 squareSize, squareSize, x, y, 1);
4203 static void colorDrawPiece(piece, square_color, x, y, dest)
4205 int square_color, x, y;
4208 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4209 switch (square_color) {
4211 XCopyPlane(xDisplay, *pieceToSolid(piece),
4212 dest, (int) piece < (int) BlackPawn
4213 ? wlPieceGC : blPieceGC, 0, 0,
4214 squareSize, squareSize, x, y, 1);
4217 XCopyPlane(xDisplay, *pieceToSolid(piece),
4218 dest, (int) piece < (int) BlackPawn
4219 ? wdPieceGC : bdPieceGC, 0, 0,
4220 squareSize, squareSize, x, y, 1);
4222 case 2: /* neutral */
4224 XCopyPlane(xDisplay, *pieceToSolid(piece),
4225 dest, (int) piece < (int) BlackPawn
4226 ? wjPieceGC : bjPieceGC, 0, 0,
4227 squareSize, squareSize, x, y, 1);
4232 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4234 int square_color, x, y;
4237 int kind, p = piece;
4239 switch (square_color) {
4241 case 2: /* neutral */
4243 if ((int)piece < (int) BlackPawn) {
4251 if ((int)piece < (int) BlackPawn) {
4259 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4260 if(useTexture & square_color+1) {
4261 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4262 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4263 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4264 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4265 XSetClipMask(xDisplay, wlPieceGC, None);
4266 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4268 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4269 dest, wlPieceGC, 0, 0,
4270 squareSize, squareSize, x, y);
4273 typedef void (*DrawFunc)();
4275 DrawFunc ChooseDrawFunc()
4277 if (appData.monoMode) {
4278 if (DefaultDepth(xDisplay, xScreen) == 1) {
4279 return monoDrawPiece_1bit;
4281 return monoDrawPiece;
4285 return colorDrawPieceImage;
4287 return colorDrawPiece;
4291 /* [HR] determine square color depending on chess variant. */
4292 static int SquareColor(row, column)
4297 if (gameInfo.variant == VariantXiangqi) {
4298 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4300 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4302 } else if (row <= 4) {
4308 square_color = ((column + row) % 2) == 1;
4311 /* [hgm] holdings: next line makes all holdings squares light */
4312 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4314 return square_color;
4317 void DrawSquare(row, column, piece, do_flash)
4318 int row, column, do_flash;
4321 int square_color, x, y, direction, font_ascent, font_descent;
4324 XCharStruct overall;
4328 /* Calculate delay in milliseconds (2-delays per complete flash) */
4329 flash_delay = 500 / appData.flashRate;
4332 x = lineGap + ((BOARD_WIDTH-1)-column) *
4333 (squareSize + lineGap);
4334 y = lineGap + row * (squareSize + lineGap);
4336 x = lineGap + column * (squareSize + lineGap);
4337 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4338 (squareSize + lineGap);
4341 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4343 square_color = SquareColor(row, column);
4345 if ( // [HGM] holdings: blank out area between board and holdings
4346 column == BOARD_LEFT-1 || column == BOARD_RGHT
4347 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4348 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4349 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4351 // [HGM] print piece counts next to holdings
4352 string[1] = NULLCHAR;
4353 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4354 string[0] = '0' + piece;
4355 XTextExtents(countFontStruct, string, 1, &direction,
4356 &font_ascent, &font_descent, &overall);
4357 if (appData.monoMode) {
4358 XDrawImageString(xDisplay, xBoardWindow, countGC,
4359 x + squareSize - overall.width - 2,
4360 y + font_ascent + 1, string, 1);
4362 XDrawString(xDisplay, xBoardWindow, countGC,
4363 x + squareSize - overall.width - 2,
4364 y + font_ascent + 1, string, 1);
4367 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4368 string[0] = '0' + piece;
4369 XTextExtents(countFontStruct, string, 1, &direction,
4370 &font_ascent, &font_descent, &overall);
4371 if (appData.monoMode) {
4372 XDrawImageString(xDisplay, xBoardWindow, countGC,
4373 x + 2, y + font_ascent + 1, string, 1);
4375 XDrawString(xDisplay, xBoardWindow, countGC,
4376 x + 2, y + font_ascent + 1, string, 1);
4380 if (piece == EmptySquare || appData.blindfold) {
4381 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4383 drawfunc = ChooseDrawFunc();
4384 if (do_flash && appData.flashCount > 0) {
4385 for (i=0; i<appData.flashCount; ++i) {
4387 drawfunc(piece, square_color, x, y, xBoardWindow);
4388 XSync(xDisplay, False);
4389 do_flash_delay(flash_delay);
4391 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4392 XSync(xDisplay, False);
4393 do_flash_delay(flash_delay);
4396 drawfunc(piece, square_color, x, y, xBoardWindow);
4400 string[1] = NULLCHAR;
4401 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4402 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4403 string[0] = 'a' + column - BOARD_LEFT;
4404 XTextExtents(coordFontStruct, string, 1, &direction,
4405 &font_ascent, &font_descent, &overall);
4406 if (appData.monoMode) {
4407 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4408 x + squareSize - overall.width - 2,
4409 y + squareSize - font_descent - 1, string, 1);
4411 XDrawString(xDisplay, xBoardWindow, coordGC,
4412 x + squareSize - overall.width - 2,
4413 y + squareSize - font_descent - 1, string, 1);
4416 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4417 string[0] = ONE + row;
4418 XTextExtents(coordFontStruct, string, 1, &direction,
4419 &font_ascent, &font_descent, &overall);
4420 if (appData.monoMode) {
4421 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4422 x + 2, y + font_ascent + 1, string, 1);
4424 XDrawString(xDisplay, xBoardWindow, coordGC,
4425 x + 2, y + font_ascent + 1, string, 1);
4428 if(!partnerUp && marker[row][column]) {
4429 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4430 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4435 /* Why is this needed on some versions of X? */
4436 void EventProc(widget, unused, event)
4441 if (!XtIsRealized(widget))
4444 switch (event->type) {
4446 if (event->xexpose.count > 0) return; /* no clipping is done */
4447 XDrawPosition(widget, True, NULL);
4448 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4449 flipView = !flipView; partnerUp = !partnerUp;
4450 XDrawPosition(widget, True, NULL);
4451 flipView = !flipView; partnerUp = !partnerUp;
4455 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4462 void DrawPosition(fullRedraw, board)
4463 /*Boolean*/int fullRedraw;
4466 XDrawPosition(boardWidget, fullRedraw, board);
4469 /* Returns 1 if there are "too many" differences between b1 and b2
4470 (i.e. more than 1 move was made) */
4471 static int too_many_diffs(b1, b2)
4477 for (i=0; i<BOARD_HEIGHT; ++i) {
4478 for (j=0; j<BOARD_WIDTH; ++j) {
4479 if (b1[i][j] != b2[i][j]) {
4480 if (++c > 4) /* Castling causes 4 diffs */
4489 /* Matrix describing castling maneuvers */
4490 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4491 static int castling_matrix[4][5] = {
4492 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4493 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4494 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4495 { 7, 7, 4, 5, 6 } /* 0-0, black */
4498 /* Checks whether castling occurred. If it did, *rrow and *rcol
4499 are set to the destination (row,col) of the rook that moved.
4501 Returns 1 if castling occurred, 0 if not.
4503 Note: Only handles a max of 1 castling move, so be sure
4504 to call too_many_diffs() first.
4506 static int check_castle_draw(newb, oldb, rrow, rcol)
4513 /* For each type of castling... */
4514 for (i=0; i<4; ++i) {
4515 r = castling_matrix[i];
4517 /* Check the 4 squares involved in the castling move */
4519 for (j=1; j<=4; ++j) {
4520 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4527 /* All 4 changed, so it must be a castling move */
4536 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4537 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4539 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4542 void DrawSeekBackground( int left, int top, int right, int bottom )
4544 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4547 void DrawSeekText(char *buf, int x, int y)
4549 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4552 void DrawSeekDot(int x, int y, int colorNr)
4554 int square = colorNr & 0x80;
4557 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4559 XFillRectangle(xDisplay, xBoardWindow, color,
4560 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4562 XFillArc(xDisplay, xBoardWindow, color,
4563 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4566 static int damage[2][BOARD_RANKS][BOARD_FILES];
4569 * event handler for redrawing the board
4571 void XDrawPosition(w, repaint, board)
4573 /*Boolean*/int repaint;
4577 static int lastFlipView = 0;
4578 static int lastBoardValid[2] = {0, 0};
4579 static Board lastBoard[2];
4582 int nr = twoBoards*partnerUp;
4584 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4586 if (board == NULL) {
4587 if (!lastBoardValid[nr]) return;
4588 board = lastBoard[nr];
4590 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4591 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4592 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4597 * It would be simpler to clear the window with XClearWindow()
4598 * but this causes a very distracting flicker.
4601 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4603 /* If too much changes (begin observing new game, etc.), don't
4605 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4607 /* Special check for castling so we don't flash both the king
4608 and the rook (just flash the king). */
4610 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4611 /* Draw rook with NO flashing. King will be drawn flashing later */
4612 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4613 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4617 /* First pass -- Draw (newly) empty squares and repair damage.
4618 This prevents you from having a piece show up twice while it
4619 is flashing on its new square */
4620 for (i = 0; i < BOARD_HEIGHT; i++)
4621 for (j = 0; j < BOARD_WIDTH; j++)
4622 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4623 || damage[nr][i][j]) {
4624 DrawSquare(i, j, board[i][j], 0);
4625 damage[nr][i][j] = False;
4628 /* Second pass -- Draw piece(s) in new position and flash them */
4629 for (i = 0; i < BOARD_HEIGHT; i++)
4630 for (j = 0; j < BOARD_WIDTH; j++)
4631 if (board[i][j] != lastBoard[nr][i][j]) {
4632 DrawSquare(i, j, board[i][j], do_flash);
4636 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4637 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4638 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4640 for (i = 0; i < BOARD_HEIGHT; i++)
4641 for (j = 0; j < BOARD_WIDTH; j++) {
4642 DrawSquare(i, j, board[i][j], 0);
4643 damage[nr][i][j] = False;
4647 CopyBoard(lastBoard[nr], board);
4648 lastBoardValid[nr] = 1;
4649 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4650 lastFlipView = flipView;
4652 /* Draw highlights */
4653 if (pm1X >= 0 && pm1Y >= 0) {
4654 drawHighlight(pm1X, pm1Y, prelineGC);
4656 if (pm2X >= 0 && pm2Y >= 0) {
4657 drawHighlight(pm2X, pm2Y, prelineGC);
4659 if (hi1X >= 0 && hi1Y >= 0) {
4660 drawHighlight(hi1X, hi1Y, highlineGC);
4662 if (hi2X >= 0 && hi2Y >= 0) {
4663 drawHighlight(hi2X, hi2Y, highlineGC);
4666 /* If piece being dragged around board, must redraw that too */
4669 XSync(xDisplay, False);
4674 * event handler for redrawing the board
4676 void DrawPositionProc(w, event, prms, nprms)
4682 XDrawPosition(w, True, NULL);
4687 * event handler for parsing user moves
4689 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4690 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4691 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4692 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4693 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4694 // and at the end FinishMove() to perform the move after optional promotion popups.
4695 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4696 void HandleUserMove(w, event, prms, nprms)
4702 if (w != boardWidget || errorExitStatus != -1) return;
4703 if(nprms) shiftKey = !strcmp(prms[0], "1");
4706 if (event->type == ButtonPress) {
4707 XtPopdown(promotionShell);
4708 XtDestroyWidget(promotionShell);
4709 promotionUp = False;
4717 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4718 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4719 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4722 void AnimateUserMove (Widget w, XEvent * event,
4723 String * params, Cardinal * nParams)
4725 DragPieceMove(event->xmotion.x, event->xmotion.y);
4728 void HandlePV (Widget w, XEvent * event,
4729 String * params, Cardinal * nParams)
4730 { // [HGM] pv: walk PV
4731 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4734 Widget CommentCreate(name, text, mutable, callback, lines)
4736 int /*Boolean*/ mutable;
4737 XtCallbackProc callback;
4741 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4746 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4747 XtGetValues(boardWidget, args, j);
4750 XtSetArg(args[j], XtNresizable, True); j++;
4753 XtCreatePopupShell(name, topLevelShellWidgetClass,
4754 shellWidget, args, j);
4757 XtCreatePopupShell(name, transientShellWidgetClass,
4758 shellWidget, args, j);
4761 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4762 layoutArgs, XtNumber(layoutArgs));
4764 XtCreateManagedWidget("form", formWidgetClass, layout,
4765 formArgs, XtNumber(formArgs));
4769 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4770 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4772 XtSetArg(args[j], XtNstring, text); j++;
4773 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4774 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4775 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4776 XtSetArg(args[j], XtNright, XtChainRight); j++;
4777 XtSetArg(args[j], XtNresizable, True); j++;
4778 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4779 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4780 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4781 XtSetArg(args[j], XtNautoFill, True); j++;
4782 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4784 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4785 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4789 XtSetArg(args[j], XtNfromVert, edit); j++;
4790 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4791 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4792 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4793 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4795 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4796 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4799 XtSetArg(args[j], XtNfromVert, edit); j++;
4800 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4801 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4802 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4803 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4804 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4806 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4807 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4810 XtSetArg(args[j], XtNfromVert, edit); j++;
4811 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4812 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4813 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4814 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4815 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4817 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4818 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4821 XtSetArg(args[j], XtNfromVert, edit); j++;
4822 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4823 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4824 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4825 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4827 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4828 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4831 XtSetArg(args[j], XtNfromVert, edit); j++;
4832 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4833 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4834 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4835 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4836 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4838 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4839 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4842 XtRealizeWidget(shell);
4844 if (commentX == -1) {
4847 Dimension pw_height;
4848 Dimension ew_height;
4851 XtSetArg(args[j], XtNheight, &ew_height); j++;
4852 XtGetValues(edit, args, j);
4855 XtSetArg(args[j], XtNheight, &pw_height); j++;
4856 XtGetValues(shell, args, j);
4857 commentH = pw_height + (lines - 1) * ew_height;
4858 commentW = bw_width - 16;
4860 XSync(xDisplay, False);
4862 /* This code seems to tickle an X bug if it is executed too soon
4863 after xboard starts up. The coordinates get transformed as if
4864 the main window was positioned at (0, 0).
4866 XtTranslateCoords(shellWidget,
4867 (bw_width - commentW) / 2, 0 - commentH / 2,
4868 &commentX, &commentY);
4870 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4871 RootWindowOfScreen(XtScreen(shellWidget)),
4872 (bw_width - commentW) / 2, 0 - commentH / 2,
4877 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4880 if(wpComment.width > 0) {
4881 commentX = wpComment.x;
4882 commentY = wpComment.y;
4883 commentW = wpComment.width;
4884 commentH = wpComment.height;
4888 XtSetArg(args[j], XtNheight, commentH); j++;
4889 XtSetArg(args[j], XtNwidth, commentW); j++;
4890 XtSetArg(args[j], XtNx, commentX); j++;
4891 XtSetArg(args[j], XtNy, commentY); j++;
4892 XtSetValues(shell, args, j);
4893 XtSetKeyboardFocus(shell, edit);
4898 /* Used for analysis window and ICS input window */
4899 Widget MiscCreate(name, text, mutable, callback, lines)
4901 int /*Boolean*/ mutable;
4902 XtCallbackProc callback;
4906 Widget shell, layout, form, edit;
4908 Dimension bw_width, pw_height, ew_height, w, h;
4914 XtSetArg(args[j], XtNresizable, True); j++;
4917 XtCreatePopupShell(name, topLevelShellWidgetClass,
4918 shellWidget, args, j);
4921 XtCreatePopupShell(name, transientShellWidgetClass,
4922 shellWidget, args, j);
4925 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4926 layoutArgs, XtNumber(layoutArgs));
4928 XtCreateManagedWidget("form", formWidgetClass, layout,
4929 formArgs, XtNumber(formArgs));
4933 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4934 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4936 XtSetArg(args[j], XtNstring, text); j++;
4937 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4938 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4939 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4940 XtSetArg(args[j], XtNright, XtChainRight); j++;
4941 XtSetArg(args[j], XtNresizable, True); j++;
4942 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4943 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4944 XtSetArg(args[j], XtNautoFill, True); j++;
4945 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4947 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4949 XtRealizeWidget(shell);
4952 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4953 XtGetValues(boardWidget, args, j);
4956 XtSetArg(args[j], XtNheight, &ew_height); j++;
4957 XtGetValues(edit, args, j);
4960 XtSetArg(args[j], XtNheight, &pw_height); j++;
4961 XtGetValues(shell, args, j);
4962 h = pw_height + (lines - 1) * ew_height;
4965 XSync(xDisplay, False);
4967 /* This code seems to tickle an X bug if it is executed too soon
4968 after xboard starts up. The coordinates get transformed as if
4969 the main window was positioned at (0, 0).
4971 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4973 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4974 RootWindowOfScreen(XtScreen(shellWidget)),
4975 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4979 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4982 XtSetArg(args[j], XtNheight, h); j++;
4983 XtSetArg(args[j], XtNwidth, w); j++;
4984 XtSetArg(args[j], XtNx, x); j++;
4985 XtSetArg(args[j], XtNy, y); j++;
4986 XtSetValues(shell, args, j);
4992 static int savedIndex; /* gross that this is global */
4994 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4997 XawTextPosition index, dummy;
5000 XawTextGetSelectionPos(w, &index, &dummy);
5001 XtSetArg(arg, XtNstring, &val);
5002 XtGetValues(w, &arg, 1);
5003 ReplaceComment(savedIndex, val);
5004 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5005 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5008 void EditCommentPopUp(index, title, text)
5017 if (text == NULL) text = "";
5019 if (editShell == NULL) {
5021 CommentCreate(title, text, True, EditCommentCallback, 4);
5022 XtRealizeWidget(editShell);
5023 CatchDeleteWindow(editShell, "EditCommentPopDown");
5025 edit = XtNameToWidget(editShell, "*form.text");
5027 XtSetArg(args[j], XtNstring, text); j++;
5028 XtSetValues(edit, args, j);
5030 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5031 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5032 XtSetValues(editShell, args, j);
5035 XtPopup(editShell, XtGrabNone);
5039 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5040 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5042 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5046 void EditCommentCallback(w, client_data, call_data)
5048 XtPointer client_data, call_data;
5056 XtSetArg(args[j], XtNlabel, &name); j++;
5057 XtGetValues(w, args, j);
5059 if (strcmp(name, _("ok")) == 0) {
5060 edit = XtNameToWidget(editShell, "*form.text");
5062 XtSetArg(args[j], XtNstring, &val); j++;
5063 XtGetValues(edit, args, j);
5064 ReplaceComment(savedIndex, val);
5065 EditCommentPopDown();
5066 } else if (strcmp(name, _("cancel")) == 0) {
5067 EditCommentPopDown();
5068 } else if (strcmp(name, _("clear")) == 0) {
5069 edit = XtNameToWidget(editShell, "*form.text");
5070 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5071 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5075 void EditCommentPopDown()
5080 if (!editUp) return;
5082 XtSetArg(args[j], XtNx, &commentX); j++;
5083 XtSetArg(args[j], XtNy, &commentY); j++;
5084 XtSetArg(args[j], XtNheight, &commentH); j++;
5085 XtSetArg(args[j], XtNwidth, &commentW); j++;
5086 XtGetValues(editShell, args, j);
5087 XtPopdown(editShell);
5090 XtSetArg(args[j], XtNleftBitmap, None); j++;
5091 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5093 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5097 void ICSInputBoxPopUp()
5102 char *title = _("ICS Input");
5105 if (ICSInputShell == NULL) {
5106 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5107 tr = XtParseTranslationTable(ICSInputTranslations);
5108 edit = XtNameToWidget(ICSInputShell, "*form.text");
5109 XtOverrideTranslations(edit, tr);
5110 XtRealizeWidget(ICSInputShell);
5111 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5114 edit = XtNameToWidget(ICSInputShell, "*form.text");
5116 XtSetArg(args[j], XtNstring, ""); j++;
5117 XtSetValues(edit, args, j);
5119 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5120 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5121 XtSetValues(ICSInputShell, args, j);
5124 XtPopup(ICSInputShell, XtGrabNone);
5125 XtSetKeyboardFocus(ICSInputShell, edit);
5127 ICSInputBoxUp = True;
5129 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5130 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5134 void ICSInputSendText()
5141 edit = XtNameToWidget(ICSInputShell, "*form.text");
5143 XtSetArg(args[j], XtNstring, &val); j++;
5144 XtGetValues(edit, args, j);
5146 SendMultiLineToICS(val);
5147 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5148 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5151 void ICSInputBoxPopDown()
5156 if (!ICSInputBoxUp) return;
5158 XtPopdown(ICSInputShell);
5159 ICSInputBoxUp = False;
5161 XtSetArg(args[j], XtNleftBitmap, None); j++;
5162 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5166 void CommentPopUp(title, text)
5173 savedIndex = currentMove; // [HGM] vari
5174 if (commentShell == NULL) {
5176 CommentCreate(title, text, False, CommentCallback, 4);
5177 XtRealizeWidget(commentShell);
5178 CatchDeleteWindow(commentShell, "CommentPopDown");
5180 edit = XtNameToWidget(commentShell, "*form.text");
5182 XtSetArg(args[j], XtNstring, text); j++;
5183 XtSetValues(edit, args, j);
5185 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5186 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5187 XtSetValues(commentShell, args, j);
5190 XtPopup(commentShell, XtGrabNone);
5191 XSync(xDisplay, False);
5196 void CommentCallback(w, client_data, call_data)
5198 XtPointer client_data, call_data;
5205 XtSetArg(args[j], XtNlabel, &name); j++;
5206 XtGetValues(w, args, j);
5208 if (strcmp(name, _("close")) == 0) {
5210 } else if (strcmp(name, _("edit")) == 0) {
5217 void CommentPopDown()
5222 if (!commentUp) return;
5224 XtSetArg(args[j], XtNx, &commentX); j++;
5225 XtSetArg(args[j], XtNy, &commentY); j++;
5226 XtSetArg(args[j], XtNwidth, &commentW); j++;
5227 XtSetArg(args[j], XtNheight, &commentH); j++;
5228 XtGetValues(commentShell, args, j);
5229 XtPopdown(commentShell);
5230 XSync(xDisplay, False);
5234 void FileNamePopUp(label, def, proc, openMode)
5240 fileProc = proc; /* I can't see a way not */
5241 fileOpenMode = openMode; /* to use globals here */
5242 { // [HGM] use file-selector dialog stolen from Ghostview
5244 int index; // this is not supported yet
5246 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5247 def, openMode, NULL, &name))
5248 (void) (*fileProc)(f, index=0, name);
5252 void FileNamePopDown()
5254 if (!filenameUp) return;
5255 XtPopdown(fileNameShell);
5256 XtDestroyWidget(fileNameShell);
5261 void FileNameCallback(w, client_data, call_data)
5263 XtPointer client_data, call_data;
5268 XtSetArg(args[0], XtNlabel, &name);
5269 XtGetValues(w, args, 1);
5271 if (strcmp(name, _("cancel")) == 0) {
5276 FileNameAction(w, NULL, NULL, NULL);
5279 void FileNameAction(w, event, prms, nprms)
5291 name = XawDialogGetValueString(w = XtParent(w));
5293 if ((name != NULL) && (*name != NULLCHAR)) {
5294 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5295 XtPopdown(w = XtParent(XtParent(w)));
5299 p = strrchr(buf, ' ');
5306 fullname = ExpandPathName(buf);
5308 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5311 f = fopen(fullname, fileOpenMode);
5313 DisplayError(_("Failed to open file"), errno);
5315 (void) (*fileProc)(f, index, buf);
5322 XtPopdown(w = XtParent(XtParent(w)));
5328 void PromotionPopUp()
5331 Widget dialog, layout;
5333 Dimension bw_width, pw_width;
5337 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5338 XtGetValues(boardWidget, args, j);
5341 XtSetArg(args[j], XtNresizable, True); j++;
5342 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5344 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5345 shellWidget, args, j);
5347 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5348 layoutArgs, XtNumber(layoutArgs));
5351 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5352 XtSetArg(args[j], XtNborderWidth, 0); j++;
5353 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5356 if(gameInfo.variant != VariantShogi) {
5357 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5358 (XtPointer) dialog);
5359 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5360 (XtPointer) dialog);
5361 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5362 (XtPointer) dialog);
5363 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5364 (XtPointer) dialog);
5365 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5366 gameInfo.variant == VariantGiveaway) {
5367 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5368 (XtPointer) dialog);
5370 if(gameInfo.variant == VariantCapablanca ||
5371 gameInfo.variant == VariantGothic ||
5372 gameInfo.variant == VariantCapaRandom) {
5373 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5374 (XtPointer) dialog);
5375 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5376 (XtPointer) dialog);
5378 } else // [HGM] shogi
5380 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5381 (XtPointer) dialog);
5382 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5383 (XtPointer) dialog);
5385 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5386 (XtPointer) dialog);
5388 XtRealizeWidget(promotionShell);
5389 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5392 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5393 XtGetValues(promotionShell, args, j);
5395 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5396 lineGap + squareSize/3 +
5397 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5398 0 : 6*(squareSize + lineGap)), &x, &y);
5401 XtSetArg(args[j], XtNx, x); j++;
5402 XtSetArg(args[j], XtNy, y); j++;
5403 XtSetValues(promotionShell, args, j);
5405 XtPopup(promotionShell, XtGrabNone);
5410 void PromotionPopDown()
5412 if (!promotionUp) return;
5413 XtPopdown(promotionShell);
5414 XtDestroyWidget(promotionShell);
5415 promotionUp = False;
5418 void PromotionCallback(w, client_data, call_data)
5420 XtPointer client_data, call_data;
5426 XtSetArg(args[0], XtNlabel, &name);
5427 XtGetValues(w, args, 1);
5431 if (fromX == -1) return;
5433 if (strcmp(name, _("cancel")) == 0) {
5437 } else if (strcmp(name, _("Knight")) == 0) {
5439 } else if (strcmp(name, _("Promote")) == 0) {
5441 } else if (strcmp(name, _("Defer")) == 0) {
5444 promoChar = ToLower(name[0]);
5447 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5449 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5450 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5455 void ErrorCallback(w, client_data, call_data)
5457 XtPointer client_data, call_data;
5460 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5462 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5468 if (!errorUp) return;
5470 XtPopdown(errorShell);
5471 XtDestroyWidget(errorShell);
5472 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5475 void ErrorPopUp(title, label, modal)
5476 char *title, *label;
5480 Widget dialog, layout;
5484 Dimension bw_width, pw_width;
5485 Dimension pw_height;
5489 XtSetArg(args[i], XtNresizable, True); i++;
5490 XtSetArg(args[i], XtNtitle, title); i++;
5492 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5493 shellWidget, args, i);
5495 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5496 layoutArgs, XtNumber(layoutArgs));
5499 XtSetArg(args[i], XtNlabel, label); i++;
5500 XtSetArg(args[i], XtNborderWidth, 0); i++;
5501 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5504 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5506 XtRealizeWidget(errorShell);
5507 CatchDeleteWindow(errorShell, "ErrorPopDown");
5510 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5511 XtGetValues(boardWidget, args, i);
5513 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5514 XtSetArg(args[i], XtNheight, &pw_height); i++;
5515 XtGetValues(errorShell, args, i);
5518 /* This code seems to tickle an X bug if it is executed too soon
5519 after xboard starts up. The coordinates get transformed as if
5520 the main window was positioned at (0, 0).
5522 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5523 0 - pw_height + squareSize / 3, &x, &y);
5525 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5526 RootWindowOfScreen(XtScreen(boardWidget)),
5527 (bw_width - pw_width) / 2,
5528 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5532 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5535 XtSetArg(args[i], XtNx, x); i++;
5536 XtSetArg(args[i], XtNy, y); i++;
5537 XtSetValues(errorShell, args, i);
5540 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5543 /* Disable all user input other than deleting the window */
5544 static int frozen = 0;
5548 /* Grab by a widget that doesn't accept input */
5549 XtAddGrab(messageWidget, TRUE, FALSE);
5553 /* Undo a FreezeUI */
5556 if (!frozen) return;
5557 XtRemoveGrab(messageWidget);
5561 char *ModeToWidgetName(mode)
5565 case BeginningOfGame:
5566 if (appData.icsActive)
5567 return "menuMode.ICS Client";
5568 else if (appData.noChessProgram ||
5569 *appData.cmailGameName != NULLCHAR)
5570 return "menuMode.Edit Game";
5572 return "menuMode.Machine Black";
5573 case MachinePlaysBlack:
5574 return "menuMode.Machine Black";
5575 case MachinePlaysWhite:
5576 return "menuMode.Machine White";
5578 return "menuMode.Analysis Mode";
5580 return "menuMode.Analyze File";
5581 case TwoMachinesPlay:
5582 return "menuMode.Two Machines";
5584 return "menuMode.Edit Game";
5585 case PlayFromGameFile:
5586 return "menuFile.Load Game";
5588 return "menuMode.Edit Position";
5590 return "menuMode.Training";
5591 case IcsPlayingWhite:
5592 case IcsPlayingBlack:
5596 return "menuMode.ICS Client";
5603 void ModeHighlight()
5606 static int oldPausing = FALSE;
5607 static GameMode oldmode = (GameMode) -1;
5610 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5612 if (pausing != oldPausing) {
5613 oldPausing = pausing;
5615 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5617 XtSetArg(args[0], XtNleftBitmap, None);
5619 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5622 if (appData.showButtonBar) {
5623 /* Always toggle, don't set. Previous code messes up when
5624 invoked while the button is pressed, as releasing it
5625 toggles the state again. */
5628 XtSetArg(args[0], XtNbackground, &oldbg);
5629 XtSetArg(args[1], XtNforeground, &oldfg);
5630 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5632 XtSetArg(args[0], XtNbackground, oldfg);
5633 XtSetArg(args[1], XtNforeground, oldbg);
5635 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5639 wname = ModeToWidgetName(oldmode);
5640 if (wname != NULL) {
5641 XtSetArg(args[0], XtNleftBitmap, None);
5642 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5644 wname = ModeToWidgetName(gameMode);
5645 if (wname != NULL) {
5646 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5647 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5651 /* Maybe all the enables should be handled here, not just this one */
5652 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5653 gameMode == Training || gameMode == PlayFromGameFile);
5658 * Button/menu procedures
5660 void ResetProc(w, event, prms, nprms)
5669 int LoadGamePopUp(f, gameNumber, title)
5674 cmailMsgLoaded = FALSE;
5675 if (gameNumber == 0) {
5676 int error = GameListBuild(f);
5678 DisplayError(_("Cannot build game list"), error);
5679 } else if (!ListEmpty(&gameList) &&
5680 ((ListGame *) gameList.tailPred)->number > 1) {
5681 GameListPopUp(f, title);
5687 return LoadGame(f, gameNumber, title, FALSE);
5690 void LoadGameProc(w, event, prms, nprms)
5696 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5699 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5702 void LoadNextGameProc(w, event, prms, nprms)
5711 void LoadPrevGameProc(w, event, prms, nprms)
5720 void ReloadGameProc(w, event, prms, nprms)
5729 void LoadNextPositionProc(w, event, prms, nprms)
5738 void LoadPrevPositionProc(w, event, prms, nprms)
5747 void ReloadPositionProc(w, event, prms, nprms)
5756 void LoadPositionProc(w, event, prms, nprms)
5762 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5765 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5768 void SaveGameProc(w, event, prms, nprms)
5774 FileNamePopUp(_("Save game file name?"),
5775 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5779 void SavePositionProc(w, event, prms, nprms)
5785 FileNamePopUp(_("Save position file name?"),
5786 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5790 void ReloadCmailMsgProc(w, event, prms, nprms)
5796 ReloadCmailMsgEvent(FALSE);
5799 void MailMoveProc(w, event, prms, nprms)
5808 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5809 char *selected_fen_position=NULL;
5812 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5813 Atom *type_return, XtPointer *value_return,
5814 unsigned long *length_return, int *format_return)
5816 char *selection_tmp;
5818 if (!selected_fen_position) return False; /* should never happen */
5819 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5820 /* note: since no XtSelectionDoneProc was registered, Xt will
5821 * automatically call XtFree on the value returned. So have to
5822 * make a copy of it allocated with XtMalloc */
5823 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5824 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5826 *value_return=selection_tmp;
5827 *length_return=strlen(selection_tmp);
5828 *type_return=*target;
5829 *format_return = 8; /* bits per byte */
5831 } else if (*target == XA_TARGETS(xDisplay)) {
5832 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5833 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5834 targets_tmp[1] = XA_STRING;
5835 *value_return = targets_tmp;
5836 *type_return = XA_ATOM;
5838 *format_return = 8 * sizeof(Atom);
5839 if (*format_return > 32) {
5840 *length_return *= *format_return / 32;
5841 *format_return = 32;
5849 /* note: when called from menu all parameters are NULL, so no clue what the
5850 * Widget which was clicked on was, or what the click event was
5852 void CopyPositionProc(w, event, prms, nprms)
5859 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5860 * have a notion of a position that is selected but not copied.
5861 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5863 if(gameMode == EditPosition) EditPositionDone(TRUE);
5864 if (selected_fen_position) free(selected_fen_position);
5865 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5866 if (!selected_fen_position) return;
5867 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5869 SendPositionSelection,
5870 NULL/* lose_ownership_proc */ ,
5871 NULL/* transfer_done_proc */);
5872 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5874 SendPositionSelection,
5875 NULL/* lose_ownership_proc */ ,
5876 NULL/* transfer_done_proc */);
5879 /* function called when the data to Paste is ready */
5881 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5882 Atom *type, XtPointer value, unsigned long *len, int *format)
5885 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5886 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5887 EditPositionPasteFEN(fenstr);
5891 /* called when Paste Position button is pressed,
5892 * all parameters will be NULL */
5893 void PastePositionProc(w, event, prms, nprms)
5899 XtGetSelectionValue(menuBarWidget,
5900 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5901 /* (XtSelectionCallbackProc) */ PastePositionCB,
5902 NULL, /* client_data passed to PastePositionCB */
5904 /* better to use the time field from the event that triggered the
5905 * call to this function, but that isn't trivial to get
5913 SendGameSelection(Widget w, Atom *selection, Atom *target,
5914 Atom *type_return, XtPointer *value_return,
5915 unsigned long *length_return, int *format_return)
5917 char *selection_tmp;
5919 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5920 FILE* f = fopen(gameCopyFilename, "r");
5923 if (f == NULL) return False;
5927 selection_tmp = XtMalloc(len + 1);
5928 count = fread(selection_tmp, 1, len, f);
5930 XtFree(selection_tmp);
5933 selection_tmp[len] = NULLCHAR;
5934 *value_return = selection_tmp;
5935 *length_return = len;
5936 *type_return = *target;
5937 *format_return = 8; /* bits per byte */
5939 } else if (*target == XA_TARGETS(xDisplay)) {
5940 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5941 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5942 targets_tmp[1] = XA_STRING;
5943 *value_return = targets_tmp;
5944 *type_return = XA_ATOM;
5946 *format_return = 8 * sizeof(Atom);
5947 if (*format_return > 32) {
5948 *length_return *= *format_return / 32;
5949 *format_return = 32;
5957 /* note: when called from menu all parameters are NULL, so no clue what the
5958 * Widget which was clicked on was, or what the click event was
5960 void CopyGameProc(w, event, prms, nprms)
5968 ret = SaveGameToFile(gameCopyFilename, FALSE);
5972 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5973 * have a notion of a game that is selected but not copied.
5974 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5976 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5979 NULL/* lose_ownership_proc */ ,
5980 NULL/* transfer_done_proc */);
5981 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5984 NULL/* lose_ownership_proc */ ,
5985 NULL/* transfer_done_proc */);
5988 /* function called when the data to Paste is ready */
5990 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5991 Atom *type, XtPointer value, unsigned long *len, int *format)
5994 if (value == NULL || *len == 0) {
5995 return; /* nothing had been selected to copy */
5997 f = fopen(gamePasteFilename, "w");
5999 DisplayError(_("Can't open temp file"), errno);
6002 fwrite(value, 1, *len, f);
6005 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6008 /* called when Paste Game button is pressed,
6009 * all parameters will be NULL */
6010 void PasteGameProc(w, event, prms, nprms)
6016 XtGetSelectionValue(menuBarWidget,
6017 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6018 /* (XtSelectionCallbackProc) */ PasteGameCB,
6019 NULL, /* client_data passed to PasteGameCB */
6021 /* better to use the time field from the event that triggered the
6022 * call to this function, but that isn't trivial to get
6032 SaveGameProc(NULL, NULL, NULL, NULL);
6036 void QuitProc(w, event, prms, nprms)
6045 void PauseProc(w, event, prms, nprms)
6055 void MachineBlackProc(w, event, prms, nprms)
6061 MachineBlackEvent();
6064 void MachineWhiteProc(w, event, prms, nprms)
6070 MachineWhiteEvent();
6073 void AnalyzeModeProc(w, event, prms, nprms)
6081 if (!first.analysisSupport) {
6082 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6083 DisplayError(buf, 0);
6086 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6087 if (appData.icsActive) {
6088 if (gameMode != IcsObserving) {
6089 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6090 DisplayError(buf, 0);
6092 if (appData.icsEngineAnalyze) {
6093 if (appData.debugMode)
6094 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6100 /* if enable, use want disable icsEngineAnalyze */
6101 if (appData.icsEngineAnalyze) {
6106 appData.icsEngineAnalyze = TRUE;
6107 if (appData.debugMode)
6108 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6110 if (!appData.showThinking)
6111 ShowThinkingProc(w,event,prms,nprms);
6116 void AnalyzeFileProc(w, event, prms, nprms)
6122 if (!first.analysisSupport) {
6124 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6125 DisplayError(buf, 0);
6130 if (!appData.showThinking)
6131 ShowThinkingProc(w,event,prms,nprms);
6134 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6135 AnalysisPeriodicEvent(1);
6138 void TwoMachinesProc(w, event, prms, nprms)
6147 void IcsClientProc(w, event, prms, nprms)
6156 void EditGameProc(w, event, prms, nprms)
6165 void EditPositionProc(w, event, prms, nprms)
6171 EditPositionEvent();
6174 void TrainingProc(w, event, prms, nprms)
6183 void EditCommentProc(w, event, prms, nprms)
6190 EditCommentPopDown();
6196 void IcsInputBoxProc(w, event, prms, nprms)
6202 if (ICSInputBoxUp) {
6203 ICSInputBoxPopDown();
6209 void AcceptProc(w, event, prms, nprms)
6218 void DeclineProc(w, event, prms, nprms)
6227 void RematchProc(w, event, prms, nprms)
6236 void CallFlagProc(w, event, prms, nprms)
6245 void DrawProc(w, event, prms, nprms)
6254 void AbortProc(w, event, prms, nprms)
6263 void AdjournProc(w, event, prms, nprms)
6272 void ResignProc(w, event, prms, nprms)
6281 void AdjuWhiteProc(w, event, prms, nprms)
6287 UserAdjudicationEvent(+1);
6290 void AdjuBlackProc(w, event, prms, nprms)
6296 UserAdjudicationEvent(-1);
6299 void AdjuDrawProc(w, event, prms, nprms)
6305 UserAdjudicationEvent(0);
6308 void EnterKeyProc(w, event, prms, nprms)
6314 if (ICSInputBoxUp == True)
6318 void UpKeyProc(w, event, prms, nprms)
6323 { // [HGM] input: let up-arrow recall previous line from history
6330 if (!ICSInputBoxUp) return;
6331 edit = XtNameToWidget(ICSInputShell, "*form.text");
6333 XtSetArg(args[j], XtNstring, &val); j++;
6334 XtGetValues(edit, args, j);
6335 val = PrevInHistory(val);
6336 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6337 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6339 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6340 XawTextReplace(edit, 0, 0, &t);
6341 XawTextSetInsertionPoint(edit, 9999);
6345 void DownKeyProc(w, event, prms, nprms)
6350 { // [HGM] input: let down-arrow recall next line from history
6355 if (!ICSInputBoxUp) return;
6356 edit = XtNameToWidget(ICSInputShell, "*form.text");
6357 val = NextInHistory();
6358 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6359 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6361 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6362 XawTextReplace(edit, 0, 0, &t);
6363 XawTextSetInsertionPoint(edit, 9999);
6367 void StopObservingProc(w, event, prms, nprms)
6373 StopObservingEvent();
6376 void StopExaminingProc(w, event, prms, nprms)
6382 StopExaminingEvent();
6385 void UploadProc(w, event, prms, nprms)
6395 void ForwardProc(w, event, prms, nprms)
6405 void BackwardProc(w, event, prms, nprms)
6414 void ToStartProc(w, event, prms, nprms)
6423 void ToEndProc(w, event, prms, nprms)
6432 void RevertProc(w, event, prms, nprms)
6441 void AnnotateProc(w, event, prms, nprms)
6450 void TruncateGameProc(w, event, prms, nprms)
6456 TruncateGameEvent();
6458 void RetractMoveProc(w, event, prms, nprms)
6467 void MoveNowProc(w, event, prms, nprms)
6477 void AlwaysQueenProc(w, event, prms, nprms)
6485 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6487 if (appData.alwaysPromoteToQueen) {
6488 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6490 XtSetArg(args[0], XtNleftBitmap, None);
6492 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6496 void AnimateDraggingProc(w, event, prms, nprms)
6504 appData.animateDragging = !appData.animateDragging;
6506 if (appData.animateDragging) {
6507 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6510 XtSetArg(args[0], XtNleftBitmap, None);
6512 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6516 void AnimateMovingProc(w, event, prms, nprms)
6524 appData.animate = !appData.animate;
6526 if (appData.animate) {
6527 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6530 XtSetArg(args[0], XtNleftBitmap, None);
6532 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6536 void AutocommProc(w, event, prms, nprms)
6544 appData.autoComment = !appData.autoComment;
6546 if (appData.autoComment) {
6547 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6549 XtSetArg(args[0], XtNleftBitmap, None);
6551 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6556 void AutoflagProc(w, event, prms, nprms)
6564 appData.autoCallFlag = !appData.autoCallFlag;
6566 if (appData.autoCallFlag) {
6567 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6569 XtSetArg(args[0], XtNleftBitmap, None);
6571 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6575 void AutoflipProc(w, event, prms, nprms)
6583 appData.autoFlipView = !appData.autoFlipView;
6585 if (appData.autoFlipView) {
6586 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6588 XtSetArg(args[0], XtNleftBitmap, None);
6590 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6594 void AutobsProc(w, event, prms, nprms)
6602 appData.autoObserve = !appData.autoObserve;
6604 if (appData.autoObserve) {
6605 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6607 XtSetArg(args[0], XtNleftBitmap, None);
6609 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6613 void AutoraiseProc(w, event, prms, nprms)
6621 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6623 if (appData.autoRaiseBoard) {
6624 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6626 XtSetArg(args[0], XtNleftBitmap, None);
6628 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6632 void AutosaveProc(w, event, prms, nprms)
6640 appData.autoSaveGames = !appData.autoSaveGames;
6642 if (appData.autoSaveGames) {
6643 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6645 XtSetArg(args[0], XtNleftBitmap, None);
6647 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6651 void BlindfoldProc(w, event, prms, nprms)
6659 appData.blindfold = !appData.blindfold;
6661 if (appData.blindfold) {
6662 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6664 XtSetArg(args[0], XtNleftBitmap, None);
6666 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6669 DrawPosition(True, NULL);
6672 void TestLegalityProc(w, event, prms, nprms)
6680 appData.testLegality = !appData.testLegality;
6682 if (appData.testLegality) {
6683 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6685 XtSetArg(args[0], XtNleftBitmap, None);
6687 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6692 void FlashMovesProc(w, event, prms, nprms)
6700 if (appData.flashCount == 0) {
6701 appData.flashCount = 3;
6703 appData.flashCount = -appData.flashCount;
6706 if (appData.flashCount > 0) {
6707 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6709 XtSetArg(args[0], XtNleftBitmap, None);
6711 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6715 void FlipViewProc(w, event, prms, nprms)
6721 flipView = !flipView;
6722 DrawPosition(True, NULL);
6725 void GetMoveListProc(w, event, prms, nprms)
6733 appData.getMoveList = !appData.getMoveList;
6735 if (appData.getMoveList) {
6736 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6739 XtSetArg(args[0], XtNleftBitmap, None);
6741 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6746 void HighlightDraggingProc(w, event, prms, nprms)
6754 appData.highlightDragging = !appData.highlightDragging;
6756 if (appData.highlightDragging) {
6757 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6759 XtSetArg(args[0], XtNleftBitmap, None);
6761 XtSetValues(XtNameToWidget(menuBarWidget,
6762 "menuOptions.Highlight Dragging"), args, 1);
6766 void HighlightLastMoveProc(w, event, prms, nprms)
6774 appData.highlightLastMove = !appData.highlightLastMove;
6776 if (appData.highlightLastMove) {
6777 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6779 XtSetArg(args[0], XtNleftBitmap, None);
6781 XtSetValues(XtNameToWidget(menuBarWidget,
6782 "menuOptions.Highlight Last Move"), args, 1);
6785 void IcsAlarmProc(w, event, prms, nprms)
6793 appData.icsAlarm = !appData.icsAlarm;
6795 if (appData.icsAlarm) {
6796 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6798 XtSetArg(args[0], XtNleftBitmap, None);
6800 XtSetValues(XtNameToWidget(menuBarWidget,
6801 "menuOptions.ICS Alarm"), args, 1);
6804 void MoveSoundProc(w, event, prms, nprms)
6812 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6814 if (appData.ringBellAfterMoves) {
6815 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6817 XtSetArg(args[0], XtNleftBitmap, None);
6819 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6824 void OldSaveStyleProc(w, event, prms, nprms)
6832 appData.oldSaveStyle = !appData.oldSaveStyle;
6834 if (appData.oldSaveStyle) {
6835 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6837 XtSetArg(args[0], XtNleftBitmap, None);
6839 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6843 void PeriodicUpdatesProc(w, event, prms, nprms)
6851 PeriodicUpdatesEvent(!appData.periodicUpdates);
6853 if (appData.periodicUpdates) {
6854 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6856 XtSetArg(args[0], XtNleftBitmap, None);
6858 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6862 void PonderNextMoveProc(w, event, prms, nprms)
6870 PonderNextMoveEvent(!appData.ponderNextMove);
6872 if (appData.ponderNextMove) {
6873 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6875 XtSetArg(args[0], XtNleftBitmap, None);
6877 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6881 void PopupExitMessageProc(w, event, prms, nprms)
6889 appData.popupExitMessage = !appData.popupExitMessage;
6891 if (appData.popupExitMessage) {
6892 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6894 XtSetArg(args[0], XtNleftBitmap, None);
6896 XtSetValues(XtNameToWidget(menuBarWidget,
6897 "menuOptions.Popup Exit Message"), args, 1);
6900 void PopupMoveErrorsProc(w, event, prms, nprms)
6908 appData.popupMoveErrors = !appData.popupMoveErrors;
6910 if (appData.popupMoveErrors) {
6911 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6913 XtSetArg(args[0], XtNleftBitmap, None);
6915 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6919 void PremoveProc(w, event, prms, nprms)
6927 appData.premove = !appData.premove;
6929 if (appData.premove) {
6930 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6932 XtSetArg(args[0], XtNleftBitmap, None);
6934 XtSetValues(XtNameToWidget(menuBarWidget,
6935 "menuOptions.Premove"), args, 1);
6938 void QuietPlayProc(w, event, prms, nprms)
6946 appData.quietPlay = !appData.quietPlay;
6948 if (appData.quietPlay) {
6949 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6951 XtSetArg(args[0], XtNleftBitmap, None);
6953 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6957 void ShowCoordsProc(w, event, prms, nprms)
6965 appData.showCoords = !appData.showCoords;
6967 if (appData.showCoords) {
6968 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6970 XtSetArg(args[0], XtNleftBitmap, None);
6972 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6975 DrawPosition(True, NULL);
6978 void ShowThinkingProc(w, event, prms, nprms)
6984 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6985 ShowThinkingEvent();
6988 void HideThinkingProc(w, event, prms, nprms)
6996 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6997 ShowThinkingEvent();
6999 if (appData.hideThinkingFromHuman) {
7000 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7002 XtSetArg(args[0], XtNleftBitmap, None);
7004 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
7008 void SaveOnExitProc(w, event, prms, nprms)
7016 saveSettingsOnExit = !saveSettingsOnExit;
7018 if (saveSettingsOnExit) {
7019 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7021 XtSetArg(args[0], XtNleftBitmap, None);
7023 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
7027 void SaveSettingsProc(w, event, prms, nprms)
7033 SaveSettings(settingsFileName);
7036 void InfoProc(w, event, prms, nprms)
7043 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
7048 void ManProc(w, event, prms, nprms)
7056 if (nprms && *nprms > 0)
7060 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7064 void HintProc(w, event, prms, nprms)
7073 void BookProc(w, event, prms, nprms)
7082 void AboutProc(w, event, prms, nprms)
7090 char *zippy = " (with Zippy code)";
7094 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7095 programVersion, zippy,
7096 "Copyright 1991 Digital Equipment Corporation",
7097 "Enhancements Copyright 1992-2009 Free Software Foundation",
7098 "Enhancements Copyright 2005 Alessandro Scotti",
7099 PACKAGE, " is free software and carries NO WARRANTY;",
7100 "see the file COPYING for more information.");
7101 ErrorPopUp(_("About XBoard"), buf, FALSE);
7104 void DebugProc(w, event, prms, nprms)
7110 appData.debugMode = !appData.debugMode;
7113 void AboutGameProc(w, event, prms, nprms)
7122 void NothingProc(w, event, prms, nprms)
7131 void Iconify(w, event, prms, nprms)
7140 XtSetArg(args[0], XtNiconic, True);
7141 XtSetValues(shellWidget, args, 1);
7144 void DisplayMessage(message, extMessage)
7145 char *message, *extMessage;
7147 /* display a message in the message widget */
7156 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7161 message = extMessage;
7165 /* need to test if messageWidget already exists, since this function
7166 can also be called during the startup, if for example a Xresource
7167 is not set up correctly */
7170 XtSetArg(arg, XtNlabel, message);
7171 XtSetValues(messageWidget, &arg, 1);
7177 void DisplayTitle(text)
7182 char title[MSG_SIZ];
7185 if (text == NULL) text = "";
7187 if (appData.titleInWindow) {
7189 XtSetArg(args[i], XtNlabel, text); i++;
7190 XtSetValues(titleWidget, args, i);
7193 if (*text != NULLCHAR) {
7194 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7195 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7196 } else if (appData.icsActive) {
7197 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7198 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7199 } else if (appData.cmailGameName[0] != NULLCHAR) {
7200 snprintf(icon, sizeof(icon), "%s", "CMail");
7201 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7203 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7204 } else if (gameInfo.variant == VariantGothic) {
7205 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7206 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7209 } else if (gameInfo.variant == VariantFalcon) {
7210 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7211 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7213 } else if (appData.noChessProgram) {
7214 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7215 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7217 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7218 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7221 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7222 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7223 XtSetValues(shellWidget, args, i);
7228 DisplayError(message, error)
7235 if (appData.debugMode || appData.matchMode) {
7236 fprintf(stderr, "%s: %s\n", programName, message);
7239 if (appData.debugMode || appData.matchMode) {
7240 fprintf(stderr, "%s: %s: %s\n",
7241 programName, message, strerror(error));
7243 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7246 ErrorPopUp(_("Error"), message, FALSE);
7250 void DisplayMoveError(message)
7255 DrawPosition(FALSE, NULL);
7256 if (appData.debugMode || appData.matchMode) {
7257 fprintf(stderr, "%s: %s\n", programName, message);
7259 if (appData.popupMoveErrors) {
7260 ErrorPopUp(_("Error"), message, FALSE);
7262 DisplayMessage(message, "");
7267 void DisplayFatalError(message, error, status)
7273 errorExitStatus = status;
7275 fprintf(stderr, "%s: %s\n", programName, message);
7277 fprintf(stderr, "%s: %s: %s\n",
7278 programName, message, strerror(error));
7279 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7282 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7283 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7289 void DisplayInformation(message)
7293 ErrorPopUp(_("Information"), message, TRUE);
7296 void DisplayNote(message)
7300 ErrorPopUp(_("Note"), message, FALSE);
7304 NullXErrorCheck(dpy, error_event)
7306 XErrorEvent *error_event;
7311 void DisplayIcsInteractionTitle(message)
7314 if (oldICSInteractionTitle == NULL) {
7315 /* Magic to find the old window title, adapted from vim */
7316 char *wina = getenv("WINDOWID");
7318 Window win = (Window) atoi(wina);
7319 Window root, parent, *children;
7320 unsigned int nchildren;
7321 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7323 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7324 if (!XQueryTree(xDisplay, win, &root, &parent,
7325 &children, &nchildren)) break;
7326 if (children) XFree((void *)children);
7327 if (parent == root || parent == 0) break;
7330 XSetErrorHandler(oldHandler);
7332 if (oldICSInteractionTitle == NULL) {
7333 oldICSInteractionTitle = "xterm";
7336 printf("\033]0;%s\007", message);
7340 char pendingReplyPrefix[MSG_SIZ];
7341 ProcRef pendingReplyPR;
7343 void AskQuestionProc(w, event, prms, nprms)
7350 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7354 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7357 void AskQuestionPopDown()
7359 if (!askQuestionUp) return;
7360 XtPopdown(askQuestionShell);
7361 XtDestroyWidget(askQuestionShell);
7362 askQuestionUp = False;
7365 void AskQuestionReplyAction(w, event, prms, nprms)
7375 reply = XawDialogGetValueString(w = XtParent(w));
7376 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7377 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7378 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7379 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7380 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7381 AskQuestionPopDown();
7383 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7386 void AskQuestionCallback(w, client_data, call_data)
7388 XtPointer client_data, call_data;
7393 XtSetArg(args[0], XtNlabel, &name);
7394 XtGetValues(w, args, 1);
7396 if (strcmp(name, _("cancel")) == 0) {
7397 AskQuestionPopDown();
7399 AskQuestionReplyAction(w, NULL, NULL, NULL);
7403 void AskQuestion(title, question, replyPrefix, pr)
7404 char *title, *question, *replyPrefix;
7408 Widget popup, layout, dialog, edit;
7414 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7415 pendingReplyPR = pr;
7418 XtSetArg(args[i], XtNresizable, True); i++;
7419 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7420 askQuestionShell = popup =
7421 XtCreatePopupShell(title, transientShellWidgetClass,
7422 shellWidget, args, i);
7425 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7426 layoutArgs, XtNumber(layoutArgs));
7429 XtSetArg(args[i], XtNlabel, question); i++;
7430 XtSetArg(args[i], XtNvalue, ""); i++;
7431 XtSetArg(args[i], XtNborderWidth, 0); i++;
7432 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7435 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7436 (XtPointer) dialog);
7437 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7438 (XtPointer) dialog);
7440 XtRealizeWidget(popup);
7441 CatchDeleteWindow(popup, "AskQuestionPopDown");
7443 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7444 &x, &y, &win_x, &win_y, &mask);
7446 XtSetArg(args[0], XtNx, x - 10);
7447 XtSetArg(args[1], XtNy, y - 30);
7448 XtSetValues(popup, args, 2);
7450 XtPopup(popup, XtGrabExclusive);
7451 askQuestionUp = True;
7453 edit = XtNameToWidget(dialog, "*value");
7454 XtSetKeyboardFocus(popup, edit);
7462 if (*name == NULLCHAR) {
7464 } else if (strcmp(name, "$") == 0) {
7465 putc(BELLCHAR, stderr);
7468 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7476 PlaySound(appData.soundMove);
7482 PlaySound(appData.soundIcsWin);
7488 PlaySound(appData.soundIcsLoss);
7494 PlaySound(appData.soundIcsDraw);
7498 PlayIcsUnfinishedSound()
7500 PlaySound(appData.soundIcsUnfinished);
7506 PlaySound(appData.soundIcsAlarm);
7512 system("stty echo");
7518 system("stty -echo");
7522 Colorize(cc, continuation)
7527 int count, outCount, error;
7529 if (textColors[(int)cc].bg > 0) {
7530 if (textColors[(int)cc].fg > 0) {
7531 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7532 textColors[(int)cc].fg, textColors[(int)cc].bg);
7534 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7535 textColors[(int)cc].bg);
7538 if (textColors[(int)cc].fg > 0) {
7539 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7540 textColors[(int)cc].fg);
7542 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7545 count = strlen(buf);
7546 outCount = OutputToProcess(NoProc, buf, count, &error);
7547 if (outCount < count) {
7548 DisplayFatalError(_("Error writing to display"), error, 1);
7551 if (continuation) return;
7554 PlaySound(appData.soundShout);
7557 PlaySound(appData.soundSShout);
7560 PlaySound(appData.soundChannel1);
7563 PlaySound(appData.soundChannel);
7566 PlaySound(appData.soundKibitz);
7569 PlaySound(appData.soundTell);
7571 case ColorChallenge:
7572 PlaySound(appData.soundChallenge);
7575 PlaySound(appData.soundRequest);
7578 PlaySound(appData.soundSeek);
7589 return getpwuid(getuid())->pw_name;
7593 ExpandPathName(path)
7596 static char static_buf[4*MSG_SIZ];
7597 char *d, *s, buf[4*MSG_SIZ];
7603 while (*s && isspace(*s))
7612 if (*(s+1) == '/') {
7613 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7617 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7618 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7619 pwd = getpwnam(buf);
7622 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7626 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7627 strcat(d, strchr(s+1, '/'));
7631 safeStrCpy(d, s, 4*MSG_SIZ );
7638 static char host_name[MSG_SIZ];
7640 #if HAVE_GETHOSTNAME
7641 gethostname(host_name, MSG_SIZ);
7643 #else /* not HAVE_GETHOSTNAME */
7644 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7645 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7647 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7649 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7650 #endif /* not HAVE_GETHOSTNAME */
7653 XtIntervalId delayedEventTimerXID = 0;
7654 DelayedEventCallback delayedEventCallback = 0;
7659 delayedEventTimerXID = 0;
7660 delayedEventCallback();
7664 ScheduleDelayedEvent(cb, millisec)
7665 DelayedEventCallback cb; long millisec;
7667 if(delayedEventTimerXID && delayedEventCallback == cb)
7668 // [HGM] alive: replace, rather than add or flush identical event
7669 XtRemoveTimeOut(delayedEventTimerXID);
7670 delayedEventCallback = cb;
7671 delayedEventTimerXID =
7672 XtAppAddTimeOut(appContext, millisec,
7673 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7676 DelayedEventCallback
7679 if (delayedEventTimerXID) {
7680 return delayedEventCallback;
7687 CancelDelayedEvent()
7689 if (delayedEventTimerXID) {
7690 XtRemoveTimeOut(delayedEventTimerXID);
7691 delayedEventTimerXID = 0;
7695 XtIntervalId loadGameTimerXID = 0;
7697 int LoadGameTimerRunning()
7699 return loadGameTimerXID != 0;
7702 int StopLoadGameTimer()
7704 if (loadGameTimerXID != 0) {
7705 XtRemoveTimeOut(loadGameTimerXID);
7706 loadGameTimerXID = 0;
7714 LoadGameTimerCallback(arg, id)
7718 loadGameTimerXID = 0;
7723 StartLoadGameTimer(millisec)
7727 XtAppAddTimeOut(appContext, millisec,
7728 (XtTimerCallbackProc) LoadGameTimerCallback,
7732 XtIntervalId analysisClockXID = 0;
7735 AnalysisClockCallback(arg, id)
7739 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7740 || appData.icsEngineAnalyze) { // [DM]
7741 AnalysisPeriodicEvent(0);
7742 StartAnalysisClock();
7747 StartAnalysisClock()
7750 XtAppAddTimeOut(appContext, 2000,
7751 (XtTimerCallbackProc) AnalysisClockCallback,
7755 XtIntervalId clockTimerXID = 0;
7757 int ClockTimerRunning()
7759 return clockTimerXID != 0;
7762 int StopClockTimer()
7764 if (clockTimerXID != 0) {
7765 XtRemoveTimeOut(clockTimerXID);
7774 ClockTimerCallback(arg, id)
7783 StartClockTimer(millisec)
7787 XtAppAddTimeOut(appContext, millisec,
7788 (XtTimerCallbackProc) ClockTimerCallback,
7793 DisplayTimerLabel(w, color, timer, highlight)
7802 /* check for low time warning */
7803 Pixel foregroundOrWarningColor = timerForegroundPixel;
7806 appData.lowTimeWarning &&
7807 (timer / 1000) < appData.icsAlarmTime)
7808 foregroundOrWarningColor = lowTimeWarningColor;
7810 if (appData.clockMode) {
7811 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7812 XtSetArg(args[0], XtNlabel, buf);
7814 snprintf(buf, MSG_SIZ, "%s ", color);
7815 XtSetArg(args[0], XtNlabel, buf);
7820 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7821 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7823 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7824 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7827 XtSetValues(w, args, 3);
7831 DisplayWhiteClock(timeRemaining, highlight)
7837 if(appData.noGUI) return;
7838 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7839 if (highlight && iconPixmap == bIconPixmap) {
7840 iconPixmap = wIconPixmap;
7841 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7842 XtSetValues(shellWidget, args, 1);
7847 DisplayBlackClock(timeRemaining, highlight)
7853 if(appData.noGUI) return;
7854 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7855 if (highlight && iconPixmap == wIconPixmap) {
7856 iconPixmap = bIconPixmap;
7857 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7858 XtSetValues(shellWidget, args, 1);
7876 int StartChildProcess(cmdLine, dir, pr)
7883 int to_prog[2], from_prog[2];
7887 if (appData.debugMode) {
7888 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7891 /* We do NOT feed the cmdLine to the shell; we just
7892 parse it into blank-separated arguments in the
7893 most simple-minded way possible.
7896 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7899 while(*p == ' ') p++;
7901 if(*p == '"' || *p == '\'')
7902 p = strchr(++argv[i-1], *p);
7903 else p = strchr(p, ' ');
7904 if (p == NULL) break;
7909 SetUpChildIO(to_prog, from_prog);
7911 if ((pid = fork()) == 0) {
7913 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7914 close(to_prog[1]); // first close the unused pipe ends
7915 close(from_prog[0]);
7916 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7917 dup2(from_prog[1], 1);
7918 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7919 close(from_prog[1]); // and closing again loses one of the pipes!
7920 if(fileno(stderr) >= 2) // better safe than sorry...
7921 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7923 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7928 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7930 execvp(argv[0], argv);
7932 /* If we get here, exec failed */
7937 /* Parent process */
7939 close(from_prog[1]);
7941 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7944 cp->fdFrom = from_prog[0];
7945 cp->fdTo = to_prog[1];
7950 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7951 static RETSIGTYPE AlarmCallBack(int n)
7957 DestroyChildProcess(pr, signalType)
7961 ChildProc *cp = (ChildProc *) pr;
7963 if (cp->kind != CPReal) return;
7965 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7966 signal(SIGALRM, AlarmCallBack);
7968 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7969 kill(cp->pid, SIGKILL); // kill it forcefully
7970 wait((int *) 0); // and wait again
7974 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7976 /* Process is exiting either because of the kill or because of
7977 a quit command sent by the backend; either way, wait for it to die.
7986 InterruptChildProcess(pr)
7989 ChildProc *cp = (ChildProc *) pr;
7991 if (cp->kind != CPReal) return;
7992 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7995 int OpenTelnet(host, port, pr)
8000 char cmdLine[MSG_SIZ];
8002 if (port[0] == NULLCHAR) {
8003 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
8005 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
8007 return StartChildProcess(cmdLine, "", pr);
8010 int OpenTCP(host, port, pr)
8016 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
8017 #else /* !OMIT_SOCKETS */
8019 struct sockaddr_in sa;
8021 unsigned short uport;
8024 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8028 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8029 sa.sin_family = AF_INET;
8030 sa.sin_addr.s_addr = INADDR_ANY;
8031 uport = (unsigned short) 0;
8032 sa.sin_port = htons(uport);
8033 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8037 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8038 if (!(hp = gethostbyname(host))) {
8040 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8041 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8042 hp->h_addrtype = AF_INET;
8044 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8045 hp->h_addr_list[0] = (char *) malloc(4);
8046 hp->h_addr_list[0][0] = b0;
8047 hp->h_addr_list[0][1] = b1;
8048 hp->h_addr_list[0][2] = b2;
8049 hp->h_addr_list[0][3] = b3;
8054 sa.sin_family = hp->h_addrtype;
8055 uport = (unsigned short) atoi(port);
8056 sa.sin_port = htons(uport);
8057 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8059 if (connect(s, (struct sockaddr *) &sa,
8060 sizeof(struct sockaddr_in)) < 0) {
8064 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8071 #endif /* !OMIT_SOCKETS */
8076 int OpenCommPort(name, pr)
8083 fd = open(name, 2, 0);
8084 if (fd < 0) return errno;
8086 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8096 int OpenLoopback(pr)
8102 SetUpChildIO(to, from);
8104 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8107 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8114 int OpenRcmd(host, user, cmd, pr)
8115 char *host, *user, *cmd;
8118 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8122 #define INPUT_SOURCE_BUF_SIZE 8192
8131 char buf[INPUT_SOURCE_BUF_SIZE];
8136 DoInputCallback(closure, source, xid)
8141 InputSource *is = (InputSource *) closure;
8146 if (is->lineByLine) {
8147 count = read(is->fd, is->unused,
8148 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8150 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8153 is->unused += count;
8155 while (p < is->unused) {
8156 q = memchr(p, '\n', is->unused - p);
8157 if (q == NULL) break;
8159 (is->func)(is, is->closure, p, q - p, 0);
8163 while (p < is->unused) {
8168 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8173 (is->func)(is, is->closure, is->buf, count, error);
8177 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8184 ChildProc *cp = (ChildProc *) pr;
8186 is = (InputSource *) calloc(1, sizeof(InputSource));
8187 is->lineByLine = lineByLine;
8191 is->fd = fileno(stdin);
8193 is->kind = cp->kind;
8194 is->fd = cp->fdFrom;
8197 is->unused = is->buf;
8200 is->xid = XtAppAddInput(appContext, is->fd,
8201 (XtPointer) (XtInputReadMask),
8202 (XtInputCallbackProc) DoInputCallback,
8204 is->closure = closure;
8205 return (InputSourceRef) is;
8209 RemoveInputSource(isr)
8212 InputSource *is = (InputSource *) isr;
8214 if (is->xid == 0) return;
8215 XtRemoveInput(is->xid);
8219 int OutputToProcess(pr, message, count, outError)
8225 static int line = 0;
8226 ChildProc *cp = (ChildProc *) pr;
8231 if (appData.noJoin || !appData.useInternalWrap)
8232 outCount = fwrite(message, 1, count, stdout);
8235 int width = get_term_width();
8236 int len = wrap(NULL, message, count, width, &line);
8237 char *msg = malloc(len);
8241 outCount = fwrite(message, 1, count, stdout);
8244 dbgchk = wrap(msg, message, count, width, &line);
8245 if (dbgchk != len && appData.debugMode)
8246 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8247 outCount = fwrite(msg, 1, dbgchk, stdout);
8253 outCount = write(cp->fdTo, message, count);
8263 /* Output message to process, with "ms" milliseconds of delay
8264 between each character. This is needed when sending the logon
8265 script to ICC, which for some reason doesn't like the
8266 instantaneous send. */
8267 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8274 ChildProc *cp = (ChildProc *) pr;
8279 r = write(cp->fdTo, message++, 1);
8292 /**** Animation code by Hugh Fisher, DCS, ANU.
8294 Known problem: if a window overlapping the board is
8295 moved away while a piece is being animated underneath,
8296 the newly exposed area won't be updated properly.
8297 I can live with this.
8299 Known problem: if you look carefully at the animation
8300 of pieces in mono mode, they are being drawn as solid
8301 shapes without interior detail while moving. Fixing
8302 this would be a major complication for minimal return.
8305 /* Masks for XPM pieces. Black and white pieces can have
8306 different shapes, but in the interest of retaining my
8307 sanity pieces must have the same outline on both light
8308 and dark squares, and all pieces must use the same
8309 background square colors/images. */
8311 static int xpmDone = 0;
8314 CreateAnimMasks (pieceDepth)
8321 unsigned long plane;
8324 /* Need a bitmap just to get a GC with right depth */
8325 buf = XCreatePixmap(xDisplay, xBoardWindow,
8327 values.foreground = 1;
8328 values.background = 0;
8329 /* Don't use XtGetGC, not read only */
8330 maskGC = XCreateGC(xDisplay, buf,
8331 GCForeground | GCBackground, &values);
8332 XFreePixmap(xDisplay, buf);
8334 buf = XCreatePixmap(xDisplay, xBoardWindow,
8335 squareSize, squareSize, pieceDepth);
8336 values.foreground = XBlackPixel(xDisplay, xScreen);
8337 values.background = XWhitePixel(xDisplay, xScreen);
8338 bufGC = XCreateGC(xDisplay, buf,
8339 GCForeground | GCBackground, &values);
8341 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8342 /* Begin with empty mask */
8343 if(!xpmDone) // [HGM] pieces: keep using existing
8344 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8345 squareSize, squareSize, 1);
8346 XSetFunction(xDisplay, maskGC, GXclear);
8347 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8348 0, 0, squareSize, squareSize);
8350 /* Take a copy of the piece */
8355 XSetFunction(xDisplay, bufGC, GXcopy);
8356 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8358 0, 0, squareSize, squareSize, 0, 0);
8360 /* XOR the background (light) over the piece */
8361 XSetFunction(xDisplay, bufGC, GXxor);
8363 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8364 0, 0, squareSize, squareSize, 0, 0);
8366 XSetForeground(xDisplay, bufGC, lightSquareColor);
8367 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8370 /* We now have an inverted piece image with the background
8371 erased. Construct mask by just selecting all the non-zero
8372 pixels - no need to reconstruct the original image. */
8373 XSetFunction(xDisplay, maskGC, GXor);
8375 /* Might be quicker to download an XImage and create bitmap
8376 data from it rather than this N copies per piece, but it
8377 only takes a fraction of a second and there is a much
8378 longer delay for loading the pieces. */
8379 for (n = 0; n < pieceDepth; n ++) {
8380 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8381 0, 0, squareSize, squareSize,
8387 XFreePixmap(xDisplay, buf);
8388 XFreeGC(xDisplay, bufGC);
8389 XFreeGC(xDisplay, maskGC);
8393 InitAnimState (anim, info)
8395 XWindowAttributes * info;
8400 /* Each buffer is square size, same depth as window */
8401 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8402 squareSize, squareSize, info->depth);
8403 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8404 squareSize, squareSize, info->depth);
8406 /* Create a plain GC for blitting */
8407 mask = GCForeground | GCBackground | GCFunction |
8408 GCPlaneMask | GCGraphicsExposures;
8409 values.foreground = XBlackPixel(xDisplay, xScreen);
8410 values.background = XWhitePixel(xDisplay, xScreen);
8411 values.function = GXcopy;
8412 values.plane_mask = AllPlanes;
8413 values.graphics_exposures = False;
8414 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8416 /* Piece will be copied from an existing context at
8417 the start of each new animation/drag. */
8418 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8420 /* Outline will be a read-only copy of an existing */
8421 anim->outlineGC = None;
8427 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8428 XWindowAttributes info;
8430 if (xpmDone && gameInfo.variant == old) return;
8431 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8432 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8434 InitAnimState(&game, &info);
8435 InitAnimState(&player, &info);
8437 /* For XPM pieces, we need bitmaps to use as masks. */
8439 CreateAnimMasks(info.depth);
8445 static Boolean frameWaiting;
8447 static RETSIGTYPE FrameAlarm (sig)
8450 frameWaiting = False;
8451 /* In case System-V style signals. Needed?? */
8452 signal(SIGALRM, FrameAlarm);
8459 struct itimerval delay;
8461 XSync(xDisplay, False);
8464 frameWaiting = True;
8465 signal(SIGALRM, FrameAlarm);
8466 delay.it_interval.tv_sec =
8467 delay.it_value.tv_sec = time / 1000;
8468 delay.it_interval.tv_usec =
8469 delay.it_value.tv_usec = (time % 1000) * 1000;
8470 setitimer(ITIMER_REAL, &delay, NULL);
8471 while (frameWaiting) pause();
8472 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8473 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8474 setitimer(ITIMER_REAL, &delay, NULL);
8484 XSync(xDisplay, False);
8486 usleep(time * 1000);
8491 /* Convert board position to corner of screen rect and color */
8494 ScreenSquare(column, row, pt, color)
8495 int column; int row; XPoint * pt; int * color;
8498 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8499 pt->y = lineGap + row * (squareSize + lineGap);
8501 pt->x = lineGap + column * (squareSize + lineGap);
8502 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8504 *color = SquareColor(row, column);
8507 /* Convert window coords to square */
8510 BoardSquare(x, y, column, row)
8511 int x; int y; int * column; int * row;
8513 *column = EventToSquare(x, BOARD_WIDTH);
8514 if (flipView && *column >= 0)
8515 *column = BOARD_WIDTH - 1 - *column;
8516 *row = EventToSquare(y, BOARD_HEIGHT);
8517 if (!flipView && *row >= 0)
8518 *row = BOARD_HEIGHT - 1 - *row;
8523 #undef Max /* just in case */
8525 #define Max(a, b) ((a) > (b) ? (a) : (b))
8526 #define Min(a, b) ((a) < (b) ? (a) : (b))
8529 SetRect(rect, x, y, width, height)
8530 XRectangle * rect; int x; int y; int width; int height;
8534 rect->width = width;
8535 rect->height = height;
8538 /* Test if two frames overlap. If they do, return
8539 intersection rect within old and location of
8540 that rect within new. */
8543 Intersect(old, new, size, area, pt)
8544 XPoint * old; XPoint * new;
8545 int size; XRectangle * area; XPoint * pt;
8547 if (old->x > new->x + size || new->x > old->x + size ||
8548 old->y > new->y + size || new->y > old->y + size) {
8551 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8552 size - abs(old->x - new->x), size - abs(old->y - new->y));
8553 pt->x = Max(old->x - new->x, 0);
8554 pt->y = Max(old->y - new->y, 0);
8559 /* For two overlapping frames, return the rect(s)
8560 in the old that do not intersect with the new. */
8563 CalcUpdateRects(old, new, size, update, nUpdates)
8564 XPoint * old; XPoint * new; int size;
8565 XRectangle update[]; int * nUpdates;
8569 /* If old = new (shouldn't happen) then nothing to draw */
8570 if (old->x == new->x && old->y == new->y) {
8574 /* Work out what bits overlap. Since we know the rects
8575 are the same size we don't need a full intersect calc. */
8577 /* Top or bottom edge? */
8578 if (new->y > old->y) {
8579 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8581 } else if (old->y > new->y) {
8582 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8583 size, old->y - new->y);
8586 /* Left or right edge - don't overlap any update calculated above. */
8587 if (new->x > old->x) {
8588 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8589 new->x - old->x, size - abs(new->y - old->y));
8591 } else if (old->x > new->x) {
8592 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8593 old->x - new->x, size - abs(new->y - old->y));
8600 /* Generate a series of frame coords from start->mid->finish.
8601 The movement rate doubles until the half way point is
8602 reached, then halves back down to the final destination,
8603 which gives a nice slow in/out effect. The algorithmn
8604 may seem to generate too many intermediates for short
8605 moves, but remember that the purpose is to attract the
8606 viewers attention to the piece about to be moved and
8607 then to where it ends up. Too few frames would be less
8611 Tween(start, mid, finish, factor, frames, nFrames)
8612 XPoint * start; XPoint * mid;
8613 XPoint * finish; int factor;
8614 XPoint frames[]; int * nFrames;
8616 int fraction, n, count;
8620 /* Slow in, stepping 1/16th, then 1/8th, ... */
8622 for (n = 0; n < factor; n++)
8624 for (n = 0; n < factor; n++) {
8625 frames[count].x = start->x + (mid->x - start->x) / fraction;
8626 frames[count].y = start->y + (mid->y - start->y) / fraction;
8628 fraction = fraction / 2;
8632 frames[count] = *mid;
8635 /* Slow out, stepping 1/2, then 1/4, ... */
8637 for (n = 0; n < factor; n++) {
8638 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8639 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8641 fraction = fraction * 2;
8646 /* Draw a piece on the screen without disturbing what's there */
8649 SelectGCMask(piece, clip, outline, mask)
8650 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8654 /* Bitmap for piece being moved. */
8655 if (appData.monoMode) {
8656 *mask = *pieceToSolid(piece);
8657 } else if (useImages) {
8659 *mask = xpmMask[piece];
8661 *mask = ximMaskPm[piece];
8664 *mask = *pieceToSolid(piece);
8667 /* GC for piece being moved. Square color doesn't matter, but
8668 since it gets modified we make a copy of the original. */
8670 if (appData.monoMode)
8675 if (appData.monoMode)
8680 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8682 /* Outline only used in mono mode and is not modified */
8684 *outline = bwPieceGC;
8686 *outline = wbPieceGC;
8690 OverlayPiece(piece, clip, outline, dest)
8691 ChessSquare piece; GC clip; GC outline; Drawable dest;
8696 /* Draw solid rectangle which will be clipped to shape of piece */
8697 XFillRectangle(xDisplay, dest, clip,
8698 0, 0, squareSize, squareSize);
8699 if (appData.monoMode)
8700 /* Also draw outline in contrasting color for black
8701 on black / white on white cases */
8702 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8703 0, 0, squareSize, squareSize, 0, 0, 1);
8705 /* Copy the piece */
8710 if(appData.upsideDown && flipView) kind ^= 2;
8711 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8713 0, 0, squareSize, squareSize,
8718 /* Animate the movement of a single piece */
8721 BeginAnimation(anim, piece, startColor, start)
8729 /* The old buffer is initialised with the start square (empty) */
8730 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8731 anim->prevFrame = *start;
8733 /* The piece will be drawn using its own bitmap as a matte */
8734 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8735 XSetClipMask(xDisplay, anim->pieceGC, mask);
8739 AnimationFrame(anim, frame, piece)
8744 XRectangle updates[4];
8749 /* Save what we are about to draw into the new buffer */
8750 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8751 frame->x, frame->y, squareSize, squareSize,
8754 /* Erase bits of the previous frame */
8755 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8756 /* Where the new frame overlapped the previous,
8757 the contents in newBuf are wrong. */
8758 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8759 overlap.x, overlap.y,
8760 overlap.width, overlap.height,
8762 /* Repaint the areas in the old that don't overlap new */
8763 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8764 for (i = 0; i < count; i++)
8765 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8766 updates[i].x - anim->prevFrame.x,
8767 updates[i].y - anim->prevFrame.y,
8768 updates[i].width, updates[i].height,
8769 updates[i].x, updates[i].y);
8771 /* Easy when no overlap */
8772 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8773 0, 0, squareSize, squareSize,
8774 anim->prevFrame.x, anim->prevFrame.y);
8777 /* Save this frame for next time round */
8778 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8779 0, 0, squareSize, squareSize,
8781 anim->prevFrame = *frame;
8783 /* Draw piece over original screen contents, not current,
8784 and copy entire rect. Wipes out overlapping piece images. */
8785 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8786 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8787 0, 0, squareSize, squareSize,
8788 frame->x, frame->y);
8792 EndAnimation (anim, finish)
8796 XRectangle updates[4];
8801 /* The main code will redraw the final square, so we
8802 only need to erase the bits that don't overlap. */
8803 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8804 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8805 for (i = 0; i < count; i++)
8806 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8807 updates[i].x - anim->prevFrame.x,
8808 updates[i].y - anim->prevFrame.y,
8809 updates[i].width, updates[i].height,
8810 updates[i].x, updates[i].y);
8812 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8813 0, 0, squareSize, squareSize,
8814 anim->prevFrame.x, anim->prevFrame.y);
8819 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8821 ChessSquare piece; int startColor;
8822 XPoint * start; XPoint * finish;
8823 XPoint frames[]; int nFrames;
8827 BeginAnimation(anim, piece, startColor, start);
8828 for (n = 0; n < nFrames; n++) {
8829 AnimationFrame(anim, &(frames[n]), piece);
8830 FrameDelay(appData.animSpeed);
8832 EndAnimation(anim, finish);
8836 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8839 ChessSquare piece = board[fromY][toY];
8840 board[fromY][toY] = EmptySquare;
8841 DrawPosition(FALSE, board);
8843 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8844 y = lineGap + toY * (squareSize + lineGap);
8846 x = lineGap + toX * (squareSize + lineGap);
8847 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8849 for(i=1; i<4*kFactor; i++) {
8850 int r = squareSize * 9 * i/(20*kFactor - 5);
8851 XFillArc(xDisplay, xBoardWindow, highlineGC,
8852 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8853 FrameDelay(appData.animSpeed);
8855 board[fromY][toY] = piece;
8858 /* Main control logic for deciding what to animate and how */
8861 AnimateMove(board, fromX, fromY, toX, toY)
8870 XPoint start, finish, mid;
8871 XPoint frames[kFactor * 2 + 1];
8872 int nFrames, startColor, endColor;
8874 /* Are we animating? */
8875 if (!appData.animate || appData.blindfold)
8878 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8879 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8880 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8882 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8883 piece = board[fromY][fromX];
8884 if (piece >= EmptySquare) return;
8889 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8892 if (appData.debugMode) {
8893 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8894 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8895 piece, fromX, fromY, toX, toY); }
8897 ScreenSquare(fromX, fromY, &start, &startColor);
8898 ScreenSquare(toX, toY, &finish, &endColor);
8901 /* Knight: make straight movement then diagonal */
8902 if (abs(toY - fromY) < abs(toX - fromX)) {
8903 mid.x = start.x + (finish.x - start.x) / 2;
8907 mid.y = start.y + (finish.y - start.y) / 2;
8910 mid.x = start.x + (finish.x - start.x) / 2;
8911 mid.y = start.y + (finish.y - start.y) / 2;
8914 /* Don't use as many frames for very short moves */
8915 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8916 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8918 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8919 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8920 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8922 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8923 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8926 /* Be sure end square is redrawn */
8927 damage[0][toY][toX] = True;
8931 DragPieceBegin(x, y)
8934 int boardX, boardY, color;
8937 /* Are we animating? */
8938 if (!appData.animateDragging || appData.blindfold)
8941 /* Figure out which square we start in and the
8942 mouse position relative to top left corner. */
8943 BoardSquare(x, y, &boardX, &boardY);
8944 player.startBoardX = boardX;
8945 player.startBoardY = boardY;
8946 ScreenSquare(boardX, boardY, &corner, &color);
8947 player.startSquare = corner;
8948 player.startColor = color;
8949 /* As soon as we start dragging, the piece will jump slightly to
8950 be centered over the mouse pointer. */
8951 player.mouseDelta.x = squareSize/2;
8952 player.mouseDelta.y = squareSize/2;
8953 /* Initialise animation */
8954 player.dragPiece = PieceForSquare(boardX, boardY);
8956 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8957 player.dragActive = True;
8958 BeginAnimation(&player, player.dragPiece, color, &corner);
8959 /* Mark this square as needing to be redrawn. Note that
8960 we don't remove the piece though, since logically (ie
8961 as seen by opponent) the move hasn't been made yet. */
8962 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8963 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8964 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8965 corner.x, corner.y, squareSize, squareSize,
8966 0, 0); // [HGM] zh: unstack in stead of grab
8967 if(gatingPiece != EmptySquare) {
8968 /* Kludge alert: When gating we want the introduced
8969 piece to appear on the from square. To generate an
8970 image of it, we draw it on the board, copy the image,
8971 and draw the original piece again. */
8972 ChessSquare piece = boards[currentMove][boardY][boardX];
8973 DrawSquare(boardY, boardX, gatingPiece, 0);
8974 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8975 corner.x, corner.y, squareSize, squareSize, 0, 0);
8976 DrawSquare(boardY, boardX, piece, 0);
8978 damage[0][boardY][boardX] = True;
8980 player.dragActive = False;
8990 /* Are we animating? */
8991 if (!appData.animateDragging || appData.blindfold)
8995 if (! player.dragActive)
8997 /* Move piece, maintaining same relative position
8998 of mouse within square */
8999 corner.x = x - player.mouseDelta.x;
9000 corner.y = y - player.mouseDelta.y;
9001 AnimationFrame(&player, &corner, player.dragPiece);
9003 if (appData.highlightDragging) {
9005 BoardSquare(x, y, &boardX, &boardY);
9006 SetHighlights(fromX, fromY, boardX, boardY);
9015 int boardX, boardY, color;
9018 /* Are we animating? */
9019 if (!appData.animateDragging || appData.blindfold)
9023 if (! player.dragActive)
9025 /* Last frame in sequence is square piece is
9026 placed on, which may not match mouse exactly. */
9027 BoardSquare(x, y, &boardX, &boardY);
9028 ScreenSquare(boardX, boardY, &corner, &color);
9029 EndAnimation(&player, &corner);
9031 /* Be sure end square is redrawn */
9032 damage[0][boardY][boardX] = True;
9034 /* This prevents weird things happening with fast successive
9035 clicks which on my Sun at least can cause motion events
9036 without corresponding press/release. */
9037 player.dragActive = False;
9040 /* Handle expose event while piece being dragged */
9045 if (!player.dragActive || appData.blindfold)
9048 /* What we're doing: logically, the move hasn't been made yet,
9049 so the piece is still in it's original square. But visually
9050 it's being dragged around the board. So we erase the square
9051 that the piece is on and draw it at the last known drag point. */
9052 BlankSquare(player.startSquare.x, player.startSquare.y,
9053 player.startColor, EmptySquare, xBoardWindow, 1);
9054 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9055 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9058 #include <sys/ioctl.h>
9059 int get_term_width()
9061 int fd, default_width;
9064 default_width = 79; // this is FICS default anyway...
9066 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9068 if (!ioctl(fd, TIOCGSIZE, &win))
9069 default_width = win.ts_cols;
9070 #elif defined(TIOCGWINSZ)
9072 if (!ioctl(fd, TIOCGWINSZ, &win))
9073 default_width = win.ws_col;
9075 return default_width;
9081 static int old_width = 0;
9082 int new_width = get_term_width();
9084 if (old_width != new_width)
9085 ics_printf("set width %d\n", new_width);
9086 old_width = new_width;
9089 void NotifyFrontendLogin()