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"
197 #include "xgamelist.h"
198 #include "xhistory.h"
199 #include "xedittags.h"
202 // must be moved to xengineoutput.h
204 void EngineOutputProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
206 void EvalGraphProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
214 #define usleep(t) _sleep2(((t)+500)/1000)
218 # define _(s) gettext (s)
219 # define N_(s) gettext_noop (s)
235 int main P((int argc, char **argv));
236 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
237 char *init_path, char *mode, int (*show_entry)(), char **name_return));
238 RETSIGTYPE CmailSigHandler P((int sig));
239 RETSIGTYPE IntSigHandler P((int sig));
240 RETSIGTYPE TermSizeSigHandler P((int sig));
241 void CreateGCs P((void));
242 void CreateXIMPieces P((void));
243 void CreateXPMPieces P((void));
244 void CreatePieces P((void));
245 void CreatePieceMenus P((void));
246 Widget CreateMenuBar P((Menu *mb));
247 Widget CreateButtonBar P ((MenuItem *mi));
248 char *FindFont P((char *pattern, int targetPxlSize));
249 void PieceMenuPopup P((Widget w, XEvent *event,
250 String *params, Cardinal *num_params));
251 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
252 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
253 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
254 u_int wreq, u_int hreq));
255 void CreateGrid P((void));
256 int EventToSquare P((int x, int limit));
257 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
258 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
259 void HandleUserMove P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void AnimateUserMove P((Widget w, XEvent * event,
262 String * params, Cardinal * nParams));
263 void HandlePV P((Widget w, XEvent * event,
264 String * params, Cardinal * nParams));
265 void WhiteClock P((Widget w, XEvent *event,
266 String *prms, Cardinal *nprms));
267 void BlackClock P((Widget w, XEvent *event,
268 String *prms, Cardinal *nprms));
269 void DrawPositionProc P((Widget w, XEvent *event,
270 String *prms, Cardinal *nprms));
271 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
273 void CommentPopUp P((char *title, char *label));
274 void CommentPopDown P((void));
275 void CommentCallback P((Widget w, XtPointer client_data,
276 XtPointer call_data));
277 void ICSInputBoxPopUp P((void));
278 void ICSInputBoxPopDown P((void));
279 void FileNamePopUp P((char *label, char *def,
280 FileProc proc, char *openMode));
281 void FileNamePopDown P((void));
282 void FileNameCallback P((Widget w, XtPointer client_data,
283 XtPointer call_data));
284 void FileNameAction P((Widget w, XEvent *event,
285 String *prms, Cardinal *nprms));
286 void AskQuestionReplyAction P((Widget w, XEvent *event,
287 String *prms, Cardinal *nprms));
288 void AskQuestionProc P((Widget w, XEvent *event,
289 String *prms, Cardinal *nprms));
290 void AskQuestionPopDown P((void));
291 void PromotionPopDown P((void));
292 void PromotionCallback P((Widget w, XtPointer client_data,
293 XtPointer call_data));
294 void EditCommentPopDown P((void));
295 void EditCommentCallback P((Widget w, XtPointer client_data,
296 XtPointer call_data));
297 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
298 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
299 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
300 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
302 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
304 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
306 void LoadPositionProc P((Widget w, XEvent *event,
307 String *prms, Cardinal *nprms));
308 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
310 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
312 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
314 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
316 void PastePositionProc P((Widget w, XEvent *event, String *prms,
318 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void SavePositionProc P((Widget w, XEvent *event,
322 String *prms, Cardinal *nprms));
323 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
324 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
326 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
330 void MachineWhiteProc P((Widget w, XEvent *event,
331 String *prms, Cardinal *nprms));
332 void AnalyzeModeProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void AnalyzeFileProc P((Widget w, XEvent *event,
335 String *prms, Cardinal *nprms));
336 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
338 void IcsClientProc P((Widget w, XEvent *event, String *prms,
340 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void EditPositionProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void EditCommentProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void IcsInputBoxProc P((Widget w, XEvent *event,
347 String *prms, Cardinal *nprms));
348 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void StopObservingProc P((Widget w, XEvent *event, String *prms,
364 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
366 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
375 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
377 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
380 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
382 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
384 void AutocommProc P((Widget w, XEvent *event, String *prms,
386 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void AutobsProc P((Widget w, XEvent *event, String *prms,
390 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
395 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
398 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
400 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
402 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
406 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
408 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
410 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
412 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
414 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
418 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
420 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
422 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
424 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void DisplayMove P((int moveNumber));
436 void DisplayTitle P((char *title));
437 void ICSInitScript P((void));
438 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
439 void ErrorPopUp P((char *title, char *text, int modal));
440 void ErrorPopDown P((void));
441 static char *ExpandPathName P((char *path));
442 static void CreateAnimVars P((void));
443 static void DragPieceMove P((int x, int y));
444 static void DrawDragPiece P((void));
445 char *ModeToWidgetName P((GameMode mode));
446 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void GameListOptionsPopDown P(());
455 void ShufflePopDown P(());
456 void EnginePopDown P(());
457 void UciPopDown P(());
458 void TimeControlPopDown P(());
459 void NewVariantPopDown P(());
460 void SettingsPopDown P(());
461 void update_ics_width P(());
462 int get_term_width P(());
463 int CopyMemoProc P(());
465 * XBoard depends on Xt R4 or higher
467 int xtVersion = XtSpecificationRelease;
472 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
473 jailSquareColor, highlightSquareColor, premoveHighlightColor;
474 Pixel lowTimeWarningColor;
475 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
476 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
477 wjPieceGC, bjPieceGC, prelineGC, countGC;
478 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
479 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
480 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
481 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
482 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
483 ICSInputShell, fileNameShell, askQuestionShell;
484 Widget historyShell, evalGraphShell, gameListShell;
485 int hOffset; // [HGM] dual
486 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
487 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
488 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
489 Font clockFontID, coordFontID, countFontID;
490 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
491 XtAppContext appContext;
493 char *oldICSInteractionTitle;
497 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
499 Position commentX = -1, commentY = -1;
500 Dimension commentW, commentH;
501 typedef unsigned int BoardSize;
503 Boolean chessProgram;
505 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
506 int squareSize, smallLayout = 0, tinyLayout = 0,
507 marginW, marginH, // [HGM] for run-time resizing
508 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
509 ICSInputBoxUp = False, askQuestionUp = False,
510 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
511 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
512 Pixel timerForegroundPixel, timerBackgroundPixel;
513 Pixel buttonForegroundPixel, buttonBackgroundPixel;
514 char *chessDir, *programName, *programVersion,
515 *gameCopyFilename, *gamePasteFilename;
516 Boolean alwaysOnTop = False;
517 Boolean saveSettingsOnExit;
518 char *settingsFileName;
519 char *icsTextMenuString;
521 char *firstChessProgramNames;
522 char *secondChessProgramNames;
524 WindowPlacement wpMain;
525 WindowPlacement wpConsole;
526 WindowPlacement wpComment;
527 WindowPlacement wpMoveHistory;
528 WindowPlacement wpEvalGraph;
529 WindowPlacement wpEngineOutput;
530 WindowPlacement wpGameList;
531 WindowPlacement wpTags;
535 Pixmap pieceBitmap[2][(int)BlackPawn];
536 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
537 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
538 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
539 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
540 int useImages, useImageSqs;
541 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
542 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
543 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
544 XImage *ximLightSquare, *ximDarkSquare;
547 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
548 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
550 #define White(piece) ((int)(piece) < (int)BlackPawn)
552 /* Variables for doing smooth animation. This whole thing
553 would be much easier if the board was double-buffered,
554 but that would require a fairly major rewrite. */
559 GC blitGC, pieceGC, outlineGC;
560 XPoint startSquare, prevFrame, mouseDelta;
564 int startBoardX, startBoardY;
567 /* There can be two pieces being animated at once: a player
568 can begin dragging a piece before the remote opponent has moved. */
570 static AnimState game, player;
572 /* Bitmaps for use as masks when drawing XPM pieces.
573 Need one for each black and white piece. */
574 static Pixmap xpmMask[BlackKing + 1];
576 /* This magic number is the number of intermediate frames used
577 in each half of the animation. For short moves it's reduced
578 by 1. The total number of frames will be factor * 2 + 1. */
581 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
583 MenuItem fileMenu[] = {
584 {N_("New Game"), ResetProc},
585 {N_("New Shuffle Game ..."), ShuffleMenuProc},
586 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
587 {"----", NothingProc},
588 {N_("Load Game"), LoadGameProc},
589 {N_("Load Next Game"), LoadNextGameProc},
590 {N_("Load Previous Game"), LoadPrevGameProc},
591 {N_("Reload Same Game"), ReloadGameProc},
592 {N_("Save Game"), SaveGameProc},
593 {"----", NothingProc},
594 {N_("Copy Game"), CopyGameProc},
595 {N_("Paste Game"), PasteGameProc},
596 {"----", NothingProc},
597 {N_("Load Position"), LoadPositionProc},
598 {N_("Load Next Position"), LoadNextPositionProc},
599 {N_("Load Previous Position"), LoadPrevPositionProc},
600 {N_("Reload Same Position"), ReloadPositionProc},
601 {N_("Save Position"), SavePositionProc},
602 {"----", NothingProc},
603 {N_("Copy Position"), CopyPositionProc},
604 {N_("Paste Position"), PastePositionProc},
605 {"----", NothingProc},
606 {N_("Mail Move"), MailMoveProc},
607 {N_("Reload CMail Message"), ReloadCmailMsgProc},
608 {"----", NothingProc},
609 {N_("Exit"), QuitProc},
613 MenuItem modeMenu[] = {
614 {N_("Machine White"), MachineWhiteProc},
615 {N_("Machine Black"), MachineBlackProc},
616 {N_("Two Machines"), TwoMachinesProc},
617 {N_("Analysis Mode"), AnalyzeModeProc},
618 {N_("Analyze File"), AnalyzeFileProc },
619 {N_("ICS Client"), IcsClientProc},
620 {N_("Edit Game"), EditGameProc},
621 {N_("Edit Position"), EditPositionProc},
622 {N_("Training"), TrainingProc},
623 {"----", NothingProc},
624 {N_("Show Engine Output"), EngineOutputProc},
625 {N_("Show Evaluation Graph"), EvalGraphProc},
626 {N_("Show Game List"), ShowGameListProc},
627 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
628 {"----", NothingProc},
629 {N_("Edit Tags"), EditTagsProc},
630 {N_("Edit Comment"), EditCommentProc},
631 {N_("ICS Input Box"), IcsInputBoxProc},
632 {N_("Pause"), PauseProc},
636 MenuItem actionMenu[] = {
637 {N_("Accept"), AcceptProc},
638 {N_("Decline"), DeclineProc},
639 {N_("Rematch"), RematchProc},
640 {"----", NothingProc},
641 {N_("Call Flag"), CallFlagProc},
642 {N_("Draw"), DrawProc},
643 {N_("Adjourn"), AdjournProc},
644 {N_("Abort"), AbortProc},
645 {N_("Resign"), ResignProc},
646 {"----", NothingProc},
647 {N_("Stop Observing"), StopObservingProc},
648 {N_("Stop Examining"), StopExaminingProc},
649 {N_("Upload to Examine"), UploadProc},
650 {"----", NothingProc},
651 {N_("Adjudicate to White"), AdjuWhiteProc},
652 {N_("Adjudicate to Black"), AdjuBlackProc},
653 {N_("Adjudicate Draw"), AdjuDrawProc},
657 MenuItem stepMenu[] = {
658 {N_("Backward"), BackwardProc},
659 {N_("Forward"), ForwardProc},
660 {N_("Back to Start"), ToStartProc},
661 {N_("Forward to End"), ToEndProc},
662 {N_("Revert"), RevertProc},
663 {N_("Annotate"), AnnotateProc},
664 {N_("Truncate Game"), TruncateGameProc},
665 {"----", NothingProc},
666 {N_("Move Now"), MoveNowProc},
667 {N_("Retract Move"), RetractMoveProc},
671 MenuItem optionsMenu[] = {
672 {N_("Flip View"), FlipViewProc},
673 {"----", NothingProc},
674 {N_("Adjudications ..."), EngineMenuProc},
675 {N_("General Settings ..."), UciMenuProc},
676 {N_("Engine #1 Settings ..."), FirstSettingsProc},
677 {N_("Engine #2 Settings ..."), SecondSettingsProc},
678 {N_("Time Control ..."), TimeControlProc},
679 {N_("Game List ..."), GameListOptionsPopUp},
680 {"----", NothingProc},
681 {N_("Always Queen"), AlwaysQueenProc},
682 {N_("Animate Dragging"), AnimateDraggingProc},
683 {N_("Animate Moving"), AnimateMovingProc},
684 {N_("Auto Comment"), AutocommProc},
685 {N_("Auto Flag"), AutoflagProc},
686 {N_("Auto Flip View"), AutoflipProc},
687 {N_("Auto Observe"), AutobsProc},
688 {N_("Auto Raise Board"), AutoraiseProc},
689 {N_("Auto Save"), AutosaveProc},
690 {N_("Blindfold"), BlindfoldProc},
691 {N_("Flash Moves"), FlashMovesProc},
692 {N_("Get Move List"), GetMoveListProc},
694 {N_("Highlight Dragging"), HighlightDraggingProc},
696 {N_("Highlight Last Move"), HighlightLastMoveProc},
697 {N_("Move Sound"), MoveSoundProc},
698 {N_("ICS Alarm"), IcsAlarmProc},
699 {N_("Old Save Style"), OldSaveStyleProc},
700 {N_("Periodic Updates"), PeriodicUpdatesProc},
701 {N_("Ponder Next Move"), PonderNextMoveProc},
702 {N_("Popup Exit Message"), PopupExitMessageProc},
703 {N_("Popup Move Errors"), PopupMoveErrorsProc},
704 {N_("Premove"), PremoveProc},
705 {N_("Quiet Play"), QuietPlayProc},
706 {N_("Show Coords"), ShowCoordsProc},
707 {N_("Hide Thinking"), HideThinkingProc},
708 {N_("Test Legality"), TestLegalityProc},
709 {"----", NothingProc},
710 {N_("Save Settings Now"), SaveSettingsProc},
711 {N_("Save Settings on Exit"), SaveOnExitProc},
715 MenuItem helpMenu[] = {
716 {N_("Info XBoard"), InfoProc},
717 {N_("Man XBoard"), ManProc},
718 {"----", NothingProc},
719 {N_("Hint"), HintProc},
720 {N_("Book"), BookProc},
721 {"----", NothingProc},
722 {N_("About XBoard"), AboutProc},
727 {N_("File"), fileMenu},
728 {N_("Mode"), modeMenu},
729 {N_("Action"), actionMenu},
730 {N_("Step"), stepMenu},
731 {N_("Options"), optionsMenu},
732 {N_("Help"), helpMenu},
736 #define PAUSE_BUTTON N_("P")
737 MenuItem buttonBar[] = {
740 {PAUSE_BUTTON, PauseProc},
746 #define PIECE_MENU_SIZE 18
747 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
748 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
749 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
750 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
751 N_("Empty square"), N_("Clear board") },
752 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
753 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
754 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
755 N_("Empty square"), N_("Clear board") }
757 /* must be in same order as PieceMenuStrings! */
758 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
759 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
760 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
761 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
762 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
763 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
764 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
765 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
766 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
769 #define DROP_MENU_SIZE 6
770 String dropMenuStrings[DROP_MENU_SIZE] = {
771 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
773 /* must be in same order as PieceMenuStrings! */
774 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
775 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
776 WhiteRook, WhiteQueen
784 DropMenuEnables dmEnables[] = {
802 { XtNborderWidth, 0 },
803 { XtNdefaultDistance, 0 },
807 { XtNborderWidth, 0 },
808 { XtNresizable, (XtArgVal) True },
812 { XtNborderWidth, 0 },
818 { XtNjustify, (XtArgVal) XtJustifyRight },
819 { XtNlabel, (XtArgVal) "..." },
820 { XtNresizable, (XtArgVal) True },
821 { XtNresize, (XtArgVal) False }
824 Arg messageArgs[] = {
825 { XtNjustify, (XtArgVal) XtJustifyLeft },
826 { XtNlabel, (XtArgVal) "..." },
827 { XtNresizable, (XtArgVal) True },
828 { XtNresize, (XtArgVal) False }
832 { XtNborderWidth, 0 },
833 { XtNjustify, (XtArgVal) XtJustifyLeft }
836 XtResource clientResources[] = {
837 { "flashCount", "flashCount", XtRInt, sizeof(int),
838 XtOffset(AppDataPtr, flashCount), XtRImmediate,
839 (XtPointer) FLASH_COUNT },
842 XrmOptionDescRec shellOptions[] = {
843 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
844 { "-flash", "flashCount", XrmoptionNoArg, "3" },
845 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
848 XtActionsRec boardActions[] = {
849 { "DrawPosition", DrawPositionProc },
850 { "HandleUserMove", HandleUserMove },
851 { "AnimateUserMove", AnimateUserMove },
852 { "HandlePV", HandlePV },
853 { "UnLoadPV", UnLoadPV },
854 { "FileNameAction", FileNameAction },
855 { "AskQuestionProc", AskQuestionProc },
856 { "AskQuestionReplyAction", AskQuestionReplyAction },
857 { "PieceMenuPopup", PieceMenuPopup },
858 { "WhiteClock", WhiteClock },
859 { "BlackClock", BlackClock },
860 { "Iconify", Iconify },
861 { "ResetProc", ResetProc },
862 { "LoadGameProc", LoadGameProc },
863 { "LoadNextGameProc", LoadNextGameProc },
864 { "LoadPrevGameProc", LoadPrevGameProc },
865 { "LoadSelectedProc", LoadSelectedProc },
866 { "SetFilterProc", SetFilterProc },
867 { "ReloadGameProc", ReloadGameProc },
868 { "LoadPositionProc", LoadPositionProc },
869 { "LoadNextPositionProc", LoadNextPositionProc },
870 { "LoadPrevPositionProc", LoadPrevPositionProc },
871 { "ReloadPositionProc", ReloadPositionProc },
872 { "CopyPositionProc", CopyPositionProc },
873 { "PastePositionProc", PastePositionProc },
874 { "CopyGameProc", CopyGameProc },
875 { "PasteGameProc", PasteGameProc },
876 { "SaveGameProc", SaveGameProc },
877 { "SavePositionProc", SavePositionProc },
878 { "MailMoveProc", MailMoveProc },
879 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
880 { "QuitProc", QuitProc },
881 { "MachineWhiteProc", MachineWhiteProc },
882 { "MachineBlackProc", MachineBlackProc },
883 { "AnalysisModeProc", AnalyzeModeProc },
884 { "AnalyzeFileProc", AnalyzeFileProc },
885 { "TwoMachinesProc", TwoMachinesProc },
886 { "IcsClientProc", IcsClientProc },
887 { "EditGameProc", EditGameProc },
888 { "EditPositionProc", EditPositionProc },
889 { "TrainingProc", EditPositionProc },
890 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
891 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
892 { "ShowGameListProc", ShowGameListProc },
893 { "ShowMoveListProc", HistoryShowProc},
894 { "EditTagsProc", EditCommentProc },
895 { "EditCommentProc", EditCommentProc },
896 { "IcsAlarmProc", IcsAlarmProc },
897 { "IcsInputBoxProc", IcsInputBoxProc },
898 { "PauseProc", PauseProc },
899 { "AcceptProc", AcceptProc },
900 { "DeclineProc", DeclineProc },
901 { "RematchProc", RematchProc },
902 { "CallFlagProc", CallFlagProc },
903 { "DrawProc", DrawProc },
904 { "AdjournProc", AdjournProc },
905 { "AbortProc", AbortProc },
906 { "ResignProc", ResignProc },
907 { "AdjuWhiteProc", AdjuWhiteProc },
908 { "AdjuBlackProc", AdjuBlackProc },
909 { "AdjuDrawProc", AdjuDrawProc },
910 { "EnterKeyProc", EnterKeyProc },
911 { "UpKeyProc", UpKeyProc },
912 { "DownKeyProc", DownKeyProc },
913 { "StopObservingProc", StopObservingProc },
914 { "StopExaminingProc", StopExaminingProc },
915 { "UploadProc", UploadProc },
916 { "BackwardProc", BackwardProc },
917 { "ForwardProc", ForwardProc },
918 { "ToStartProc", ToStartProc },
919 { "ToEndProc", ToEndProc },
920 { "RevertProc", RevertProc },
921 { "AnnotateProc", AnnotateProc },
922 { "TruncateGameProc", TruncateGameProc },
923 { "MoveNowProc", MoveNowProc },
924 { "RetractMoveProc", RetractMoveProc },
925 { "AlwaysQueenProc", AlwaysQueenProc },
926 { "AnimateDraggingProc", AnimateDraggingProc },
927 { "AnimateMovingProc", AnimateMovingProc },
928 { "AutoflagProc", AutoflagProc },
929 { "AutoflipProc", AutoflipProc },
930 { "AutobsProc", AutobsProc },
931 { "AutoraiseProc", AutoraiseProc },
932 { "AutosaveProc", AutosaveProc },
933 { "BlindfoldProc", BlindfoldProc },
934 { "FlashMovesProc", FlashMovesProc },
935 { "FlipViewProc", FlipViewProc },
936 { "GetMoveListProc", GetMoveListProc },
938 { "HighlightDraggingProc", HighlightDraggingProc },
940 { "HighlightLastMoveProc", HighlightLastMoveProc },
941 { "IcsAlarmProc", IcsAlarmProc },
942 { "MoveSoundProc", MoveSoundProc },
943 { "OldSaveStyleProc", OldSaveStyleProc },
944 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
945 { "PonderNextMoveProc", PonderNextMoveProc },
946 { "PopupExitMessageProc", PopupExitMessageProc },
947 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
948 { "PremoveProc", PremoveProc },
949 { "QuietPlayProc", QuietPlayProc },
950 { "ShowCoordsProc", ShowCoordsProc },
951 { "ShowThinkingProc", ShowThinkingProc },
952 { "HideThinkingProc", HideThinkingProc },
953 { "TestLegalityProc", TestLegalityProc },
954 { "SaveSettingsProc", SaveSettingsProc },
955 { "SaveOnExitProc", SaveOnExitProc },
956 { "InfoProc", InfoProc },
957 { "ManProc", ManProc },
958 { "HintProc", HintProc },
959 { "BookProc", BookProc },
960 { "AboutGameProc", AboutGameProc },
961 { "AboutProc", AboutProc },
962 { "DebugProc", DebugProc },
963 { "NothingProc", NothingProc },
964 { "CommentPopDown", (XtActionProc) CommentPopDown },
965 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
966 { "TagsPopDown", (XtActionProc) TagsPopDown },
967 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
968 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
969 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
970 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
971 { "GameListPopDown", (XtActionProc) GameListPopDown },
972 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
973 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
974 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
975 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
976 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
977 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
978 { "EnginePopDown", (XtActionProc) EnginePopDown },
979 { "UciPopDown", (XtActionProc) UciPopDown },
980 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
981 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
982 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
983 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
986 char globalTranslations[] =
987 ":<Key>R: ResignProc() \n \
988 :<Key>r: ResetProc() \n \
989 :<Key>g: LoadGameProc() \n \
990 :<Key>N: LoadNextGameProc() \n \
991 :<Key>P: LoadPrevGameProc() \n \
992 :<Key>Q: QuitProc() \n \
993 :<Key>F: ToEndProc() \n \
994 :<Key>f: ForwardProc() \n \
995 :<Key>B: ToStartProc() \n \
996 :<Key>b: BackwardProc() \n \
997 :<Key>p: PauseProc() \n \
998 :<Key>d: DrawProc() \n \
999 :<Key>t: CallFlagProc() \n \
1000 :<Key>i: Iconify() \n \
1001 :<Key>c: Iconify() \n \
1002 :<Key>v: FlipViewProc() \n \
1003 <KeyDown>Control_L: BackwardProc() \n \
1004 <KeyUp>Control_L: ForwardProc() \n \
1005 <KeyDown>Control_R: BackwardProc() \n \
1006 <KeyUp>Control_R: ForwardProc() \n \
1007 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1008 \"Send to chess program:\",,1) \n \
1009 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1010 \"Send to second chess program:\",,2) \n";
1012 char boardTranslations[] =
1013 "<Btn1Down>: HandleUserMove() \n \
1014 <Btn1Up>: HandleUserMove() \n \
1015 <Btn1Motion>: AnimateUserMove() \n \
1016 <Btn3Motion>: HandlePV() \n \
1017 <Btn3Up>: PieceMenuPopup(menuB) \n \
1018 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1019 PieceMenuPopup(menuB) \n \
1020 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1021 PieceMenuPopup(menuW) \n \
1022 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1023 PieceMenuPopup(menuW) \n \
1024 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1025 PieceMenuPopup(menuB) \n";
1027 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1028 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1030 char ICSInputTranslations[] =
1031 "<Key>Up: UpKeyProc() \n "
1032 "<Key>Down: DownKeyProc() \n "
1033 "<Key>Return: EnterKeyProc() \n";
1035 String xboardResources[] = {
1036 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1037 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1038 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1043 /* Max possible square size */
1044 #define MAXSQSIZE 256
1046 static int xpm_avail[MAXSQSIZE];
1048 #ifdef HAVE_DIR_STRUCT
1050 /* Extract piece size from filename */
1052 xpm_getsize(name, len, ext)
1063 if ((p=strchr(name, '.')) == NULL ||
1064 StrCaseCmp(p+1, ext) != 0)
1070 while (*p && isdigit(*p))
1077 /* Setup xpm_avail */
1079 xpm_getavail(dirname, ext)
1087 for (i=0; i<MAXSQSIZE; ++i)
1090 if (appData.debugMode)
1091 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1093 dir = opendir(dirname);
1096 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1097 programName, dirname);
1101 while ((ent=readdir(dir)) != NULL) {
1102 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1103 if (i > 0 && i < MAXSQSIZE)
1113 xpm_print_avail(fp, ext)
1119 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1120 for (i=1; i<MAXSQSIZE; ++i) {
1126 /* Return XPM piecesize closest to size */
1128 xpm_closest_to(dirname, size, ext)
1134 int sm_diff = MAXSQSIZE;
1138 xpm_getavail(dirname, ext);
1140 if (appData.debugMode)
1141 xpm_print_avail(stderr, ext);
1143 for (i=1; i<MAXSQSIZE; ++i) {
1146 diff = (diff<0) ? -diff : diff;
1147 if (diff < sm_diff) {
1155 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1161 #else /* !HAVE_DIR_STRUCT */
1162 /* If we are on a system without a DIR struct, we can't
1163 read the directory, so we can't collect a list of
1164 filenames, etc., so we can't do any size-fitting. */
1166 xpm_closest_to(dirname, size, ext)
1171 fprintf(stderr, _("\
1172 Warning: No DIR structure found on this system --\n\
1173 Unable to autosize for XPM/XIM pieces.\n\
1174 Please report this error to frankm@hiwaay.net.\n\
1175 Include system type & operating system in message.\n"));
1178 #endif /* HAVE_DIR_STRUCT */
1180 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1181 "magenta", "cyan", "white" };
1185 TextColors textColors[(int)NColorClasses];
1187 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1189 parse_color(str, which)
1193 char *p, buf[100], *d;
1196 if (strlen(str) > 99) /* watch bounds on buf */
1201 for (i=0; i<which; ++i) {
1208 /* Could be looking at something like:
1210 .. in which case we want to stop on a comma also */
1211 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1215 return -1; /* Use default for empty field */
1218 if (which == 2 || isdigit(*p))
1221 while (*p && isalpha(*p))
1226 for (i=0; i<8; ++i) {
1227 if (!StrCaseCmp(buf, cnames[i]))
1228 return which? (i+40) : (i+30);
1230 if (!StrCaseCmp(buf, "default")) return -1;
1232 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1237 parse_cpair(cc, str)
1241 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1242 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1247 /* bg and attr are optional */
1248 textColors[(int)cc].bg = parse_color(str, 1);
1249 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1250 textColors[(int)cc].attr = 0;
1256 /* Arrange to catch delete-window events */
1257 Atom wm_delete_window;
1259 CatchDeleteWindow(Widget w, String procname)
1262 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1263 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1264 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1271 XtSetArg(args[0], XtNiconic, False);
1272 XtSetValues(shellWidget, args, 1);
1274 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1277 //---------------------------------------------------------------------------------------------------------
1278 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1281 #define CW_USEDEFAULT (1<<31)
1282 #define ICS_TEXT_MENU_SIZE 90
1283 #define DEBUG_FILE "xboard.debug"
1284 #define SetCurrentDirectory chdir
1285 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1289 // these two must some day move to frontend.h, when they are implemented
1290 Boolean GameListIsUp();
1292 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1295 // front-end part of option handling
1297 // [HGM] This platform-dependent table provides the location for storing the color info
1298 extern char *crWhite, * crBlack;
1302 &appData.whitePieceColor,
1303 &appData.blackPieceColor,
1304 &appData.lightSquareColor,
1305 &appData.darkSquareColor,
1306 &appData.highlightSquareColor,
1307 &appData.premoveHighlightColor,
1308 &appData.lowTimeWarningColor,
1319 // [HGM] font: keep a font for each square size, even non-stndard ones
1320 #define NUM_SIZES 18
1321 #define MAX_SIZE 130
1322 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1323 char *fontTable[NUM_FONTS][MAX_SIZE];
1326 ParseFont(char *name, int number)
1327 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1329 if(sscanf(name, "size%d:", &size)) {
1330 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1331 // defer processing it until we know if it matches our board size
1332 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1333 fontTable[number][size] = strdup(strchr(name, ':')+1);
1334 fontValid[number][size] = True;
1339 case 0: // CLOCK_FONT
1340 appData.clockFont = strdup(name);
1342 case 1: // MESSAGE_FONT
1343 appData.font = strdup(name);
1345 case 2: // COORD_FONT
1346 appData.coordFont = strdup(name);
1351 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1356 { // only 2 fonts currently
1357 appData.clockFont = CLOCK_FONT_NAME;
1358 appData.coordFont = COORD_FONT_NAME;
1359 appData.font = DEFAULT_FONT_NAME;
1364 { // no-op, until we identify the code for this already in XBoard and move it here
1368 ParseColor(int n, char *name)
1369 { // in XBoard, just copy the color-name string
1370 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1374 ParseTextAttribs(ColorClass cc, char *s)
1376 (&appData.colorShout)[cc] = strdup(s);
1380 ParseBoardSize(void *addr, char *name)
1382 appData.boardSize = strdup(name);
1387 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1391 SetCommPortDefaults()
1392 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1395 // [HGM] args: these three cases taken out to stay in front-end
1397 SaveFontArg(FILE *f, ArgDescriptor *ad)
1399 char *name, buf[MSG_SIZ];
1400 int i, n = (int)ad->argLoc;
1402 case 0: // CLOCK_FONT
1403 name = appData.clockFont;
1405 case 1: // MESSAGE_FONT
1406 name = appData.font;
1408 case 2: // COORD_FONT
1409 name = appData.coordFont;
1414 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1415 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1416 fontTable[n][squareSize] = strdup(name);
1417 fontValid[n][squareSize] = True;
1420 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1421 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1426 { // nothing to do, as the sounds are at all times represented by their text-string names already
1430 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1431 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1432 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1436 SaveColor(FILE *f, ArgDescriptor *ad)
1437 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1438 if(colorVariable[(int)ad->argLoc])
1439 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1443 SaveBoardSize(FILE *f, char *name, void *addr)
1444 { // wrapper to shield back-end from BoardSize & sizeInfo
1445 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1449 ParseCommPortSettings(char *s)
1450 { // no such option in XBoard (yet)
1453 extern Widget engineOutputShell;
1454 extern Widget tagsShell, editTagsShell;
1456 GetActualPlacement(Widget wg, WindowPlacement *wp)
1466 XtSetArg(args[i], XtNx, &x); i++;
1467 XtSetArg(args[i], XtNy, &y); i++;
1468 XtSetArg(args[i], XtNwidth, &w); i++;
1469 XtSetArg(args[i], XtNheight, &h); i++;
1470 XtGetValues(wg, args, i);
1479 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1480 // In XBoard this will have to wait until awareness of window parameters is implemented
1481 GetActualPlacement(shellWidget, &wpMain);
1482 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1483 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1484 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1485 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1486 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1487 else GetActualPlacement(editShell, &wpComment);
1488 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1489 else GetActualPlacement(editTagsShell, &wpTags);
1493 PrintCommPortSettings(FILE *f, char *name)
1494 { // This option does not exist in XBoard
1498 MySearchPath(char *installDir, char *name, char *fullname)
1499 { // just append installDir and name. Perhaps ExpandPath should be used here?
1500 name = ExpandPathName(name);
1501 if(name && name[0] == '/') strcpy(fullname, name); else {
1502 sprintf(fullname, "%s%c%s", installDir, '/', name);
1508 MyGetFullPathName(char *name, char *fullname)
1509 { // should use ExpandPath?
1510 name = ExpandPathName(name);
1511 strcpy(fullname, name);
1516 EnsureOnScreen(int *x, int *y, int minX, int minY)
1523 { // [HGM] args: allows testing if main window is realized from back-end
1524 return xBoardWindow != 0;
1528 PopUpStartupDialog()
1529 { // start menu not implemented in XBoard
1532 ConvertToLine(int argc, char **argv)
1534 static char line[128*1024], buf[1024];
1538 for(i=1; i<argc; i++) {
1539 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1540 && argv[i][0] != '{' )
1541 sprintf(buf, "{%s} ", argv[i]);
1542 else sprintf(buf, "%s ", argv[i]);
1545 line[strlen(line)-1] = NULLCHAR;
1549 //--------------------------------------------------------------------------------------------
1551 extern Boolean twoBoards, partnerUp;
1554 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1556 #define BoardSize int
1557 void InitDrawingSizes(BoardSize boardSize, int flags)
1558 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1559 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1561 XtGeometryResult gres;
1564 if(!formWidget) return;
1567 * Enable shell resizing.
1569 shellArgs[0].value = (XtArgVal) &w;
1570 shellArgs[1].value = (XtArgVal) &h;
1571 XtGetValues(shellWidget, shellArgs, 2);
1573 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1574 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1575 XtSetValues(shellWidget, &shellArgs[2], 4);
1577 XtSetArg(args[0], XtNdefaultDistance, &sep);
1578 XtGetValues(formWidget, args, 1);
1580 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1581 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1583 hOffset = boardWidth + 10;
1584 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1585 secondSegments[i] = gridSegments[i];
1586 secondSegments[i].x1 += hOffset;
1587 secondSegments[i].x2 += hOffset;
1590 XtSetArg(args[0], XtNwidth, boardWidth);
1591 XtSetArg(args[1], XtNheight, boardHeight);
1592 XtSetValues(boardWidget, args, 2);
1594 timerWidth = (boardWidth - sep) / 2;
1595 XtSetArg(args[0], XtNwidth, timerWidth);
1596 XtSetValues(whiteTimerWidget, args, 1);
1597 XtSetValues(blackTimerWidget, args, 1);
1599 XawFormDoLayout(formWidget, False);
1601 if (appData.titleInWindow) {
1603 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1604 XtSetArg(args[i], XtNheight, &h); i++;
1605 XtGetValues(titleWidget, args, i);
1607 w = boardWidth - 2*bor;
1609 XtSetArg(args[0], XtNwidth, &w);
1610 XtGetValues(menuBarWidget, args, 1);
1611 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1614 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1615 if (gres != XtGeometryYes && appData.debugMode) {
1617 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1618 programName, gres, w, h, wr, hr);
1622 XawFormDoLayout(formWidget, True);
1625 * Inhibit shell resizing.
1627 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1628 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1629 shellArgs[4].value = shellArgs[2].value = w;
1630 shellArgs[5].value = shellArgs[3].value = h;
1631 XtSetValues(shellWidget, &shellArgs[0], 6);
1633 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1636 for(i=0; i<4; i++) {
1638 for(p=0; p<=(int)WhiteKing; p++)
1639 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1640 if(gameInfo.variant == VariantShogi) {
1641 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1642 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1643 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1644 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1645 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1648 if(gameInfo.variant == VariantGothic) {
1649 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1653 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1654 for(p=0; p<=(int)WhiteKing; p++)
1655 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1656 if(gameInfo.variant == VariantShogi) {
1657 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1658 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1659 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1660 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1661 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1664 if(gameInfo.variant == VariantGothic) {
1665 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1671 for(i=0; i<2; i++) {
1673 for(p=0; p<=(int)WhiteKing; p++)
1674 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1675 if(gameInfo.variant == VariantShogi) {
1676 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1677 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1678 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1679 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1680 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1683 if(gameInfo.variant == VariantGothic) {
1684 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1695 void EscapeExpand(char *p, char *q)
1696 { // [HGM] initstring: routine to shape up string arguments
1697 while(*p++ = *q++) if(p[-1] == '\\')
1699 case 'n': p[-1] = '\n'; break;
1700 case 'r': p[-1] = '\r'; break;
1701 case 't': p[-1] = '\t'; break;
1702 case '\\': p[-1] = '\\'; break;
1703 case 0: *p = 0; return;
1704 default: p[-1] = q[-1]; break;
1713 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1714 XSetWindowAttributes window_attributes;
1716 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1717 XrmValue vFrom, vTo;
1718 XtGeometryResult gres;
1721 int forceMono = False;
1723 srandom(time(0)); // [HGM] book: make random truly random
1725 setbuf(stdout, NULL);
1726 setbuf(stderr, NULL);
1729 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1730 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1734 programName = strrchr(argv[0], '/');
1735 if (programName == NULL)
1736 programName = argv[0];
1741 XtSetLanguageProc(NULL, NULL, NULL);
1742 bindtextdomain(PACKAGE, LOCALEDIR);
1743 textdomain(PACKAGE);
1747 XtAppInitialize(&appContext, "XBoard", shellOptions,
1748 XtNumber(shellOptions),
1749 &argc, argv, xboardResources, NULL, 0);
1750 appData.boardSize = "";
1751 InitAppData(ConvertToLine(argc, argv));
1753 if (p == NULL) p = "/tmp";
1754 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1755 gameCopyFilename = (char*) malloc(i);
1756 gamePasteFilename = (char*) malloc(i);
1757 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1758 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1760 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1761 clientResources, XtNumber(clientResources),
1764 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1765 static char buf[MSG_SIZ];
1766 EscapeExpand(buf, appData.initString);
1767 appData.initString = strdup(buf);
1768 EscapeExpand(buf, appData.secondInitString);
1769 appData.secondInitString = strdup(buf);
1770 EscapeExpand(buf, appData.firstComputerString);
1771 appData.firstComputerString = strdup(buf);
1772 EscapeExpand(buf, appData.secondComputerString);
1773 appData.secondComputerString = strdup(buf);
1776 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1779 if (chdir(chessDir) != 0) {
1780 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1786 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1787 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1788 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1789 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1792 setbuf(debugFP, NULL);
1795 /* [HGM,HR] make sure board size is acceptable */
1796 if(appData.NrFiles > BOARD_FILES ||
1797 appData.NrRanks > BOARD_RANKS )
1798 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1801 /* This feature does not work; animation needs a rewrite */
1802 appData.highlightDragging = FALSE;
1806 xDisplay = XtDisplay(shellWidget);
1807 xScreen = DefaultScreen(xDisplay);
1808 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1810 gameInfo.variant = StringToVariant(appData.variant);
1811 InitPosition(FALSE);
1814 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1816 if (isdigit(appData.boardSize[0])) {
1817 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1818 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1819 &fontPxlSize, &smallLayout, &tinyLayout);
1821 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1822 programName, appData.boardSize);
1826 /* Find some defaults; use the nearest known size */
1827 SizeDefaults *szd, *nearest;
1828 int distance = 99999;
1829 nearest = szd = sizeDefaults;
1830 while (szd->name != NULL) {
1831 if (abs(szd->squareSize - squareSize) < distance) {
1833 distance = abs(szd->squareSize - squareSize);
1834 if (distance == 0) break;
1838 if (i < 2) lineGap = nearest->lineGap;
1839 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1840 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1841 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1842 if (i < 6) smallLayout = nearest->smallLayout;
1843 if (i < 7) tinyLayout = nearest->tinyLayout;
1846 SizeDefaults *szd = sizeDefaults;
1847 if (*appData.boardSize == NULLCHAR) {
1848 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1849 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1852 if (szd->name == NULL) szd--;
1853 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1855 while (szd->name != NULL &&
1856 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1857 if (szd->name == NULL) {
1858 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1859 programName, appData.boardSize);
1863 squareSize = szd->squareSize;
1864 lineGap = szd->lineGap;
1865 clockFontPxlSize = szd->clockFontPxlSize;
1866 coordFontPxlSize = szd->coordFontPxlSize;
1867 fontPxlSize = szd->fontPxlSize;
1868 smallLayout = szd->smallLayout;
1869 tinyLayout = szd->tinyLayout;
1870 // [HGM] font: use defaults from settings file if available and not overruled
1872 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1873 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1874 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1875 appData.font = fontTable[MESSAGE_FONT][squareSize];
1876 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1877 appData.coordFont = fontTable[COORD_FONT][squareSize];
1879 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1880 if (strlen(appData.pixmapDirectory) > 0) {
1881 p = ExpandPathName(appData.pixmapDirectory);
1883 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1884 appData.pixmapDirectory);
1887 if (appData.debugMode) {
1888 fprintf(stderr, _("\
1889 XBoard square size (hint): %d\n\
1890 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1892 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1893 if (appData.debugMode) {
1894 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1898 /* [HR] height treated separately (hacked) */
1899 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1900 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1901 if (appData.showJail == 1) {
1902 /* Jail on top and bottom */
1903 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1904 XtSetArg(boardArgs[2], XtNheight,
1905 boardHeight + 2*(lineGap + squareSize));
1906 } else if (appData.showJail == 2) {
1908 XtSetArg(boardArgs[1], XtNwidth,
1909 boardWidth + 2*(lineGap + squareSize));
1910 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1913 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1914 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1918 * Determine what fonts to use.
1920 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1921 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1922 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1923 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1924 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1925 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1926 appData.font = FindFont(appData.font, fontPxlSize);
1927 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1928 countFontStruct = XQueryFont(xDisplay, countFontID);
1929 // appData.font = FindFont(appData.font, fontPxlSize);
1931 xdb = XtDatabase(xDisplay);
1932 XrmPutStringResource(&xdb, "*font", appData.font);
1935 * Detect if there are not enough colors available and adapt.
1937 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1938 appData.monoMode = True;
1941 if (!appData.monoMode) {
1942 vFrom.addr = (caddr_t) appData.lightSquareColor;
1943 vFrom.size = strlen(appData.lightSquareColor);
1944 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1945 if (vTo.addr == NULL) {
1946 appData.monoMode = True;
1949 lightSquareColor = *(Pixel *) vTo.addr;
1952 if (!appData.monoMode) {
1953 vFrom.addr = (caddr_t) appData.darkSquareColor;
1954 vFrom.size = strlen(appData.darkSquareColor);
1955 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1956 if (vTo.addr == NULL) {
1957 appData.monoMode = True;
1960 darkSquareColor = *(Pixel *) vTo.addr;
1963 if (!appData.monoMode) {
1964 vFrom.addr = (caddr_t) appData.whitePieceColor;
1965 vFrom.size = strlen(appData.whitePieceColor);
1966 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1967 if (vTo.addr == NULL) {
1968 appData.monoMode = True;
1971 whitePieceColor = *(Pixel *) vTo.addr;
1974 if (!appData.monoMode) {
1975 vFrom.addr = (caddr_t) appData.blackPieceColor;
1976 vFrom.size = strlen(appData.blackPieceColor);
1977 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1978 if (vTo.addr == NULL) {
1979 appData.monoMode = True;
1982 blackPieceColor = *(Pixel *) vTo.addr;
1986 if (!appData.monoMode) {
1987 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1988 vFrom.size = strlen(appData.highlightSquareColor);
1989 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1990 if (vTo.addr == NULL) {
1991 appData.monoMode = True;
1994 highlightSquareColor = *(Pixel *) vTo.addr;
1998 if (!appData.monoMode) {
1999 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2000 vFrom.size = strlen(appData.premoveHighlightColor);
2001 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2002 if (vTo.addr == NULL) {
2003 appData.monoMode = True;
2006 premoveHighlightColor = *(Pixel *) vTo.addr;
2011 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2014 if (appData.bitmapDirectory == NULL ||
2015 appData.bitmapDirectory[0] == NULLCHAR)
2016 appData.bitmapDirectory = DEF_BITMAP_DIR;
2019 if (appData.lowTimeWarning && !appData.monoMode) {
2020 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2021 vFrom.size = strlen(appData.lowTimeWarningColor);
2022 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2023 if (vTo.addr == NULL)
2024 appData.monoMode = True;
2026 lowTimeWarningColor = *(Pixel *) vTo.addr;
2029 if (appData.monoMode && appData.debugMode) {
2030 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2031 (unsigned long) XWhitePixel(xDisplay, xScreen),
2032 (unsigned long) XBlackPixel(xDisplay, xScreen));
2035 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2036 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2037 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2038 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2039 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2040 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2041 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2042 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2043 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2044 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2046 if (appData.colorize) {
2048 _("%s: can't parse color names; disabling colorization\n"),
2051 appData.colorize = FALSE;
2053 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2054 textColors[ColorNone].attr = 0;
2056 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2062 layoutName = "tinyLayout";
2063 } else if (smallLayout) {
2064 layoutName = "smallLayout";
2066 layoutName = "normalLayout";
2068 /* Outer layoutWidget is there only to provide a name for use in
2069 resources that depend on the layout style */
2071 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2072 layoutArgs, XtNumber(layoutArgs));
2074 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2075 formArgs, XtNumber(formArgs));
2076 XtSetArg(args[0], XtNdefaultDistance, &sep);
2077 XtGetValues(formWidget, args, 1);
2080 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2081 XtSetArg(args[0], XtNtop, XtChainTop);
2082 XtSetArg(args[1], XtNbottom, XtChainTop);
2083 XtSetArg(args[2], XtNright, XtChainLeft);
2084 XtSetValues(menuBarWidget, args, 3);
2086 widgetList[j++] = whiteTimerWidget =
2087 XtCreateWidget("whiteTime", labelWidgetClass,
2088 formWidget, timerArgs, XtNumber(timerArgs));
2089 XtSetArg(args[0], XtNfont, clockFontStruct);
2090 XtSetArg(args[1], XtNtop, XtChainTop);
2091 XtSetArg(args[2], XtNbottom, XtChainTop);
2092 XtSetValues(whiteTimerWidget, args, 3);
2094 widgetList[j++] = blackTimerWidget =
2095 XtCreateWidget("blackTime", labelWidgetClass,
2096 formWidget, timerArgs, XtNumber(timerArgs));
2097 XtSetArg(args[0], XtNfont, clockFontStruct);
2098 XtSetArg(args[1], XtNtop, XtChainTop);
2099 XtSetArg(args[2], XtNbottom, XtChainTop);
2100 XtSetValues(blackTimerWidget, args, 3);
2102 if (appData.titleInWindow) {
2103 widgetList[j++] = titleWidget =
2104 XtCreateWidget("title", labelWidgetClass, formWidget,
2105 titleArgs, XtNumber(titleArgs));
2106 XtSetArg(args[0], XtNtop, XtChainTop);
2107 XtSetArg(args[1], XtNbottom, XtChainTop);
2108 XtSetValues(titleWidget, args, 2);
2111 if (appData.showButtonBar) {
2112 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2113 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2114 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2115 XtSetArg(args[2], XtNtop, XtChainTop);
2116 XtSetArg(args[3], XtNbottom, XtChainTop);
2117 XtSetValues(buttonBarWidget, args, 4);
2120 widgetList[j++] = messageWidget =
2121 XtCreateWidget("message", labelWidgetClass, formWidget,
2122 messageArgs, XtNumber(messageArgs));
2123 XtSetArg(args[0], XtNtop, XtChainTop);
2124 XtSetArg(args[1], XtNbottom, XtChainTop);
2125 XtSetValues(messageWidget, args, 2);
2127 widgetList[j++] = boardWidget =
2128 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2129 XtNumber(boardArgs));
2131 XtManageChildren(widgetList, j);
2133 timerWidth = (boardWidth - sep) / 2;
2134 XtSetArg(args[0], XtNwidth, timerWidth);
2135 XtSetValues(whiteTimerWidget, args, 1);
2136 XtSetValues(blackTimerWidget, args, 1);
2138 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2139 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2140 XtGetValues(whiteTimerWidget, args, 2);
2142 if (appData.showButtonBar) {
2143 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2144 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2145 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2149 * formWidget uses these constraints but they are stored
2153 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2154 XtSetValues(menuBarWidget, args, i);
2155 if (appData.titleInWindow) {
2158 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2159 XtSetValues(whiteTimerWidget, args, i);
2161 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2162 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2163 XtSetValues(blackTimerWidget, args, i);
2165 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2166 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2167 XtSetValues(titleWidget, args, i);
2169 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2170 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2171 XtSetValues(messageWidget, args, i);
2172 if (appData.showButtonBar) {
2174 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2175 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2176 XtSetValues(buttonBarWidget, args, i);
2180 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2181 XtSetValues(whiteTimerWidget, args, i);
2183 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2184 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2185 XtSetValues(blackTimerWidget, args, i);
2187 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2188 XtSetValues(titleWidget, args, i);
2190 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2191 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2192 XtSetValues(messageWidget, args, i);
2193 if (appData.showButtonBar) {
2195 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2196 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2197 XtSetValues(buttonBarWidget, args, i);
2202 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2203 XtSetValues(whiteTimerWidget, args, i);
2205 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2206 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2207 XtSetValues(blackTimerWidget, args, i);
2209 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2210 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2211 XtSetValues(messageWidget, args, i);
2212 if (appData.showButtonBar) {
2214 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2215 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2216 XtSetValues(buttonBarWidget, args, i);
2220 XtSetArg(args[0], XtNfromVert, messageWidget);
2221 XtSetArg(args[1], XtNtop, XtChainTop);
2222 XtSetArg(args[2], XtNbottom, XtChainBottom);
2223 XtSetArg(args[3], XtNleft, XtChainLeft);
2224 XtSetArg(args[4], XtNright, XtChainRight);
2225 XtSetValues(boardWidget, args, 5);
2227 XtRealizeWidget(shellWidget);
2230 XtSetArg(args[0], XtNx, wpMain.x);
2231 XtSetArg(args[1], XtNy, wpMain.y);
2232 XtSetValues(shellWidget, args, 2);
2236 * Correct the width of the message and title widgets.
2237 * It is not known why some systems need the extra fudge term.
2238 * The value "2" is probably larger than needed.
2240 XawFormDoLayout(formWidget, False);
2242 #define WIDTH_FUDGE 2
2244 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2245 XtSetArg(args[i], XtNheight, &h); i++;
2246 XtGetValues(messageWidget, args, i);
2247 if (appData.showButtonBar) {
2249 XtSetArg(args[i], XtNwidth, &w); i++;
2250 XtGetValues(buttonBarWidget, args, i);
2251 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2253 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2256 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2257 if (gres != XtGeometryYes && appData.debugMode) {
2258 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2259 programName, gres, w, h, wr, hr);
2262 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2263 /* The size used for the child widget in layout lags one resize behind
2264 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2266 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2267 if (gres != XtGeometryYes && appData.debugMode) {
2268 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2269 programName, gres, w, h, wr, hr);
2272 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2273 XtSetArg(args[1], XtNright, XtChainRight);
2274 XtSetValues(messageWidget, args, 2);
2276 if (appData.titleInWindow) {
2278 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2279 XtSetArg(args[i], XtNheight, &h); i++;
2280 XtGetValues(titleWidget, args, i);
2282 w = boardWidth - 2*bor;
2284 XtSetArg(args[0], XtNwidth, &w);
2285 XtGetValues(menuBarWidget, args, 1);
2286 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2289 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2290 if (gres != XtGeometryYes && appData.debugMode) {
2292 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2293 programName, gres, w, h, wr, hr);
2296 XawFormDoLayout(formWidget, True);
2298 xBoardWindow = XtWindow(boardWidget);
2300 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2301 // not need to go into InitDrawingSizes().
2305 * Create X checkmark bitmap and initialize option menu checks.
2307 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2308 checkmark_bits, checkmark_width, checkmark_height);
2309 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2310 if (appData.alwaysPromoteToQueen) {
2311 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2314 if (appData.animateDragging) {
2315 XtSetValues(XtNameToWidget(menuBarWidget,
2316 "menuOptions.Animate Dragging"),
2319 if (appData.animate) {
2320 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2323 if (appData.autoComment) {
2324 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2327 if (appData.autoCallFlag) {
2328 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2331 if (appData.autoFlipView) {
2332 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2335 if (appData.autoObserve) {
2336 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2339 if (appData.autoRaiseBoard) {
2340 XtSetValues(XtNameToWidget(menuBarWidget,
2341 "menuOptions.Auto Raise Board"), args, 1);
2343 if (appData.autoSaveGames) {
2344 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2347 if (appData.saveGameFile[0] != NULLCHAR) {
2348 /* Can't turn this off from menu */
2349 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2351 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2355 if (appData.blindfold) {
2356 XtSetValues(XtNameToWidget(menuBarWidget,
2357 "menuOptions.Blindfold"), args, 1);
2359 if (appData.flashCount > 0) {
2360 XtSetValues(XtNameToWidget(menuBarWidget,
2361 "menuOptions.Flash Moves"),
2364 if (appData.getMoveList) {
2365 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2369 if (appData.highlightDragging) {
2370 XtSetValues(XtNameToWidget(menuBarWidget,
2371 "menuOptions.Highlight Dragging"),
2375 if (appData.highlightLastMove) {
2376 XtSetValues(XtNameToWidget(menuBarWidget,
2377 "menuOptions.Highlight Last Move"),
2380 if (appData.icsAlarm) {
2381 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2384 if (appData.ringBellAfterMoves) {
2385 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2388 if (appData.oldSaveStyle) {
2389 XtSetValues(XtNameToWidget(menuBarWidget,
2390 "menuOptions.Old Save Style"), args, 1);
2392 if (appData.periodicUpdates) {
2393 XtSetValues(XtNameToWidget(menuBarWidget,
2394 "menuOptions.Periodic Updates"), args, 1);
2396 if (appData.ponderNextMove) {
2397 XtSetValues(XtNameToWidget(menuBarWidget,
2398 "menuOptions.Ponder Next Move"), args, 1);
2400 if (appData.popupExitMessage) {
2401 XtSetValues(XtNameToWidget(menuBarWidget,
2402 "menuOptions.Popup Exit Message"), args, 1);
2404 if (appData.popupMoveErrors) {
2405 XtSetValues(XtNameToWidget(menuBarWidget,
2406 "menuOptions.Popup Move Errors"), args, 1);
2408 if (appData.premove) {
2409 XtSetValues(XtNameToWidget(menuBarWidget,
2410 "menuOptions.Premove"), args, 1);
2412 if (appData.quietPlay) {
2413 XtSetValues(XtNameToWidget(menuBarWidget,
2414 "menuOptions.Quiet Play"), args, 1);
2416 if (appData.showCoords) {
2417 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2420 if (appData.hideThinkingFromHuman) {
2421 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2424 if (appData.testLegality) {
2425 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2428 if (saveSettingsOnExit) {
2429 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2436 ReadBitmap(&wIconPixmap, "icon_white.bm",
2437 icon_white_bits, icon_white_width, icon_white_height);
2438 ReadBitmap(&bIconPixmap, "icon_black.bm",
2439 icon_black_bits, icon_black_width, icon_black_height);
2440 iconPixmap = wIconPixmap;
2442 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2443 XtSetValues(shellWidget, args, i);
2446 * Create a cursor for the board widget.
2448 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2449 XChangeWindowAttributes(xDisplay, xBoardWindow,
2450 CWCursor, &window_attributes);
2453 * Inhibit shell resizing.
2455 shellArgs[0].value = (XtArgVal) &w;
2456 shellArgs[1].value = (XtArgVal) &h;
2457 XtGetValues(shellWidget, shellArgs, 2);
2458 shellArgs[4].value = shellArgs[2].value = w;
2459 shellArgs[5].value = shellArgs[3].value = h;
2460 XtSetValues(shellWidget, &shellArgs[2], 4);
2461 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2462 marginH = h - boardHeight;
2464 CatchDeleteWindow(shellWidget, "QuitProc");
2469 if (appData.bitmapDirectory[0] != NULLCHAR) {
2476 /* Create regular pieces */
2477 if (!useImages) CreatePieces();
2482 if (appData.animate || appData.animateDragging)
2485 XtAugmentTranslations(formWidget,
2486 XtParseTranslationTable(globalTranslations));
2487 XtAugmentTranslations(boardWidget,
2488 XtParseTranslationTable(boardTranslations));
2489 XtAugmentTranslations(whiteTimerWidget,
2490 XtParseTranslationTable(whiteTranslations));
2491 XtAugmentTranslations(blackTimerWidget,
2492 XtParseTranslationTable(blackTranslations));
2494 /* Why is the following needed on some versions of X instead
2495 * of a translation? */
2496 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2497 (XtEventHandler) EventProc, NULL);
2500 /* [AS] Restore layout */
2501 if( wpMoveHistory.visible ) {
2505 if( wpEvalGraph.visible )
2510 if( wpEngineOutput.visible ) {
2511 EngineOutputPopUp();
2516 if (errorExitStatus == -1) {
2517 if (appData.icsActive) {
2518 /* We now wait until we see "login:" from the ICS before
2519 sending the logon script (problems with timestamp otherwise) */
2520 /*ICSInitScript();*/
2521 if (appData.icsInputBox) ICSInputBoxPopUp();
2525 signal(SIGWINCH, TermSizeSigHandler);
2527 signal(SIGINT, IntSigHandler);
2528 signal(SIGTERM, IntSigHandler);
2529 if (*appData.cmailGameName != NULLCHAR) {
2530 signal(SIGUSR1, CmailSigHandler);
2533 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2536 XtAppMainLoop(appContext);
2537 if (appData.debugMode) fclose(debugFP); // [DM] debug
2544 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2545 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2547 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2548 unlink(gameCopyFilename);
2549 unlink(gamePasteFilename);
2552 RETSIGTYPE TermSizeSigHandler(int sig)
2565 CmailSigHandler(sig)
2571 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2573 /* Activate call-back function CmailSigHandlerCallBack() */
2574 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2576 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2580 CmailSigHandlerCallBack(isr, closure, message, count, error)
2588 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2590 /**** end signal code ****/
2600 f = fopen(appData.icsLogon, "r");
2606 strcat(buf, appData.icsLogon);
2607 f = fopen(buf, "r");
2611 ProcessICSInitScript(f);
2618 EditCommentPopDown();
2633 if (!menuBarWidget) return;
2634 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2636 DisplayError("menuStep.Revert", 0);
2638 XtSetSensitive(w, !grey);
2640 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2642 DisplayError("menuStep.Annotate", 0);
2644 XtSetSensitive(w, !grey);
2649 SetMenuEnables(enab)
2653 if (!menuBarWidget) return;
2654 while (enab->name != NULL) {
2655 w = XtNameToWidget(menuBarWidget, enab->name);
2657 DisplayError(enab->name, 0);
2659 XtSetSensitive(w, enab->value);
2665 Enables icsEnables[] = {
2666 { "menuFile.Mail Move", False },
2667 { "menuFile.Reload CMail Message", False },
2668 { "menuMode.Machine Black", False },
2669 { "menuMode.Machine White", False },
2670 { "menuMode.Analysis Mode", False },
2671 { "menuMode.Analyze File", False },
2672 { "menuMode.Two Machines", False },
2674 { "menuHelp.Hint", False },
2675 { "menuHelp.Book", False },
2676 { "menuStep.Move Now", False },
2677 { "menuOptions.Periodic Updates", False },
2678 { "menuOptions.Hide Thinking", False },
2679 { "menuOptions.Ponder Next Move", False },
2681 { "menuStep.Annotate", False },
2685 Enables ncpEnables[] = {
2686 { "menuFile.Mail Move", False },
2687 { "menuFile.Reload CMail Message", False },
2688 { "menuMode.Machine White", False },
2689 { "menuMode.Machine Black", False },
2690 { "menuMode.Analysis Mode", False },
2691 { "menuMode.Analyze File", False },
2692 { "menuMode.Two Machines", False },
2693 { "menuMode.ICS Client", False },
2694 { "menuMode.ICS Input Box", False },
2695 { "Action", False },
2696 { "menuStep.Revert", False },
2697 { "menuStep.Annotate", False },
2698 { "menuStep.Move Now", False },
2699 { "menuStep.Retract Move", False },
2700 { "menuOptions.Auto Comment", False },
2701 { "menuOptions.Auto Flag", False },
2702 { "menuOptions.Auto Flip View", False },
2703 { "menuOptions.Auto Observe", False },
2704 { "menuOptions.Auto Raise Board", False },
2705 { "menuOptions.Get Move List", False },
2706 { "menuOptions.ICS Alarm", False },
2707 { "menuOptions.Move Sound", False },
2708 { "menuOptions.Quiet Play", False },
2709 { "menuOptions.Hide Thinking", False },
2710 { "menuOptions.Periodic Updates", False },
2711 { "menuOptions.Ponder Next Move", False },
2712 { "menuHelp.Hint", False },
2713 { "menuHelp.Book", False },
2717 Enables gnuEnables[] = {
2718 { "menuMode.ICS Client", False },
2719 { "menuMode.ICS Input Box", False },
2720 { "menuAction.Accept", False },
2721 { "menuAction.Decline", False },
2722 { "menuAction.Rematch", False },
2723 { "menuAction.Adjourn", False },
2724 { "menuAction.Stop Examining", False },
2725 { "menuAction.Stop Observing", False },
2726 { "menuAction.Upload to Examine", False },
2727 { "menuStep.Revert", False },
2728 { "menuStep.Annotate", False },
2729 { "menuOptions.Auto Comment", False },
2730 { "menuOptions.Auto Observe", False },
2731 { "menuOptions.Auto Raise Board", False },
2732 { "menuOptions.Get Move List", False },
2733 { "menuOptions.Premove", False },
2734 { "menuOptions.Quiet Play", False },
2736 /* The next two options rely on SetCmailMode being called *after* */
2737 /* SetGNUMode so that when GNU is being used to give hints these */
2738 /* menu options are still available */
2740 { "menuFile.Mail Move", False },
2741 { "menuFile.Reload CMail Message", False },
2745 Enables cmailEnables[] = {
2747 { "menuAction.Call Flag", False },
2748 { "menuAction.Draw", True },
2749 { "menuAction.Adjourn", False },
2750 { "menuAction.Abort", False },
2751 { "menuAction.Stop Observing", False },
2752 { "menuAction.Stop Examining", False },
2753 { "menuFile.Mail Move", True },
2754 { "menuFile.Reload CMail Message", True },
2758 Enables trainingOnEnables[] = {
2759 { "menuMode.Edit Comment", False },
2760 { "menuMode.Pause", False },
2761 { "menuStep.Forward", False },
2762 { "menuStep.Backward", False },
2763 { "menuStep.Forward to End", False },
2764 { "menuStep.Back to Start", False },
2765 { "menuStep.Move Now", False },
2766 { "menuStep.Truncate Game", False },
2770 Enables trainingOffEnables[] = {
2771 { "menuMode.Edit Comment", True },
2772 { "menuMode.Pause", True },
2773 { "menuStep.Forward", True },
2774 { "menuStep.Backward", True },
2775 { "menuStep.Forward to End", True },
2776 { "menuStep.Back to Start", True },
2777 { "menuStep.Move Now", True },
2778 { "menuStep.Truncate Game", True },
2782 Enables machineThinkingEnables[] = {
2783 { "menuFile.Load Game", False },
2784 { "menuFile.Load Next Game", False },
2785 { "menuFile.Load Previous Game", False },
2786 { "menuFile.Reload Same Game", False },
2787 { "menuFile.Paste Game", False },
2788 { "menuFile.Load Position", False },
2789 { "menuFile.Load Next Position", False },
2790 { "menuFile.Load Previous Position", False },
2791 { "menuFile.Reload Same Position", False },
2792 { "menuFile.Paste Position", False },
2793 { "menuMode.Machine White", False },
2794 { "menuMode.Machine Black", False },
2795 { "menuMode.Two Machines", False },
2796 { "menuStep.Retract Move", False },
2800 Enables userThinkingEnables[] = {
2801 { "menuFile.Load Game", True },
2802 { "menuFile.Load Next Game", True },
2803 { "menuFile.Load Previous Game", True },
2804 { "menuFile.Reload Same Game", True },
2805 { "menuFile.Paste Game", True },
2806 { "menuFile.Load Position", True },
2807 { "menuFile.Load Next Position", True },
2808 { "menuFile.Load Previous Position", True },
2809 { "menuFile.Reload Same Position", True },
2810 { "menuFile.Paste Position", True },
2811 { "menuMode.Machine White", True },
2812 { "menuMode.Machine Black", True },
2813 { "menuMode.Two Machines", True },
2814 { "menuStep.Retract Move", True },
2820 SetMenuEnables(icsEnables);
2823 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2824 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2831 SetMenuEnables(ncpEnables);
2837 SetMenuEnables(gnuEnables);
2843 SetMenuEnables(cmailEnables);
2849 SetMenuEnables(trainingOnEnables);
2850 if (appData.showButtonBar) {
2851 XtSetSensitive(buttonBarWidget, False);
2857 SetTrainingModeOff()
2859 SetMenuEnables(trainingOffEnables);
2860 if (appData.showButtonBar) {
2861 XtSetSensitive(buttonBarWidget, True);
2866 SetUserThinkingEnables()
2868 if (appData.noChessProgram) return;
2869 SetMenuEnables(userThinkingEnables);
2873 SetMachineThinkingEnables()
2875 if (appData.noChessProgram) return;
2876 SetMenuEnables(machineThinkingEnables);
2878 case MachinePlaysBlack:
2879 case MachinePlaysWhite:
2880 case TwoMachinesPlay:
2881 XtSetSensitive(XtNameToWidget(menuBarWidget,
2882 ModeToWidgetName(gameMode)), True);
2889 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2890 #define HISTORY_SIZE 64
\r
2891 static char *history[HISTORY_SIZE];
\r
2892 int histIn = 0, histP = 0;
\r
2895 SaveInHistory(char *cmd)
\r
2897 if (history[histIn] != NULL) {
\r
2898 free(history[histIn]);
\r
2899 history[histIn] = NULL;
\r
2901 if (*cmd == NULLCHAR) return;
\r
2902 history[histIn] = StrSave(cmd);
\r
2903 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2904 if (history[histIn] != NULL) {
\r
2905 free(history[histIn]);
\r
2906 history[histIn] = NULL;
\r
2912 PrevInHistory(char *cmd)
\r
2915 if (histP == histIn) {
\r
2916 if (history[histIn] != NULL) free(history[histIn]);
\r
2917 history[histIn] = StrSave(cmd);
\r
2919 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2920 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2922 return history[histP];
\r
2928 if (histP == histIn) return NULL;
\r
2929 histP = (histP + 1) % HISTORY_SIZE;
\r
2930 return history[histP];
\r
2932 // end of borrowed code
\r
2934 #define Abs(n) ((n)<0 ? -(n) : (n))
2937 * Find a font that matches "pattern" that is as close as
2938 * possible to the targetPxlSize. Prefer fonts that are k
2939 * pixels smaller to fonts that are k pixels larger. The
2940 * pattern must be in the X Consortium standard format,
2941 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2942 * The return value should be freed with XtFree when no
2945 char *FindFont(pattern, targetPxlSize)
2949 char **fonts, *p, *best, *scalable, *scalableTail;
2950 int i, j, nfonts, minerr, err, pxlSize;
2953 char **missing_list;
2955 char *def_string, *base_fnt_lst, strInt[3];
2957 XFontStruct **fnt_list;
2959 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2960 sprintf(strInt, "%d", targetPxlSize);
2961 p = strstr(pattern, "--");
2962 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2963 strcat(base_fnt_lst, strInt);
2964 strcat(base_fnt_lst, strchr(p + 2, '-'));
2966 if ((fntSet = XCreateFontSet(xDisplay,
2970 &def_string)) == NULL) {
2972 fprintf(stderr, _("Unable to create font set.\n"));
2976 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2978 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2980 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2981 programName, pattern);
2989 for (i=0; i<nfonts; i++) {
2992 if (*p != '-') continue;
2994 if (*p == NULLCHAR) break;
2995 if (*p++ == '-') j++;
2997 if (j < 7) continue;
3000 scalable = fonts[i];
3003 err = pxlSize - targetPxlSize;
3004 if (Abs(err) < Abs(minerr) ||
3005 (minerr > 0 && err < 0 && -err == minerr)) {
3011 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3012 /* If the error is too big and there is a scalable font,
3013 use the scalable font. */
3014 int headlen = scalableTail - scalable;
3015 p = (char *) XtMalloc(strlen(scalable) + 10);
3016 while (isdigit(*scalableTail)) scalableTail++;
3017 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3019 p = (char *) XtMalloc(strlen(best) + 1);
3022 if (appData.debugMode) {
3023 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3024 pattern, targetPxlSize, p);
3027 if (missing_count > 0)
3028 XFreeStringList(missing_list);
3029 XFreeFontSet(xDisplay, fntSet);
3031 XFreeFontNames(fonts);
3038 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3039 | GCBackground | GCFunction | GCPlaneMask;
3040 XGCValues gc_values;
3043 gc_values.plane_mask = AllPlanes;
3044 gc_values.line_width = lineGap;
3045 gc_values.line_style = LineSolid;
3046 gc_values.function = GXcopy;
3048 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3049 gc_values.background = XBlackPixel(xDisplay, xScreen);
3050 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3052 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3053 gc_values.background = XWhitePixel(xDisplay, xScreen);
3054 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3055 XSetFont(xDisplay, coordGC, coordFontID);
3057 // [HGM] make font for holdings counts (white on black0
3058 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3059 gc_values.background = XBlackPixel(xDisplay, xScreen);
3060 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3061 XSetFont(xDisplay, countGC, countFontID);
3063 if (appData.monoMode) {
3064 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3065 gc_values.background = XWhitePixel(xDisplay, xScreen);
3066 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3068 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3069 gc_values.background = XBlackPixel(xDisplay, xScreen);
3070 lightSquareGC = wbPieceGC
3071 = XtGetGC(shellWidget, value_mask, &gc_values);
3073 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3074 gc_values.background = XWhitePixel(xDisplay, xScreen);
3075 darkSquareGC = bwPieceGC
3076 = XtGetGC(shellWidget, value_mask, &gc_values);
3078 if (DefaultDepth(xDisplay, xScreen) == 1) {
3079 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3080 gc_values.function = GXcopyInverted;
3081 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3082 gc_values.function = GXcopy;
3083 if (XBlackPixel(xDisplay, xScreen) == 1) {
3084 bwPieceGC = darkSquareGC;
3085 wbPieceGC = copyInvertedGC;
3087 bwPieceGC = copyInvertedGC;
3088 wbPieceGC = lightSquareGC;
3092 gc_values.foreground = highlightSquareColor;
3093 gc_values.background = highlightSquareColor;
3094 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3096 gc_values.foreground = premoveHighlightColor;
3097 gc_values.background = premoveHighlightColor;
3098 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3100 gc_values.foreground = lightSquareColor;
3101 gc_values.background = darkSquareColor;
3102 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3104 gc_values.foreground = darkSquareColor;
3105 gc_values.background = lightSquareColor;
3106 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3108 gc_values.foreground = jailSquareColor;
3109 gc_values.background = jailSquareColor;
3110 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3112 gc_values.foreground = whitePieceColor;
3113 gc_values.background = darkSquareColor;
3114 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3116 gc_values.foreground = whitePieceColor;
3117 gc_values.background = lightSquareColor;
3118 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3120 gc_values.foreground = whitePieceColor;
3121 gc_values.background = jailSquareColor;
3122 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3124 gc_values.foreground = blackPieceColor;
3125 gc_values.background = darkSquareColor;
3126 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3128 gc_values.foreground = blackPieceColor;
3129 gc_values.background = lightSquareColor;
3130 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3132 gc_values.foreground = blackPieceColor;
3133 gc_values.background = jailSquareColor;
3134 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3138 void loadXIM(xim, xmask, filename, dest, mask)
3151 fp = fopen(filename, "rb");
3153 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3160 for (y=0; y<h; ++y) {
3161 for (x=0; x<h; ++x) {
3166 XPutPixel(xim, x, y, blackPieceColor);
3168 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3171 XPutPixel(xim, x, y, darkSquareColor);
3173 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3176 XPutPixel(xim, x, y, whitePieceColor);
3178 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3181 XPutPixel(xim, x, y, lightSquareColor);
3183 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3189 /* create Pixmap of piece */
3190 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3192 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3195 /* create Pixmap of clipmask
3196 Note: We assume the white/black pieces have the same
3197 outline, so we make only 6 masks. This is okay
3198 since the XPM clipmask routines do the same. */
3200 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3202 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3205 /* now create the 1-bit version */
3206 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3209 values.foreground = 1;
3210 values.background = 0;
3212 /* Don't use XtGetGC, not read only */
3213 maskGC = XCreateGC(xDisplay, *mask,
3214 GCForeground | GCBackground, &values);
3215 XCopyPlane(xDisplay, temp, *mask, maskGC,
3216 0, 0, squareSize, squareSize, 0, 0, 1);
3217 XFreePixmap(xDisplay, temp);
3222 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3224 void CreateXIMPieces()
3229 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3234 /* The XSynchronize calls were copied from CreatePieces.
3235 Not sure if needed, but can't hurt */
3236 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3239 /* temp needed by loadXIM() */
3240 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3241 0, 0, ss, ss, AllPlanes, XYPixmap);
3243 if (strlen(appData.pixmapDirectory) == 0) {
3247 if (appData.monoMode) {
3248 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3252 fprintf(stderr, _("\nLoading XIMs...\n"));
3254 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3255 fprintf(stderr, "%d", piece+1);
3256 for (kind=0; kind<4; kind++) {
3257 fprintf(stderr, ".");
3258 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3259 ExpandPathName(appData.pixmapDirectory),
3260 piece <= (int) WhiteKing ? "" : "w",
3261 pieceBitmapNames[piece],
3263 ximPieceBitmap[kind][piece] =
3264 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3265 0, 0, ss, ss, AllPlanes, XYPixmap);
3266 if (appData.debugMode)
3267 fprintf(stderr, _("(File:%s:) "), buf);
3268 loadXIM(ximPieceBitmap[kind][piece],
3270 &(xpmPieceBitmap2[kind][piece]),
3271 &(ximMaskPm2[piece]));
3272 if(piece <= (int)WhiteKing)
3273 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3275 fprintf(stderr," ");
3277 /* Load light and dark squares */
3278 /* If the LSQ and DSQ pieces don't exist, we will
3279 draw them with solid squares. */
3280 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3281 if (access(buf, 0) != 0) {
3285 fprintf(stderr, _("light square "));
3287 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3288 0, 0, ss, ss, AllPlanes, XYPixmap);
3289 if (appData.debugMode)
3290 fprintf(stderr, _("(File:%s:) "), buf);
3292 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3293 fprintf(stderr, _("dark square "));
3294 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3295 ExpandPathName(appData.pixmapDirectory), ss);
3296 if (appData.debugMode)
3297 fprintf(stderr, _("(File:%s:) "), buf);
3299 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3300 0, 0, ss, ss, AllPlanes, XYPixmap);
3301 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3302 xpmJailSquare = xpmLightSquare;
3304 fprintf(stderr, _("Done.\n"));
3306 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3310 void CreateXPMPieces()
3314 u_int ss = squareSize;
3316 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3317 XpmColorSymbol symbols[4];
3319 /* The XSynchronize calls were copied from CreatePieces.
3320 Not sure if needed, but can't hurt */
3321 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3323 /* Setup translations so piece colors match square colors */
3324 symbols[0].name = "light_piece";
3325 symbols[0].value = appData.whitePieceColor;
3326 symbols[1].name = "dark_piece";
3327 symbols[1].value = appData.blackPieceColor;
3328 symbols[2].name = "light_square";
3329 symbols[2].value = appData.lightSquareColor;
3330 symbols[3].name = "dark_square";
3331 symbols[3].value = appData.darkSquareColor;
3333 attr.valuemask = XpmColorSymbols;
3334 attr.colorsymbols = symbols;
3335 attr.numsymbols = 4;
3337 if (appData.monoMode) {
3338 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3342 if (strlen(appData.pixmapDirectory) == 0) {
3343 XpmPieces* pieces = builtInXpms;
3346 while (pieces->size != squareSize && pieces->size) pieces++;
3347 if (!pieces->size) {
3348 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3351 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3352 for (kind=0; kind<4; kind++) {
3354 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3355 pieces->xpm[piece][kind],
3356 &(xpmPieceBitmap2[kind][piece]),
3357 NULL, &attr)) != 0) {
3358 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3362 if(piece <= (int) WhiteKing)
3363 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3367 xpmJailSquare = xpmLightSquare;
3371 fprintf(stderr, _("\nLoading XPMs...\n"));
3374 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3375 fprintf(stderr, "%d ", piece+1);
3376 for (kind=0; kind<4; kind++) {
3377 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3378 ExpandPathName(appData.pixmapDirectory),
3379 piece > (int) WhiteKing ? "w" : "",
3380 pieceBitmapNames[piece],
3382 if (appData.debugMode) {
3383 fprintf(stderr, _("(File:%s:) "), buf);
3385 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3386 &(xpmPieceBitmap2[kind][piece]),
3387 NULL, &attr)) != 0) {
3388 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3389 // [HGM] missing: read of unorthodox piece failed; substitute King.
3390 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3391 ExpandPathName(appData.pixmapDirectory),
3393 if (appData.debugMode) {
3394 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3396 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3397 &(xpmPieceBitmap2[kind][piece]),
3401 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3406 if(piece <= (int) WhiteKing)
3407 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3410 /* Load light and dark squares */
3411 /* If the LSQ and DSQ pieces don't exist, we will
3412 draw them with solid squares. */
3413 fprintf(stderr, _("light square "));
3414 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3415 if (access(buf, 0) != 0) {
3419 if (appData.debugMode)
3420 fprintf(stderr, _("(File:%s:) "), buf);
3422 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3423 &xpmLightSquare, NULL, &attr)) != 0) {
3424 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3427 fprintf(stderr, _("dark square "));
3428 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3429 ExpandPathName(appData.pixmapDirectory), ss);
3430 if (appData.debugMode) {
3431 fprintf(stderr, _("(File:%s:) "), buf);
3433 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3434 &xpmDarkSquare, NULL, &attr)) != 0) {
3435 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3439 xpmJailSquare = xpmLightSquare;
3440 fprintf(stderr, _("Done.\n"));
3442 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3445 #endif /* HAVE_LIBXPM */
3448 /* No built-in bitmaps */
3453 u_int ss = squareSize;
3455 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3458 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3459 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3460 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3461 pieceBitmapNames[piece],
3462 ss, kind == SOLID ? 's' : 'o');
3463 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3464 if(piece <= (int)WhiteKing)
3465 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3469 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3473 /* With built-in bitmaps */
3476 BuiltInBits* bib = builtInBits;
3479 u_int ss = squareSize;
3481 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3484 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3486 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3487 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3488 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3489 pieceBitmapNames[piece],
3490 ss, kind == SOLID ? 's' : 'o');
3491 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3492 bib->bits[kind][piece], ss, ss);
3493 if(piece <= (int)WhiteKing)
3494 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3498 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3503 void ReadBitmap(pm, name, bits, wreq, hreq)
3506 unsigned char bits[];
3512 char msg[MSG_SIZ], fullname[MSG_SIZ];
3514 if (*appData.bitmapDirectory != NULLCHAR) {
3515 strcpy(fullname, appData.bitmapDirectory);
3516 strcat(fullname, "/");
3517 strcat(fullname, name);
3518 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3519 &w, &h, pm, &x_hot, &y_hot);
3520 fprintf(stderr, "load %s\n", name);
3521 if (errcode != BitmapSuccess) {
3523 case BitmapOpenFailed:
3524 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3526 case BitmapFileInvalid:
3527 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3529 case BitmapNoMemory:
3530 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3534 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3538 fprintf(stderr, _("%s: %s...using built-in\n"),
3540 } else if (w != wreq || h != hreq) {
3542 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3543 programName, fullname, w, h, wreq, hreq);
3549 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3558 if (lineGap == 0) return;
3560 /* [HR] Split this into 2 loops for non-square boards. */
3562 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3563 gridSegments[i].x1 = 0;
3564 gridSegments[i].x2 =
3565 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3566 gridSegments[i].y1 = gridSegments[i].y2
3567 = lineGap / 2 + (i * (squareSize + lineGap));
3570 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3571 gridSegments[j + i].y1 = 0;
3572 gridSegments[j + i].y2 =
3573 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3574 gridSegments[j + i].x1 = gridSegments[j + i].x2
3575 = lineGap / 2 + (j * (squareSize + lineGap));
3579 static void MenuBarSelect(w, addr, index)
3584 XtActionProc proc = (XtActionProc) addr;
3586 (proc)(NULL, NULL, NULL, NULL);
3589 void CreateMenuBarPopup(parent, name, mb)
3599 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3602 XtSetArg(args[j], XtNleftMargin, 20); j++;
3603 XtSetArg(args[j], XtNrightMargin, 20); j++;
3605 while (mi->string != NULL) {
3606 if (strcmp(mi->string, "----") == 0) {
3607 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3610 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3611 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3613 XtAddCallback(entry, XtNcallback,
3614 (XtCallbackProc) MenuBarSelect,
3615 (caddr_t) mi->proc);
3621 Widget CreateMenuBar(mb)
3625 Widget anchor, menuBar;
3627 char menuName[MSG_SIZ];
3630 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3631 XtSetArg(args[j], XtNvSpace, 0); j++;
3632 XtSetArg(args[j], XtNborderWidth, 0); j++;
3633 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3634 formWidget, args, j);
3636 while (mb->name != NULL) {
3637 strcpy(menuName, "menu");
3638 strcat(menuName, mb->name);
3640 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3643 shortName[0] = _(mb->name)[0];
3644 shortName[1] = NULLCHAR;
3645 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3648 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3651 XtSetArg(args[j], XtNborderWidth, 0); j++;
3652 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3654 CreateMenuBarPopup(menuBar, menuName, mb);
3660 Widget CreateButtonBar(mi)
3664 Widget button, buttonBar;
3668 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3670 XtSetArg(args[j], XtNhSpace, 0); j++;
3672 XtSetArg(args[j], XtNborderWidth, 0); j++;
3673 XtSetArg(args[j], XtNvSpace, 0); j++;
3674 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3675 formWidget, args, j);
3677 while (mi->string != NULL) {
3680 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3681 XtSetArg(args[j], XtNborderWidth, 0); j++;
3683 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3684 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3685 buttonBar, args, j);
3686 XtAddCallback(button, XtNcallback,
3687 (XtCallbackProc) MenuBarSelect,
3688 (caddr_t) mi->proc);
3695 CreatePieceMenu(name, color)
3702 ChessSquare selection;
3704 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3705 boardWidget, args, 0);
3707 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3708 String item = pieceMenuStrings[color][i];
3710 if (strcmp(item, "----") == 0) {
3711 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3714 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3715 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3717 selection = pieceMenuTranslation[color][i];
3718 XtAddCallback(entry, XtNcallback,
3719 (XtCallbackProc) PieceMenuSelect,
3720 (caddr_t) selection);
3721 if (selection == WhitePawn || selection == BlackPawn) {
3722 XtSetArg(args[0], XtNpopupOnEntry, entry);
3723 XtSetValues(menu, args, 1);
3736 ChessSquare selection;
3738 whitePieceMenu = CreatePieceMenu("menuW", 0);
3739 blackPieceMenu = CreatePieceMenu("menuB", 1);
3741 XtRegisterGrabAction(PieceMenuPopup, True,
3742 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3743 GrabModeAsync, GrabModeAsync);
3745 XtSetArg(args[0], XtNlabel, _("Drop"));
3746 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3747 boardWidget, args, 1);
3748 for (i = 0; i < DROP_MENU_SIZE; i++) {
3749 String item = dropMenuStrings[i];
3751 if (strcmp(item, "----") == 0) {
3752 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3755 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3756 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3758 selection = dropMenuTranslation[i];
3759 XtAddCallback(entry, XtNcallback,
3760 (XtCallbackProc) DropMenuSelect,
3761 (caddr_t) selection);
3766 void SetupDropMenu()
3774 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3775 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3776 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3777 dmEnables[i].piece);
3778 XtSetSensitive(entry, p != NULL || !appData.testLegality
3779 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3780 && !appData.icsActive));
3782 while (p && *p++ == dmEnables[i].piece) count++;
3783 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3785 XtSetArg(args[j], XtNlabel, label); j++;
3786 XtSetValues(entry, args, j);
3790 void PieceMenuPopup(w, event, params, num_params)
3794 Cardinal *num_params;
3796 String whichMenu; int menuNr;
3797 if (event->type == ButtonRelease)
3798 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3799 else if (event->type == ButtonPress)
3800 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3802 case 0: whichMenu = params[0]; break;
3803 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3805 case -1: if (errorUp) ErrorPopDown();
3808 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3811 static void PieceMenuSelect(w, piece, junk)
3816 if (pmFromX < 0 || pmFromY < 0) return;
3817 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3820 static void DropMenuSelect(w, piece, junk)
3825 if (pmFromX < 0 || pmFromY < 0) return;
3826 DropMenuEvent(piece, pmFromX, pmFromY);
3829 void WhiteClock(w, event, prms, nprms)
3835 if (gameMode == EditPosition || gameMode == IcsExamining) {
3836 SetWhiteToPlayEvent();
3837 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3842 void BlackClock(w, event, prms, nprms)
3848 if (gameMode == EditPosition || gameMode == IcsExamining) {
3849 SetBlackToPlayEvent();
3850 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3857 * If the user selects on a border boundary, return -1; if off the board,
3858 * return -2. Otherwise map the event coordinate to the square.
3860 int EventToSquare(x, limit)
3868 if ((x % (squareSize + lineGap)) >= squareSize)
3870 x /= (squareSize + lineGap);
3876 static void do_flash_delay(msec)
3882 static void drawHighlight(file, rank, gc)
3888 if (lineGap == 0 || appData.blindfold) return;
3891 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3892 (squareSize + lineGap);
3893 y = lineGap/2 + rank * (squareSize + lineGap);
3895 x = lineGap/2 + file * (squareSize + lineGap);
3896 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3897 (squareSize + lineGap);
3900 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3901 squareSize+lineGap, squareSize+lineGap);
3904 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3905 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3908 SetHighlights(fromX, fromY, toX, toY)
3909 int fromX, fromY, toX, toY;
3911 if (hi1X != fromX || hi1Y != fromY) {
3912 if (hi1X >= 0 && hi1Y >= 0) {
3913 drawHighlight(hi1X, hi1Y, lineGC);
3915 } // [HGM] first erase both, then draw new!
3916 if (hi2X != toX || hi2Y != toY) {
3917 if (hi2X >= 0 && hi2Y >= 0) {
3918 drawHighlight(hi2X, hi2Y, lineGC);
3921 if (hi1X != fromX || hi1Y != fromY) {
3922 if (fromX >= 0 && fromY >= 0) {
3923 drawHighlight(fromX, fromY, highlineGC);
3926 if (hi2X != toX || hi2Y != toY) {
3927 if (toX >= 0 && toY >= 0) {
3928 drawHighlight(toX, toY, highlineGC);
3940 SetHighlights(-1, -1, -1, -1);
3945 SetPremoveHighlights(fromX, fromY, toX, toY)
3946 int fromX, fromY, toX, toY;
3948 if (pm1X != fromX || pm1Y != fromY) {
3949 if (pm1X >= 0 && pm1Y >= 0) {
3950 drawHighlight(pm1X, pm1Y, lineGC);
3952 if (fromX >= 0 && fromY >= 0) {
3953 drawHighlight(fromX, fromY, prelineGC);
3956 if (pm2X != toX || pm2Y != toY) {
3957 if (pm2X >= 0 && pm2Y >= 0) {
3958 drawHighlight(pm2X, pm2Y, lineGC);
3960 if (toX >= 0 && toY >= 0) {
3961 drawHighlight(toX, toY, prelineGC);
3971 ClearPremoveHighlights()
3973 SetPremoveHighlights(-1, -1, -1, -1);
3976 static void BlankSquare(x, y, color, piece, dest)
3981 if (useImages && useImageSqs) {
3985 pm = xpmLightSquare;
3990 case 2: /* neutral */
3995 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3996 squareSize, squareSize, x, y);
4006 case 2: /* neutral */
4011 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4016 I split out the routines to draw a piece so that I could
4017 make a generic flash routine.
4019 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4021 int square_color, x, y;
4024 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4025 switch (square_color) {
4027 case 2: /* neutral */
4029 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4030 ? *pieceToOutline(piece)
4031 : *pieceToSolid(piece),
4032 dest, bwPieceGC, 0, 0,
4033 squareSize, squareSize, x, y);
4036 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4037 ? *pieceToSolid(piece)
4038 : *pieceToOutline(piece),
4039 dest, wbPieceGC, 0, 0,
4040 squareSize, squareSize, x, y);
4045 static void monoDrawPiece(piece, square_color, x, y, dest)
4047 int square_color, x, y;
4050 switch (square_color) {
4052 case 2: /* neutral */
4054 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4055 ? *pieceToOutline(piece)
4056 : *pieceToSolid(piece),
4057 dest, bwPieceGC, 0, 0,
4058 squareSize, squareSize, x, y, 1);
4061 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4062 ? *pieceToSolid(piece)
4063 : *pieceToOutline(piece),
4064 dest, wbPieceGC, 0, 0,
4065 squareSize, squareSize, x, y, 1);
4070 static void colorDrawPiece(piece, square_color, x, y, dest)
4072 int square_color, x, y;
4075 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4076 switch (square_color) {
4078 XCopyPlane(xDisplay, *pieceToSolid(piece),
4079 dest, (int) piece < (int) BlackPawn
4080 ? wlPieceGC : blPieceGC, 0, 0,
4081 squareSize, squareSize, x, y, 1);
4084 XCopyPlane(xDisplay, *pieceToSolid(piece),
4085 dest, (int) piece < (int) BlackPawn
4086 ? wdPieceGC : bdPieceGC, 0, 0,
4087 squareSize, squareSize, x, y, 1);
4089 case 2: /* neutral */
4091 XCopyPlane(xDisplay, *pieceToSolid(piece),
4092 dest, (int) piece < (int) BlackPawn
4093 ? wjPieceGC : bjPieceGC, 0, 0,
4094 squareSize, squareSize, x, y, 1);
4099 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4101 int square_color, x, y;
4106 switch (square_color) {
4108 case 2: /* neutral */
4110 if ((int)piece < (int) BlackPawn) {
4118 if ((int)piece < (int) BlackPawn) {
4126 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4127 dest, wlPieceGC, 0, 0,
4128 squareSize, squareSize, x, y);
4131 typedef void (*DrawFunc)();
4133 DrawFunc ChooseDrawFunc()
4135 if (appData.monoMode) {
4136 if (DefaultDepth(xDisplay, xScreen) == 1) {
4137 return monoDrawPiece_1bit;
4139 return monoDrawPiece;
4143 return colorDrawPieceImage;
4145 return colorDrawPiece;
4149 /* [HR] determine square color depending on chess variant. */
4150 static int SquareColor(row, column)
4155 if (gameInfo.variant == VariantXiangqi) {
4156 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4158 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4160 } else if (row <= 4) {
4166 square_color = ((column + row) % 2) == 1;
4169 /* [hgm] holdings: next line makes all holdings squares light */
4170 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4172 return square_color;
4175 void DrawSquare(row, column, piece, do_flash)
4176 int row, column, do_flash;
4179 int square_color, x, y, direction, font_ascent, font_descent;
4182 XCharStruct overall;
4186 /* Calculate delay in milliseconds (2-delays per complete flash) */
4187 flash_delay = 500 / appData.flashRate;
4190 x = lineGap + ((BOARD_WIDTH-1)-column) *
4191 (squareSize + lineGap);
4192 y = lineGap + row * (squareSize + lineGap);
4194 x = lineGap + column * (squareSize + lineGap);
4195 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4196 (squareSize + lineGap);
4199 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4201 square_color = SquareColor(row, column);
4203 if ( // [HGM] holdings: blank out area between board and holdings
4204 column == BOARD_LEFT-1 || column == BOARD_RGHT
4205 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4206 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4207 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4209 // [HGM] print piece counts next to holdings
4210 string[1] = NULLCHAR;
4211 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4212 string[0] = '0' + piece;
4213 XTextExtents(countFontStruct, string, 1, &direction,
4214 &font_ascent, &font_descent, &overall);
4215 if (appData.monoMode) {
4216 XDrawImageString(xDisplay, xBoardWindow, countGC,
4217 x + squareSize - overall.width - 2,
4218 y + font_ascent + 1, string, 1);
4220 XDrawString(xDisplay, xBoardWindow, countGC,
4221 x + squareSize - overall.width - 2,
4222 y + font_ascent + 1, string, 1);
4225 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4226 string[0] = '0' + piece;
4227 XTextExtents(countFontStruct, string, 1, &direction,
4228 &font_ascent, &font_descent, &overall);
4229 if (appData.monoMode) {
4230 XDrawImageString(xDisplay, xBoardWindow, countGC,
4231 x + 2, y + font_ascent + 1, string, 1);
4233 XDrawString(xDisplay, xBoardWindow, countGC,
4234 x + 2, y + font_ascent + 1, string, 1);
4238 if (piece == EmptySquare || appData.blindfold) {
4239 BlankSquare(x, y, square_color, piece, xBoardWindow);
4241 drawfunc = ChooseDrawFunc();
4242 if (do_flash && appData.flashCount > 0) {
4243 for (i=0; i<appData.flashCount; ++i) {
4245 drawfunc(piece, square_color, x, y, xBoardWindow);
4246 XSync(xDisplay, False);
4247 do_flash_delay(flash_delay);
4249 BlankSquare(x, y, square_color, piece, xBoardWindow);
4250 XSync(xDisplay, False);
4251 do_flash_delay(flash_delay);
4254 drawfunc(piece, square_color, x, y, xBoardWindow);
4258 string[1] = NULLCHAR;
4259 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4260 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4261 string[0] = 'a' + column - BOARD_LEFT;
4262 XTextExtents(coordFontStruct, string, 1, &direction,
4263 &font_ascent, &font_descent, &overall);
4264 if (appData.monoMode) {
4265 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4266 x + squareSize - overall.width - 2,
4267 y + squareSize - font_descent - 1, string, 1);
4269 XDrawString(xDisplay, xBoardWindow, coordGC,
4270 x + squareSize - overall.width - 2,
4271 y + squareSize - font_descent - 1, string, 1);
4274 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4275 string[0] = ONE + row;
4276 XTextExtents(coordFontStruct, string, 1, &direction,
4277 &font_ascent, &font_descent, &overall);
4278 if (appData.monoMode) {
4279 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4280 x + 2, y + font_ascent + 1, string, 1);
4282 XDrawString(xDisplay, xBoardWindow, coordGC,
4283 x + 2, y + font_ascent + 1, string, 1);
4286 if(marker[row][column]) {
4287 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4288 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4293 /* Why is this needed on some versions of X? */
4294 void EventProc(widget, unused, event)
4299 if (!XtIsRealized(widget))
4302 switch (event->type) {
4304 if (event->xexpose.count > 0) return; /* no clipping is done */
4305 XDrawPosition(widget, True, NULL);
4308 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4315 void DrawPosition(fullRedraw, board)
4316 /*Boolean*/int fullRedraw;
4319 XDrawPosition(boardWidget, fullRedraw, board);
4322 /* Returns 1 if there are "too many" differences between b1 and b2
4323 (i.e. more than 1 move was made) */
4324 static int too_many_diffs(b1, b2)
4330 for (i=0; i<BOARD_HEIGHT; ++i) {
4331 for (j=0; j<BOARD_WIDTH; ++j) {
4332 if (b1[i][j] != b2[i][j]) {
4333 if (++c > 4) /* Castling causes 4 diffs */
4342 /* Matrix describing castling maneuvers */
4343 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4344 static int castling_matrix[4][5] = {
4345 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4346 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4347 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4348 { 7, 7, 4, 5, 6 } /* 0-0, black */
4351 /* Checks whether castling occurred. If it did, *rrow and *rcol
4352 are set to the destination (row,col) of the rook that moved.
4354 Returns 1 if castling occurred, 0 if not.
4356 Note: Only handles a max of 1 castling move, so be sure
4357 to call too_many_diffs() first.
4359 static int check_castle_draw(newb, oldb, rrow, rcol)
4366 /* For each type of castling... */
4367 for (i=0; i<4; ++i) {
4368 r = castling_matrix[i];
4370 /* Check the 4 squares involved in the castling move */
4372 for (j=1; j<=4; ++j) {
4373 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4380 /* All 4 changed, so it must be a castling move */
4389 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4390 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4392 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4395 void DrawSeekBackground( int left, int top, int right, int bottom )
4397 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4400 void DrawSeekText(char *buf, int x, int y)
4402 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4405 void DrawSeekDot(int x, int y, int colorNr)
4407 int square = colorNr & 0x80;
4410 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4412 XFillRectangle(xDisplay, xBoardWindow, color,
4413 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4415 XFillArc(xDisplay, xBoardWindow, color,
4416 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4419 static int damage[BOARD_RANKS][BOARD_FILES];
4422 * event handler for redrawing the board
4424 void XDrawPosition(w, repaint, board)
4426 /*Boolean*/int repaint;
4430 static int lastFlipView = 0;
4431 static int lastBoardValid = 0;
4432 static Board lastBoard;
4436 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4437 if(twoBoards) repaint = True;
4439 if (board == NULL) {
4440 if (!lastBoardValid) return;
4443 if (!lastBoardValid || lastFlipView != flipView) {
4444 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4445 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4450 * It would be simpler to clear the window with XClearWindow()
4451 * but this causes a very distracting flicker.
4454 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4456 /* If too much changes (begin observing new game, etc.), don't
4458 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4460 /* Special check for castling so we don't flash both the king
4461 and the rook (just flash the king). */
4463 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4464 /* Draw rook with NO flashing. King will be drawn flashing later */
4465 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4466 lastBoard[rrow][rcol] = board[rrow][rcol];
4470 /* First pass -- Draw (newly) empty squares and repair damage.
4471 This prevents you from having a piece show up twice while it
4472 is flashing on its new square */
4473 for (i = 0; i < BOARD_HEIGHT; i++)
4474 for (j = 0; j < BOARD_WIDTH; j++)
4475 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4477 DrawSquare(i, j, board[i][j], 0);
4478 damage[i][j] = False;
4481 /* Second pass -- Draw piece(s) in new position and flash them */
4482 for (i = 0; i < BOARD_HEIGHT; i++)
4483 for (j = 0; j < BOARD_WIDTH; j++)
4484 if (board[i][j] != lastBoard[i][j]) {
4485 DrawSquare(i, j, board[i][j], do_flash);
4489 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4490 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4491 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4493 for (i = 0; i < BOARD_HEIGHT; i++)
4494 for (j = 0; j < BOARD_WIDTH; j++) {
4495 DrawSquare(i, j, board[i][j], 0);
4496 damage[i][j] = False;
4500 CopyBoard(lastBoard, board);
4502 lastFlipView = flipView;
4504 /* Draw highlights */
4505 if (pm1X >= 0 && pm1Y >= 0) {
4506 drawHighlight(pm1X, pm1Y, prelineGC);
4508 if (pm2X >= 0 && pm2Y >= 0) {
4509 drawHighlight(pm2X, pm2Y, prelineGC);
4511 if (hi1X >= 0 && hi1Y >= 0) {
4512 drawHighlight(hi1X, hi1Y, highlineGC);
4514 if (hi2X >= 0 && hi2Y >= 0) {
4515 drawHighlight(hi2X, hi2Y, highlineGC);
4518 /* If piece being dragged around board, must redraw that too */
4521 XSync(xDisplay, False);
4526 * event handler for redrawing the board
4528 void DrawPositionProc(w, event, prms, nprms)
4534 XDrawPosition(w, True, NULL);
4539 * event handler for parsing user moves
4541 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4542 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4543 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4544 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4545 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4546 // and at the end FinishMove() to perform the move after optional promotion popups.
4547 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4548 void HandleUserMove(w, event, prms, nprms)
4554 if (w != boardWidget || errorExitStatus != -1) return;
4557 if (event->type == ButtonPress) {
4558 XtPopdown(promotionShell);
4559 XtDestroyWidget(promotionShell);
4560 promotionUp = False;
4568 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4569 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4570 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4573 void AnimateUserMove (Widget w, XEvent * event,
4574 String * params, Cardinal * nParams)
4576 DragPieceMove(event->xmotion.x, event->xmotion.y);
4579 void HandlePV (Widget w, XEvent * event,
4580 String * params, Cardinal * nParams)
4581 { // [HGM] pv: walk PV
4582 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4585 Widget CommentCreate(name, text, mutable, callback, lines)
4587 int /*Boolean*/ mutable;
4588 XtCallbackProc callback;
4592 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4597 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4598 XtGetValues(boardWidget, args, j);
4601 XtSetArg(args[j], XtNresizable, True); j++;
4604 XtCreatePopupShell(name, topLevelShellWidgetClass,
4605 shellWidget, args, j);
4608 XtCreatePopupShell(name, transientShellWidgetClass,
4609 shellWidget, args, j);
4612 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4613 layoutArgs, XtNumber(layoutArgs));
4615 XtCreateManagedWidget("form", formWidgetClass, layout,
4616 formArgs, XtNumber(formArgs));
4620 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4621 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4623 XtSetArg(args[j], XtNstring, text); j++;
4624 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4625 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4626 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4627 XtSetArg(args[j], XtNright, XtChainRight); j++;
4628 XtSetArg(args[j], XtNresizable, True); j++;
4629 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4630 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4631 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4632 XtSetArg(args[j], XtNautoFill, True); j++;
4633 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4635 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4639 XtSetArg(args[j], XtNfromVert, edit); j++;
4640 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4641 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4642 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4643 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4645 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4646 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4649 XtSetArg(args[j], XtNfromVert, edit); j++;
4650 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4651 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4652 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4653 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4654 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4656 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4657 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4660 XtSetArg(args[j], XtNfromVert, edit); j++;
4661 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4662 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4663 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4664 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4665 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4667 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4668 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4671 XtSetArg(args[j], XtNfromVert, edit); j++;
4672 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4673 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4674 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4675 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4677 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4678 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4681 XtSetArg(args[j], XtNfromVert, edit); j++;
4682 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4683 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4684 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4685 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4686 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4688 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4689 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4692 XtRealizeWidget(shell);
4694 if (commentX == -1) {
4697 Dimension pw_height;
4698 Dimension ew_height;
4701 XtSetArg(args[j], XtNheight, &ew_height); j++;
4702 XtGetValues(edit, args, j);
4705 XtSetArg(args[j], XtNheight, &pw_height); j++;
4706 XtGetValues(shell, args, j);
4707 commentH = pw_height + (lines - 1) * ew_height;
4708 commentW = bw_width - 16;
4710 XSync(xDisplay, False);
4712 /* This code seems to tickle an X bug if it is executed too soon
4713 after xboard starts up. The coordinates get transformed as if
4714 the main window was positioned at (0, 0).
4716 XtTranslateCoords(shellWidget,
4717 (bw_width - commentW) / 2, 0 - commentH / 2,
4718 &commentX, &commentY);
4720 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4721 RootWindowOfScreen(XtScreen(shellWidget)),
4722 (bw_width - commentW) / 2, 0 - commentH / 2,
4727 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4730 if(wpComment.width > 0) {
4731 commentX = wpComment.x;
4732 commentY = wpComment.y;
4733 commentW = wpComment.width;
4734 commentH = wpComment.height;
4738 XtSetArg(args[j], XtNheight, commentH); j++;
4739 XtSetArg(args[j], XtNwidth, commentW); j++;
4740 XtSetArg(args[j], XtNx, commentX); j++;
4741 XtSetArg(args[j], XtNy, commentY); j++;
4742 XtSetValues(shell, args, j);
4743 XtSetKeyboardFocus(shell, edit);
4748 /* Used for analysis window and ICS input window */
4749 Widget MiscCreate(name, text, mutable, callback, lines)
4751 int /*Boolean*/ mutable;
4752 XtCallbackProc callback;
4756 Widget shell, layout, form, edit;
4758 Dimension bw_width, pw_height, ew_height, w, h;
4764 XtSetArg(args[j], XtNresizable, True); j++;
4767 XtCreatePopupShell(name, topLevelShellWidgetClass,
4768 shellWidget, args, j);
4771 XtCreatePopupShell(name, transientShellWidgetClass,
4772 shellWidget, args, j);
4775 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4776 layoutArgs, XtNumber(layoutArgs));
4778 XtCreateManagedWidget("form", formWidgetClass, layout,
4779 formArgs, XtNumber(formArgs));
4783 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4784 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4786 XtSetArg(args[j], XtNstring, text); j++;
4787 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4788 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4789 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4790 XtSetArg(args[j], XtNright, XtChainRight); j++;
4791 XtSetArg(args[j], XtNresizable, True); j++;
4792 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4793 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4794 XtSetArg(args[j], XtNautoFill, True); j++;
4795 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4797 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4799 XtRealizeWidget(shell);
4802 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4803 XtGetValues(boardWidget, args, j);
4806 XtSetArg(args[j], XtNheight, &ew_height); j++;
4807 XtGetValues(edit, args, j);
4810 XtSetArg(args[j], XtNheight, &pw_height); j++;
4811 XtGetValues(shell, args, j);
4812 h = pw_height + (lines - 1) * ew_height;
4815 XSync(xDisplay, False);
4817 /* This code seems to tickle an X bug if it is executed too soon
4818 after xboard starts up. The coordinates get transformed as if
4819 the main window was positioned at (0, 0).
4821 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4823 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4824 RootWindowOfScreen(XtScreen(shellWidget)),
4825 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4829 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4832 XtSetArg(args[j], XtNheight, h); j++;
4833 XtSetArg(args[j], XtNwidth, w); j++;
4834 XtSetArg(args[j], XtNx, x); j++;
4835 XtSetArg(args[j], XtNy, y); j++;
4836 XtSetValues(shell, args, j);
4842 static int savedIndex; /* gross that this is global */
4844 void EditCommentPopUp(index, title, text)
4853 if (text == NULL) text = "";
4855 if (editShell == NULL) {
4857 CommentCreate(title, text, True, EditCommentCallback, 4);
4858 XtRealizeWidget(editShell);
4859 CatchDeleteWindow(editShell, "EditCommentPopDown");
4861 edit = XtNameToWidget(editShell, "*form.text");
4863 XtSetArg(args[j], XtNstring, text); j++;
4864 XtSetValues(edit, args, j);
4866 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4867 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4868 XtSetValues(editShell, args, j);
4871 XtPopup(editShell, XtGrabNone);
4875 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4876 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4880 void EditCommentCallback(w, client_data, call_data)
4882 XtPointer client_data, call_data;
4890 XtSetArg(args[j], XtNlabel, &name); j++;
4891 XtGetValues(w, args, j);
4893 if (strcmp(name, _("ok")) == 0) {
4894 edit = XtNameToWidget(editShell, "*form.text");
4896 XtSetArg(args[j], XtNstring, &val); j++;
4897 XtGetValues(edit, args, j);
4898 ReplaceComment(savedIndex, val);
4899 EditCommentPopDown();
4900 } else if (strcmp(name, _("cancel")) == 0) {
4901 EditCommentPopDown();
4902 } else if (strcmp(name, _("clear")) == 0) {
4903 edit = XtNameToWidget(editShell, "*form.text");
4904 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4905 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4909 void EditCommentPopDown()
4914 if (!editUp) return;
4916 XtSetArg(args[j], XtNx, &commentX); j++;
4917 XtSetArg(args[j], XtNy, &commentY); j++;
4918 XtSetArg(args[j], XtNheight, &commentH); j++;
4919 XtSetArg(args[j], XtNwidth, &commentW); j++;
4920 XtGetValues(editShell, args, j);
4921 XtPopdown(editShell);
4924 XtSetArg(args[j], XtNleftBitmap, None); j++;
4925 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4929 void ICSInputBoxPopUp()
4934 char *title = _("ICS Input");
4937 if (ICSInputShell == NULL) {
4938 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4939 tr = XtParseTranslationTable(ICSInputTranslations);
4940 edit = XtNameToWidget(ICSInputShell, "*form.text");
4941 XtOverrideTranslations(edit, tr);
4942 XtRealizeWidget(ICSInputShell);
4943 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4946 edit = XtNameToWidget(ICSInputShell, "*form.text");
4948 XtSetArg(args[j], XtNstring, ""); j++;
4949 XtSetValues(edit, args, j);
4951 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4952 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4953 XtSetValues(ICSInputShell, args, j);
4956 XtPopup(ICSInputShell, XtGrabNone);
4957 XtSetKeyboardFocus(ICSInputShell, edit);
4959 ICSInputBoxUp = True;
4961 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4962 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4966 void ICSInputSendText()
4973 edit = XtNameToWidget(ICSInputShell, "*form.text");
4975 XtSetArg(args[j], XtNstring, &val); j++;
4976 XtGetValues(edit, args, j);
4978 SendMultiLineToICS(val);
4979 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4980 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4983 void ICSInputBoxPopDown()
4988 if (!ICSInputBoxUp) return;
4990 XtPopdown(ICSInputShell);
4991 ICSInputBoxUp = False;
4993 XtSetArg(args[j], XtNleftBitmap, None); j++;
4994 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4998 void CommentPopUp(title, text)
5005 if (commentShell == NULL) {
5007 CommentCreate(title, text, False, CommentCallback, 4);
5008 XtRealizeWidget(commentShell);
5009 CatchDeleteWindow(commentShell, "CommentPopDown");
5011 edit = XtNameToWidget(commentShell, "*form.text");
5013 XtSetArg(args[j], XtNstring, text); j++;
5014 XtSetValues(edit, args, j);
5016 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5017 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5018 XtSetValues(commentShell, args, j);
5021 XtPopup(commentShell, XtGrabNone);
5022 XSync(xDisplay, False);
5027 void CommentCallback(w, client_data, call_data)
5029 XtPointer client_data, call_data;
5036 XtSetArg(args[j], XtNlabel, &name); j++;
5037 XtGetValues(w, args, j);
5039 if (strcmp(name, _("close")) == 0) {
5041 } else if (strcmp(name, _("edit")) == 0) {
5048 void CommentPopDown()
5053 if (!commentUp) return;
5055 XtSetArg(args[j], XtNx, &commentX); j++;
5056 XtSetArg(args[j], XtNy, &commentY); j++;
5057 XtSetArg(args[j], XtNwidth, &commentW); j++;
5058 XtSetArg(args[j], XtNheight, &commentH); j++;
5059 XtGetValues(commentShell, args, j);
5060 XtPopdown(commentShell);
5061 XSync(xDisplay, False);
5065 void FileNamePopUp(label, def, proc, openMode)
5072 Widget popup, layout, dialog, edit;
5078 fileProc = proc; /* I can't see a way not */
5079 fileOpenMode = openMode; /* to use globals here */
5080 { // [HGM] use file-selector dialog stolen from Ghostview
5082 int index; // this is not supported yet
5084 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5085 NULL, openMode, NULL, &name))
5086 (void) (*fileProc)(f, index=0, name);
5090 void FileNamePopDown()
5092 if (!filenameUp) return;
5093 XtPopdown(fileNameShell);
5094 XtDestroyWidget(fileNameShell);
5099 void FileNameCallback(w, client_data, call_data)
5101 XtPointer client_data, call_data;
5106 XtSetArg(args[0], XtNlabel, &name);
5107 XtGetValues(w, args, 1);
5109 if (strcmp(name, _("cancel")) == 0) {
5114 FileNameAction(w, NULL, NULL, NULL);
5117 void FileNameAction(w, event, prms, nprms)
5129 name = XawDialogGetValueString(w = XtParent(w));
5131 if ((name != NULL) && (*name != NULLCHAR)) {
5133 XtPopdown(w = XtParent(XtParent(w)));
5137 p = strrchr(buf, ' ');
5144 fullname = ExpandPathName(buf);
5146 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5149 f = fopen(fullname, fileOpenMode);
5151 DisplayError(_("Failed to open file"), errno);
5153 (void) (*fileProc)(f, index, buf);
5160 XtPopdown(w = XtParent(XtParent(w)));
5166 void PromotionPopUp()
5169 Widget dialog, layout;
5171 Dimension bw_width, pw_width;
5175 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5176 XtGetValues(boardWidget, args, j);
5179 XtSetArg(args[j], XtNresizable, True); j++;
5180 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5182 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5183 shellWidget, args, j);
5185 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5186 layoutArgs, XtNumber(layoutArgs));
5189 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5190 XtSetArg(args[j], XtNborderWidth, 0); j++;
5191 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5194 if(gameInfo.variant != VariantShogi) {
5195 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5196 (XtPointer) dialog);
5197 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5198 (XtPointer) dialog);
5199 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5200 (XtPointer) dialog);
5201 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5202 (XtPointer) dialog);
5203 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5204 gameInfo.variant == VariantGiveaway) {
5205 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5206 (XtPointer) dialog);
5208 if(gameInfo.variant == VariantCapablanca ||
5209 gameInfo.variant == VariantGothic ||
5210 gameInfo.variant == VariantCapaRandom) {
5211 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5212 (XtPointer) dialog);
5213 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5214 (XtPointer) dialog);
5216 } else // [HGM] shogi
5218 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5219 (XtPointer) dialog);
5220 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5221 (XtPointer) dialog);
5223 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5224 (XtPointer) dialog);
5226 XtRealizeWidget(promotionShell);
5227 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5230 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5231 XtGetValues(promotionShell, args, j);
5233 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5234 lineGap + squareSize/3 +
5235 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5236 0 : 6*(squareSize + lineGap)), &x, &y);
5239 XtSetArg(args[j], XtNx, x); j++;
5240 XtSetArg(args[j], XtNy, y); j++;
5241 XtSetValues(promotionShell, args, j);
5243 XtPopup(promotionShell, XtGrabNone);
5248 void PromotionPopDown()
5250 if (!promotionUp) return;
5251 XtPopdown(promotionShell);
5252 XtDestroyWidget(promotionShell);
5253 promotionUp = False;
5256 void PromotionCallback(w, client_data, call_data)
5258 XtPointer client_data, call_data;
5264 XtSetArg(args[0], XtNlabel, &name);
5265 XtGetValues(w, args, 1);
5269 if (fromX == -1) return;
5271 if (strcmp(name, _("cancel")) == 0) {
5275 } else if (strcmp(name, _("Knight")) == 0) {
5277 } else if (strcmp(name, _("Promote")) == 0) {
5279 } else if (strcmp(name, _("Defer")) == 0) {
5282 promoChar = ToLower(name[0]);
5285 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5287 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5288 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5293 void ErrorCallback(w, client_data, call_data)
5295 XtPointer client_data, call_data;
5298 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5300 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5306 if (!errorUp) return;
5308 XtPopdown(errorShell);
5309 XtDestroyWidget(errorShell);
5310 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5313 void ErrorPopUp(title, label, modal)
5314 char *title, *label;
5318 Widget dialog, layout;
5322 Dimension bw_width, pw_width;
5323 Dimension pw_height;
5327 XtSetArg(args[i], XtNresizable, True); i++;
5328 XtSetArg(args[i], XtNtitle, title); i++;
5330 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5331 shellWidget, args, i);
5333 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5334 layoutArgs, XtNumber(layoutArgs));
5337 XtSetArg(args[i], XtNlabel, label); i++;
5338 XtSetArg(args[i], XtNborderWidth, 0); i++;
5339 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5342 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5344 XtRealizeWidget(errorShell);
5345 CatchDeleteWindow(errorShell, "ErrorPopDown");
5348 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5349 XtGetValues(boardWidget, args, i);
5351 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5352 XtSetArg(args[i], XtNheight, &pw_height); i++;
5353 XtGetValues(errorShell, args, i);
5356 /* This code seems to tickle an X bug if it is executed too soon
5357 after xboard starts up. The coordinates get transformed as if
5358 the main window was positioned at (0, 0).
5360 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5361 0 - pw_height + squareSize / 3, &x, &y);
5363 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5364 RootWindowOfScreen(XtScreen(boardWidget)),
5365 (bw_width - pw_width) / 2,
5366 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5370 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5373 XtSetArg(args[i], XtNx, x); i++;
5374 XtSetArg(args[i], XtNy, y); i++;
5375 XtSetValues(errorShell, args, i);
5378 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5381 /* Disable all user input other than deleting the window */
5382 static int frozen = 0;
5386 /* Grab by a widget that doesn't accept input */
5387 XtAddGrab(messageWidget, TRUE, FALSE);
5391 /* Undo a FreezeUI */
5394 if (!frozen) return;
5395 XtRemoveGrab(messageWidget);
5399 char *ModeToWidgetName(mode)
5403 case BeginningOfGame:
5404 if (appData.icsActive)
5405 return "menuMode.ICS Client";
5406 else if (appData.noChessProgram ||
5407 *appData.cmailGameName != NULLCHAR)
5408 return "menuMode.Edit Game";
5410 return "menuMode.Machine Black";
5411 case MachinePlaysBlack:
5412 return "menuMode.Machine Black";
5413 case MachinePlaysWhite:
5414 return "menuMode.Machine White";
5416 return "menuMode.Analysis Mode";
5418 return "menuMode.Analyze File";
5419 case TwoMachinesPlay:
5420 return "menuMode.Two Machines";
5422 return "menuMode.Edit Game";
5423 case PlayFromGameFile:
5424 return "menuFile.Load Game";
5426 return "menuMode.Edit Position";
5428 return "menuMode.Training";
5429 case IcsPlayingWhite:
5430 case IcsPlayingBlack:
5434 return "menuMode.ICS Client";
5441 void ModeHighlight()
5444 static int oldPausing = FALSE;
5445 static GameMode oldmode = (GameMode) -1;
5448 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5450 if (pausing != oldPausing) {
5451 oldPausing = pausing;
5453 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5455 XtSetArg(args[0], XtNleftBitmap, None);
5457 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5460 if (appData.showButtonBar) {
5461 /* Always toggle, don't set. Previous code messes up when
5462 invoked while the button is pressed, as releasing it
5463 toggles the state again. */
5466 XtSetArg(args[0], XtNbackground, &oldbg);
5467 XtSetArg(args[1], XtNforeground, &oldfg);
5468 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5470 XtSetArg(args[0], XtNbackground, oldfg);
5471 XtSetArg(args[1], XtNforeground, oldbg);
5473 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5477 wname = ModeToWidgetName(oldmode);
5478 if (wname != NULL) {
5479 XtSetArg(args[0], XtNleftBitmap, None);
5480 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5482 wname = ModeToWidgetName(gameMode);
5483 if (wname != NULL) {
5484 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5485 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5489 /* Maybe all the enables should be handled here, not just this one */
5490 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5491 gameMode == Training || gameMode == PlayFromGameFile);
5496 * Button/menu procedures
5498 void ResetProc(w, event, prms, nprms)
5507 int LoadGamePopUp(f, gameNumber, title)
5512 cmailMsgLoaded = FALSE;
5513 if (gameNumber == 0) {
5514 int error = GameListBuild(f);
5516 DisplayError(_("Cannot build game list"), error);
5517 } else if (!ListEmpty(&gameList) &&
5518 ((ListGame *) gameList.tailPred)->number > 1) {
5519 GameListPopUp(f, title);
5525 return LoadGame(f, gameNumber, title, FALSE);
5528 void LoadGameProc(w, event, prms, nprms)
5534 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5537 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5540 void LoadNextGameProc(w, event, prms, nprms)
5549 void LoadPrevGameProc(w, event, prms, nprms)
5558 void ReloadGameProc(w, event, prms, nprms)
5567 void LoadNextPositionProc(w, event, prms, nprms)
5576 void LoadPrevPositionProc(w, event, prms, nprms)
5585 void ReloadPositionProc(w, event, prms, nprms)
5594 void LoadPositionProc(w, event, prms, nprms)
5600 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5603 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5606 void SaveGameProc(w, event, prms, nprms)
5612 FileNamePopUp(_("Save game file name?"),
5613 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5617 void SavePositionProc(w, event, prms, nprms)
5623 FileNamePopUp(_("Save position file name?"),
5624 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5628 void ReloadCmailMsgProc(w, event, prms, nprms)
5634 ReloadCmailMsgEvent(FALSE);
5637 void MailMoveProc(w, event, prms, nprms)
5646 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5647 char *selected_fen_position=NULL;
5650 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5651 Atom *type_return, XtPointer *value_return,
5652 unsigned long *length_return, int *format_return)
5654 char *selection_tmp;
5656 if (!selected_fen_position) return False; /* should never happen */
5657 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5658 /* note: since no XtSelectionDoneProc was registered, Xt will
5659 * automatically call XtFree on the value returned. So have to
5660 * make a copy of it allocated with XtMalloc */
5661 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5662 strcpy(selection_tmp, selected_fen_position);
5664 *value_return=selection_tmp;
5665 *length_return=strlen(selection_tmp);
5666 *type_return=*target;
5667 *format_return = 8; /* bits per byte */
5669 } else if (*target == XA_TARGETS(xDisplay)) {
5670 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5671 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5672 targets_tmp[1] = XA_STRING;
5673 *value_return = targets_tmp;
5674 *type_return = XA_ATOM;
5676 *format_return = 8 * sizeof(Atom);
5677 if (*format_return > 32) {
5678 *length_return *= *format_return / 32;
5679 *format_return = 32;
5687 /* note: when called from menu all parameters are NULL, so no clue what the
5688 * Widget which was clicked on was, or what the click event was
5690 void CopyPositionProc(w, event, prms, nprms)
5697 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5698 * have a notion of a position that is selected but not copied.
5699 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5701 if(gameMode == EditPosition) EditPositionDone(TRUE);
5702 if (selected_fen_position) free(selected_fen_position);
5703 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5704 if (!selected_fen_position) return;
5705 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5707 SendPositionSelection,
5708 NULL/* lose_ownership_proc */ ,
5709 NULL/* transfer_done_proc */);
5710 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5712 SendPositionSelection,
5713 NULL/* lose_ownership_proc */ ,
5714 NULL/* transfer_done_proc */);
5717 /* function called when the data to Paste is ready */
5719 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5720 Atom *type, XtPointer value, unsigned long *len, int *format)
5723 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5724 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5725 EditPositionPasteFEN(fenstr);
5729 /* called when Paste Position button is pressed,
5730 * all parameters will be NULL */
5731 void PastePositionProc(w, event, prms, nprms)
5737 XtGetSelectionValue(menuBarWidget,
5738 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5739 /* (XtSelectionCallbackProc) */ PastePositionCB,
5740 NULL, /* client_data passed to PastePositionCB */
5742 /* better to use the time field from the event that triggered the
5743 * call to this function, but that isn't trivial to get
5751 SendGameSelection(Widget w, Atom *selection, Atom *target,
5752 Atom *type_return, XtPointer *value_return,
5753 unsigned long *length_return, int *format_return)
5755 char *selection_tmp;
5757 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5758 FILE* f = fopen(gameCopyFilename, "r");
5761 if (f == NULL) return False;
5765 selection_tmp = XtMalloc(len + 1);
5766 count = fread(selection_tmp, 1, len, f);
5768 XtFree(selection_tmp);
5771 selection_tmp[len] = NULLCHAR;
5772 *value_return = selection_tmp;
5773 *length_return = len;
5774 *type_return = *target;
5775 *format_return = 8; /* bits per byte */
5777 } else if (*target == XA_TARGETS(xDisplay)) {
5778 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5779 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5780 targets_tmp[1] = XA_STRING;
5781 *value_return = targets_tmp;
5782 *type_return = XA_ATOM;
5784 *format_return = 8 * sizeof(Atom);
5785 if (*format_return > 32) {
5786 *length_return *= *format_return / 32;
5787 *format_return = 32;
5795 /* note: when called from menu all parameters are NULL, so no clue what the
5796 * Widget which was clicked on was, or what the click event was
5798 void CopyGameProc(w, event, prms, nprms)
5806 ret = SaveGameToFile(gameCopyFilename, FALSE);
5810 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5811 * have a notion of a game that is selected but not copied.
5812 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5814 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5817 NULL/* lose_ownership_proc */ ,
5818 NULL/* transfer_done_proc */);
5819 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5822 NULL/* lose_ownership_proc */ ,
5823 NULL/* transfer_done_proc */);
5826 /* function called when the data to Paste is ready */
5828 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5829 Atom *type, XtPointer value, unsigned long *len, int *format)
5832 if (value == NULL || *len == 0) {
5833 return; /* nothing had been selected to copy */
5835 f = fopen(gamePasteFilename, "w");
5837 DisplayError(_("Can't open temp file"), errno);
5840 fwrite(value, 1, *len, f);
5843 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5846 /* called when Paste Game button is pressed,
5847 * all parameters will be NULL */
5848 void PasteGameProc(w, event, prms, nprms)
5854 XtGetSelectionValue(menuBarWidget,
5855 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5856 /* (XtSelectionCallbackProc) */ PasteGameCB,
5857 NULL, /* client_data passed to PasteGameCB */
5859 /* better to use the time field from the event that triggered the
5860 * call to this function, but that isn't trivial to get
5870 SaveGameProc(NULL, NULL, NULL, NULL);
5874 void QuitProc(w, event, prms, nprms)
5883 void PauseProc(w, event, prms, nprms)
5893 void MachineBlackProc(w, event, prms, nprms)
5899 MachineBlackEvent();
5902 void MachineWhiteProc(w, event, prms, nprms)
5908 MachineWhiteEvent();
5911 void AnalyzeModeProc(w, event, prms, nprms)
5919 if (!first.analysisSupport) {
5920 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5921 DisplayError(buf, 0);
5924 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5925 if (appData.icsActive) {
5926 if (gameMode != IcsObserving) {
5927 sprintf(buf,_("You are not observing a game"));
5928 DisplayError(buf, 0);
5930 if (appData.icsEngineAnalyze) {
5931 if (appData.debugMode)
5932 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5938 /* if enable, use want disable icsEngineAnalyze */
5939 if (appData.icsEngineAnalyze) {
5944 appData.icsEngineAnalyze = TRUE;
5945 if (appData.debugMode)
5946 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5948 if (!appData.showThinking)
5949 ShowThinkingProc(w,event,prms,nprms);
5954 void AnalyzeFileProc(w, event, prms, nprms)
5960 if (!first.analysisSupport) {
5962 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5963 DisplayError(buf, 0);
5968 if (!appData.showThinking)
5969 ShowThinkingProc(w,event,prms,nprms);
5972 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5973 AnalysisPeriodicEvent(1);
5976 void TwoMachinesProc(w, event, prms, nprms)
5985 void IcsClientProc(w, event, prms, nprms)
5994 void EditGameProc(w, event, prms, nprms)
6003 void EditPositionProc(w, event, prms, nprms)
6009 EditPositionEvent();
6012 void TrainingProc(w, event, prms, nprms)
6021 void EditCommentProc(w, event, prms, nprms)
6028 EditCommentPopDown();
6034 void IcsInputBoxProc(w, event, prms, nprms)
6040 if (ICSInputBoxUp) {
6041 ICSInputBoxPopDown();
6047 void AcceptProc(w, event, prms, nprms)
6056 void DeclineProc(w, event, prms, nprms)
6065 void RematchProc(w, event, prms, nprms)
6074 void CallFlagProc(w, event, prms, nprms)
6083 void DrawProc(w, event, prms, nprms)
6092 void AbortProc(w, event, prms, nprms)
6101 void AdjournProc(w, event, prms, nprms)
6110 void ResignProc(w, event, prms, nprms)
6119 void AdjuWhiteProc(w, event, prms, nprms)
6125 UserAdjudicationEvent(+1);
6128 void AdjuBlackProc(w, event, prms, nprms)
6134 UserAdjudicationEvent(-1);
6137 void AdjuDrawProc(w, event, prms, nprms)
6143 UserAdjudicationEvent(0);
6146 void EnterKeyProc(w, event, prms, nprms)
6152 if (ICSInputBoxUp == True)
6156 void UpKeyProc(w, event, prms, nprms)
6161 { // [HGM] input: let up-arrow recall previous line from history
6168 if (!ICSInputBoxUp) return;
6169 edit = XtNameToWidget(ICSInputShell, "*form.text");
6171 XtSetArg(args[j], XtNstring, &val); j++;
6172 XtGetValues(edit, args, j);
6173 val = PrevInHistory(val);
6174 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6175 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6177 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6178 XawTextReplace(edit, 0, 0, &t);
6179 XawTextSetInsertionPoint(edit, 9999);
6183 void DownKeyProc(w, event, prms, nprms)
6188 { // [HGM] input: let down-arrow recall next line from history
6193 if (!ICSInputBoxUp) return;
6194 edit = XtNameToWidget(ICSInputShell, "*form.text");
6195 val = NextInHistory();
6196 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6197 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6199 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6200 XawTextReplace(edit, 0, 0, &t);
6201 XawTextSetInsertionPoint(edit, 9999);
6205 void StopObservingProc(w, event, prms, nprms)
6211 StopObservingEvent();
6214 void StopExaminingProc(w, event, prms, nprms)
6220 StopExaminingEvent();
6223 void UploadProc(w, event, prms, nprms)
6233 void ForwardProc(w, event, prms, nprms)
6243 void BackwardProc(w, event, prms, nprms)
6252 void ToStartProc(w, event, prms, nprms)
6261 void ToEndProc(w, event, prms, nprms)
6270 void RevertProc(w, event, prms, nprms)
6279 void AnnotateProc(w, event, prms, nprms)
6288 void TruncateGameProc(w, event, prms, nprms)
6294 TruncateGameEvent();
6296 void RetractMoveProc(w, event, prms, nprms)
6305 void MoveNowProc(w, event, prms, nprms)
6315 void AlwaysQueenProc(w, event, prms, nprms)
6323 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6325 if (appData.alwaysPromoteToQueen) {
6326 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6328 XtSetArg(args[0], XtNleftBitmap, None);
6330 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6334 void AnimateDraggingProc(w, event, prms, nprms)
6342 appData.animateDragging = !appData.animateDragging;
6344 if (appData.animateDragging) {
6345 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6348 XtSetArg(args[0], XtNleftBitmap, None);
6350 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6354 void AnimateMovingProc(w, event, prms, nprms)
6362 appData.animate = !appData.animate;
6364 if (appData.animate) {
6365 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6368 XtSetArg(args[0], XtNleftBitmap, None);
6370 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6374 void AutocommProc(w, event, prms, nprms)
6382 appData.autoComment = !appData.autoComment;
6384 if (appData.autoComment) {
6385 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6387 XtSetArg(args[0], XtNleftBitmap, None);
6389 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6394 void AutoflagProc(w, event, prms, nprms)
6402 appData.autoCallFlag = !appData.autoCallFlag;
6404 if (appData.autoCallFlag) {
6405 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6407 XtSetArg(args[0], XtNleftBitmap, None);
6409 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6413 void AutoflipProc(w, event, prms, nprms)
6421 appData.autoFlipView = !appData.autoFlipView;
6423 if (appData.autoFlipView) {
6424 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6426 XtSetArg(args[0], XtNleftBitmap, None);
6428 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6432 void AutobsProc(w, event, prms, nprms)
6440 appData.autoObserve = !appData.autoObserve;
6442 if (appData.autoObserve) {
6443 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6445 XtSetArg(args[0], XtNleftBitmap, None);
6447 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6451 void AutoraiseProc(w, event, prms, nprms)
6459 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6461 if (appData.autoRaiseBoard) {
6462 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6464 XtSetArg(args[0], XtNleftBitmap, None);
6466 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6470 void AutosaveProc(w, event, prms, nprms)
6478 appData.autoSaveGames = !appData.autoSaveGames;
6480 if (appData.autoSaveGames) {
6481 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6483 XtSetArg(args[0], XtNleftBitmap, None);
6485 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6489 void BlindfoldProc(w, event, prms, nprms)
6497 appData.blindfold = !appData.blindfold;
6499 if (appData.blindfold) {
6500 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6502 XtSetArg(args[0], XtNleftBitmap, None);
6504 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6507 DrawPosition(True, NULL);
6510 void TestLegalityProc(w, event, prms, nprms)
6518 appData.testLegality = !appData.testLegality;
6520 if (appData.testLegality) {
6521 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6523 XtSetArg(args[0], XtNleftBitmap, None);
6525 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6530 void FlashMovesProc(w, event, prms, nprms)
6538 if (appData.flashCount == 0) {
6539 appData.flashCount = 3;
6541 appData.flashCount = -appData.flashCount;
6544 if (appData.flashCount > 0) {
6545 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6547 XtSetArg(args[0], XtNleftBitmap, None);
6549 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6553 void FlipViewProc(w, event, prms, nprms)
6559 flipView = !flipView;
6560 DrawPosition(True, NULL);
6563 void GetMoveListProc(w, event, prms, nprms)
6571 appData.getMoveList = !appData.getMoveList;
6573 if (appData.getMoveList) {
6574 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6577 XtSetArg(args[0], XtNleftBitmap, None);
6579 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6584 void HighlightDraggingProc(w, event, prms, nprms)
6592 appData.highlightDragging = !appData.highlightDragging;
6594 if (appData.highlightDragging) {
6595 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6597 XtSetArg(args[0], XtNleftBitmap, None);
6599 XtSetValues(XtNameToWidget(menuBarWidget,
6600 "menuOptions.Highlight Dragging"), args, 1);
6604 void HighlightLastMoveProc(w, event, prms, nprms)
6612 appData.highlightLastMove = !appData.highlightLastMove;
6614 if (appData.highlightLastMove) {
6615 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6617 XtSetArg(args[0], XtNleftBitmap, None);
6619 XtSetValues(XtNameToWidget(menuBarWidget,
6620 "menuOptions.Highlight Last Move"), args, 1);
6623 void IcsAlarmProc(w, event, prms, nprms)
6631 appData.icsAlarm = !appData.icsAlarm;
6633 if (appData.icsAlarm) {
6634 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6636 XtSetArg(args[0], XtNleftBitmap, None);
6638 XtSetValues(XtNameToWidget(menuBarWidget,
6639 "menuOptions.ICS Alarm"), args, 1);
6642 void MoveSoundProc(w, event, prms, nprms)
6650 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6652 if (appData.ringBellAfterMoves) {
6653 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6655 XtSetArg(args[0], XtNleftBitmap, None);
6657 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6662 void OldSaveStyleProc(w, event, prms, nprms)
6670 appData.oldSaveStyle = !appData.oldSaveStyle;
6672 if (appData.oldSaveStyle) {
6673 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6675 XtSetArg(args[0], XtNleftBitmap, None);
6677 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6681 void PeriodicUpdatesProc(w, event, prms, nprms)
6689 PeriodicUpdatesEvent(!appData.periodicUpdates);
6691 if (appData.periodicUpdates) {
6692 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6694 XtSetArg(args[0], XtNleftBitmap, None);
6696 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6700 void PonderNextMoveProc(w, event, prms, nprms)
6708 PonderNextMoveEvent(!appData.ponderNextMove);
6710 if (appData.ponderNextMove) {
6711 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6713 XtSetArg(args[0], XtNleftBitmap, None);
6715 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6719 void PopupExitMessageProc(w, event, prms, nprms)
6727 appData.popupExitMessage = !appData.popupExitMessage;
6729 if (appData.popupExitMessage) {
6730 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6732 XtSetArg(args[0], XtNleftBitmap, None);
6734 XtSetValues(XtNameToWidget(menuBarWidget,
6735 "menuOptions.Popup Exit Message"), args, 1);
6738 void PopupMoveErrorsProc(w, event, prms, nprms)
6746 appData.popupMoveErrors = !appData.popupMoveErrors;
6748 if (appData.popupMoveErrors) {
6749 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6751 XtSetArg(args[0], XtNleftBitmap, None);
6753 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6757 void PremoveProc(w, event, prms, nprms)
6765 appData.premove = !appData.premove;
6767 if (appData.premove) {
6768 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6770 XtSetArg(args[0], XtNleftBitmap, None);
6772 XtSetValues(XtNameToWidget(menuBarWidget,
6773 "menuOptions.Premove"), args, 1);
6776 void QuietPlayProc(w, event, prms, nprms)
6784 appData.quietPlay = !appData.quietPlay;
6786 if (appData.quietPlay) {
6787 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6789 XtSetArg(args[0], XtNleftBitmap, None);
6791 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6795 void ShowCoordsProc(w, event, prms, nprms)
6803 appData.showCoords = !appData.showCoords;
6805 if (appData.showCoords) {
6806 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6808 XtSetArg(args[0], XtNleftBitmap, None);
6810 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6813 DrawPosition(True, NULL);
6816 void ShowThinkingProc(w, event, prms, nprms)
6822 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6823 ShowThinkingEvent();
6826 void HideThinkingProc(w, event, prms, nprms)
6834 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6835 ShowThinkingEvent();
6837 if (appData.hideThinkingFromHuman) {
6838 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6840 XtSetArg(args[0], XtNleftBitmap, None);
6842 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6846 void SaveOnExitProc(w, event, prms, nprms)
6854 saveSettingsOnExit = !saveSettingsOnExit;
6856 if (saveSettingsOnExit) {
6857 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6859 XtSetArg(args[0], XtNleftBitmap, None);
6861 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6865 void SaveSettingsProc(w, event, prms, nprms)
6871 SaveSettings(settingsFileName);
6874 void InfoProc(w, event, prms, nprms)
6881 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6886 void ManProc(w, event, prms, nprms)
6894 if (nprms && *nprms > 0)
6898 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6902 void HintProc(w, event, prms, nprms)
6911 void BookProc(w, event, prms, nprms)
6920 void AboutProc(w, event, prms, nprms)
6928 char *zippy = " (with Zippy code)";
6932 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6933 programVersion, zippy,
6934 "Copyright 1991 Digital Equipment Corporation",
6935 "Enhancements Copyright 1992-2009 Free Software Foundation",
6936 "Enhancements Copyright 2005 Alessandro Scotti",
6937 PACKAGE, " is free software and carries NO WARRANTY;",
6938 "see the file COPYING for more information.");
6939 ErrorPopUp(_("About XBoard"), buf, FALSE);
6942 void DebugProc(w, event, prms, nprms)
6948 appData.debugMode = !appData.debugMode;
6951 void AboutGameProc(w, event, prms, nprms)
6960 void NothingProc(w, event, prms, nprms)
6969 void Iconify(w, event, prms, nprms)
6978 XtSetArg(args[0], XtNiconic, True);
6979 XtSetValues(shellWidget, args, 1);
6982 void DisplayMessage(message, extMessage)
6983 char *message, *extMessage;
6985 /* display a message in the message widget */
6994 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6999 message = extMessage;
7003 /* need to test if messageWidget already exists, since this function
7004 can also be called during the startup, if for example a Xresource
7005 is not set up correctly */
7008 XtSetArg(arg, XtNlabel, message);
7009 XtSetValues(messageWidget, &arg, 1);
7015 void DisplayTitle(text)
7020 char title[MSG_SIZ];
7023 if (text == NULL) text = "";
7025 if (appData.titleInWindow) {
7027 XtSetArg(args[i], XtNlabel, text); i++;
7028 XtSetValues(titleWidget, args, i);
7031 if (*text != NULLCHAR) {
7033 strcpy(title, text);
7034 } else if (appData.icsActive) {
7035 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7036 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7037 } else if (appData.cmailGameName[0] != NULLCHAR) {
7038 snprintf(icon, sizeof(icon), "%s", "CMail");
7039 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7041 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7042 } else if (gameInfo.variant == VariantGothic) {
7043 strcpy(icon, programName);
7044 strcpy(title, GOTHIC);
7047 } else if (gameInfo.variant == VariantFalcon) {
7048 strcpy(icon, programName);
7049 strcpy(title, FALCON);
7051 } else if (appData.noChessProgram) {
7052 strcpy(icon, programName);
7053 strcpy(title, programName);
7055 strcpy(icon, first.tidy);
7056 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7059 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7060 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7061 XtSetValues(shellWidget, args, i);
7065 void DisplayError(message, error)
7072 if (appData.debugMode || appData.matchMode) {
7073 fprintf(stderr, "%s: %s\n", programName, message);
7076 if (appData.debugMode || appData.matchMode) {
7077 fprintf(stderr, "%s: %s: %s\n",
7078 programName, message, strerror(error));
7080 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7083 ErrorPopUp(_("Error"), message, FALSE);
7087 void DisplayMoveError(message)
7092 DrawPosition(FALSE, NULL);
7093 if (appData.debugMode || appData.matchMode) {
7094 fprintf(stderr, "%s: %s\n", programName, message);
7096 if (appData.popupMoveErrors) {
7097 ErrorPopUp(_("Error"), message, FALSE);
7099 DisplayMessage(message, "");
7104 void DisplayFatalError(message, error, status)
7110 errorExitStatus = status;
7112 fprintf(stderr, "%s: %s\n", programName, message);
7114 fprintf(stderr, "%s: %s: %s\n",
7115 programName, message, strerror(error));
7116 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7119 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7120 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7126 void DisplayInformation(message)
7130 ErrorPopUp(_("Information"), message, TRUE);
7133 void DisplayNote(message)
7137 ErrorPopUp(_("Note"), message, FALSE);
7141 NullXErrorCheck(dpy, error_event)
7143 XErrorEvent *error_event;
7148 void DisplayIcsInteractionTitle(message)
7151 if (oldICSInteractionTitle == NULL) {
7152 /* Magic to find the old window title, adapted from vim */
7153 char *wina = getenv("WINDOWID");
7155 Window win = (Window) atoi(wina);
7156 Window root, parent, *children;
7157 unsigned int nchildren;
7158 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7160 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7161 if (!XQueryTree(xDisplay, win, &root, &parent,
7162 &children, &nchildren)) break;
7163 if (children) XFree((void *)children);
7164 if (parent == root || parent == 0) break;
7167 XSetErrorHandler(oldHandler);
7169 if (oldICSInteractionTitle == NULL) {
7170 oldICSInteractionTitle = "xterm";
7173 printf("\033]0;%s\007", message);
7177 char pendingReplyPrefix[MSG_SIZ];
7178 ProcRef pendingReplyPR;
7180 void AskQuestionProc(w, event, prms, nprms)
7187 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7191 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7194 void AskQuestionPopDown()
7196 if (!askQuestionUp) return;
7197 XtPopdown(askQuestionShell);
7198 XtDestroyWidget(askQuestionShell);
7199 askQuestionUp = False;
7202 void AskQuestionReplyAction(w, event, prms, nprms)
7212 reply = XawDialogGetValueString(w = XtParent(w));
7213 strcpy(buf, pendingReplyPrefix);
7214 if (*buf) strcat(buf, " ");
7217 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7218 AskQuestionPopDown();
7220 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7223 void AskQuestionCallback(w, client_data, call_data)
7225 XtPointer client_data, call_data;
7230 XtSetArg(args[0], XtNlabel, &name);
7231 XtGetValues(w, args, 1);
7233 if (strcmp(name, _("cancel")) == 0) {
7234 AskQuestionPopDown();
7236 AskQuestionReplyAction(w, NULL, NULL, NULL);
7240 void AskQuestion(title, question, replyPrefix, pr)
7241 char *title, *question, *replyPrefix;
7245 Widget popup, layout, dialog, edit;
7251 strcpy(pendingReplyPrefix, replyPrefix);
7252 pendingReplyPR = pr;
7255 XtSetArg(args[i], XtNresizable, True); i++;
7256 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7257 askQuestionShell = popup =
7258 XtCreatePopupShell(title, transientShellWidgetClass,
7259 shellWidget, args, i);
7262 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7263 layoutArgs, XtNumber(layoutArgs));
7266 XtSetArg(args[i], XtNlabel, question); i++;
7267 XtSetArg(args[i], XtNvalue, ""); i++;
7268 XtSetArg(args[i], XtNborderWidth, 0); i++;
7269 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7272 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7273 (XtPointer) dialog);
7274 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7275 (XtPointer) dialog);
7277 XtRealizeWidget(popup);
7278 CatchDeleteWindow(popup, "AskQuestionPopDown");
7280 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7281 &x, &y, &win_x, &win_y, &mask);
7283 XtSetArg(args[0], XtNx, x - 10);
7284 XtSetArg(args[1], XtNy, y - 30);
7285 XtSetValues(popup, args, 2);
7287 XtPopup(popup, XtGrabExclusive);
7288 askQuestionUp = True;
7290 edit = XtNameToWidget(dialog, "*value");
7291 XtSetKeyboardFocus(popup, edit);
7299 if (*name == NULLCHAR) {
7301 } else if (strcmp(name, "$") == 0) {
7302 putc(BELLCHAR, stderr);
7305 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7313 PlaySound(appData.soundMove);
7319 PlaySound(appData.soundIcsWin);
7325 PlaySound(appData.soundIcsLoss);
7331 PlaySound(appData.soundIcsDraw);
7335 PlayIcsUnfinishedSound()
7337 PlaySound(appData.soundIcsUnfinished);
7343 PlaySound(appData.soundIcsAlarm);
7349 system("stty echo");
7355 system("stty -echo");
7359 Colorize(cc, continuation)
7364 int count, outCount, error;
7366 if (textColors[(int)cc].bg > 0) {
7367 if (textColors[(int)cc].fg > 0) {
7368 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7369 textColors[(int)cc].fg, textColors[(int)cc].bg);
7371 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7372 textColors[(int)cc].bg);
7375 if (textColors[(int)cc].fg > 0) {
7376 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7377 textColors[(int)cc].fg);
7379 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7382 count = strlen(buf);
7383 outCount = OutputToProcess(NoProc, buf, count, &error);
7384 if (outCount < count) {
7385 DisplayFatalError(_("Error writing to display"), error, 1);
7388 if (continuation) return;
7391 PlaySound(appData.soundShout);
7394 PlaySound(appData.soundSShout);
7397 PlaySound(appData.soundChannel1);
7400 PlaySound(appData.soundChannel);
7403 PlaySound(appData.soundKibitz);
7406 PlaySound(appData.soundTell);
7408 case ColorChallenge:
7409 PlaySound(appData.soundChallenge);
7412 PlaySound(appData.soundRequest);
7415 PlaySound(appData.soundSeek);
7426 return getpwuid(getuid())->pw_name;
7429 static char *ExpandPathName(path)
7432 static char static_buf[2000];
7433 char *d, *s, buf[2000];
7439 while (*s && isspace(*s))
7448 if (*(s+1) == '/') {
7449 strcpy(d, getpwuid(getuid())->pw_dir);
7454 *strchr(buf, '/') = 0;
7455 pwd = getpwnam(buf);
7458 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7462 strcpy(d, pwd->pw_dir);
7463 strcat(d, strchr(s+1, '/'));
7474 static char host_name[MSG_SIZ];
7476 #if HAVE_GETHOSTNAME
7477 gethostname(host_name, MSG_SIZ);
7479 #else /* not HAVE_GETHOSTNAME */
7480 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7481 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7483 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7485 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7486 #endif /* not HAVE_GETHOSTNAME */
7489 XtIntervalId delayedEventTimerXID = 0;
7490 DelayedEventCallback delayedEventCallback = 0;
7495 delayedEventTimerXID = 0;
7496 delayedEventCallback();
7500 ScheduleDelayedEvent(cb, millisec)
7501 DelayedEventCallback cb; long millisec;
7503 if(delayedEventTimerXID && delayedEventCallback == cb)
7504 // [HGM] alive: replace, rather than add or flush identical event
7505 XtRemoveTimeOut(delayedEventTimerXID);
7506 delayedEventCallback = cb;
7507 delayedEventTimerXID =
7508 XtAppAddTimeOut(appContext, millisec,
7509 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7512 DelayedEventCallback
7515 if (delayedEventTimerXID) {
7516 return delayedEventCallback;
7523 CancelDelayedEvent()
7525 if (delayedEventTimerXID) {
7526 XtRemoveTimeOut(delayedEventTimerXID);
7527 delayedEventTimerXID = 0;
7531 XtIntervalId loadGameTimerXID = 0;
7533 int LoadGameTimerRunning()
7535 return loadGameTimerXID != 0;
7538 int StopLoadGameTimer()
7540 if (loadGameTimerXID != 0) {
7541 XtRemoveTimeOut(loadGameTimerXID);
7542 loadGameTimerXID = 0;
7550 LoadGameTimerCallback(arg, id)
7554 loadGameTimerXID = 0;
7559 StartLoadGameTimer(millisec)
7563 XtAppAddTimeOut(appContext, millisec,
7564 (XtTimerCallbackProc) LoadGameTimerCallback,
7568 XtIntervalId analysisClockXID = 0;
7571 AnalysisClockCallback(arg, id)
7575 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7576 || appData.icsEngineAnalyze) { // [DM]
7577 AnalysisPeriodicEvent(0);
7578 StartAnalysisClock();
7583 StartAnalysisClock()
7586 XtAppAddTimeOut(appContext, 2000,
7587 (XtTimerCallbackProc) AnalysisClockCallback,
7591 XtIntervalId clockTimerXID = 0;
7593 int ClockTimerRunning()
7595 return clockTimerXID != 0;
7598 int StopClockTimer()
7600 if (clockTimerXID != 0) {
7601 XtRemoveTimeOut(clockTimerXID);
7610 ClockTimerCallback(arg, id)
7619 StartClockTimer(millisec)
7623 XtAppAddTimeOut(appContext, millisec,
7624 (XtTimerCallbackProc) ClockTimerCallback,
7629 DisplayTimerLabel(w, color, timer, highlight)
7638 /* check for low time warning */
7639 Pixel foregroundOrWarningColor = timerForegroundPixel;
7642 appData.lowTimeWarning &&
7643 (timer / 1000) < appData.icsAlarmTime)
7644 foregroundOrWarningColor = lowTimeWarningColor;
7646 if (appData.clockMode) {
7647 sprintf(buf, "%s: %s", color, TimeString(timer));
7648 XtSetArg(args[0], XtNlabel, buf);
7650 sprintf(buf, "%s ", color);
7651 XtSetArg(args[0], XtNlabel, buf);
7656 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7657 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7659 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7660 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7663 XtSetValues(w, args, 3);
7667 DisplayWhiteClock(timeRemaining, highlight)
7673 if(appData.noGUI) return;
7674 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7675 if (highlight && iconPixmap == bIconPixmap) {
7676 iconPixmap = wIconPixmap;
7677 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7678 XtSetValues(shellWidget, args, 1);
7683 DisplayBlackClock(timeRemaining, highlight)
7689 if(appData.noGUI) return;
7690 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7691 if (highlight && iconPixmap == wIconPixmap) {
7692 iconPixmap = bIconPixmap;
7693 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7694 XtSetValues(shellWidget, args, 1);
7712 int StartChildProcess(cmdLine, dir, pr)
7719 int to_prog[2], from_prog[2];
7723 if (appData.debugMode) {
7724 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7727 /* We do NOT feed the cmdLine to the shell; we just
7728 parse it into blank-separated arguments in the
7729 most simple-minded way possible.
7732 strcpy(buf, cmdLine);
7735 while(*p == ' ') p++;
7737 if(*p == '"' || *p == '\'')
7738 p = strchr(++argv[i-1], *p);
7739 else p = strchr(p, ' ');
7740 if (p == NULL) break;
7745 SetUpChildIO(to_prog, from_prog);
7747 if ((pid = fork()) == 0) {
7749 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7750 close(to_prog[1]); // first close the unused pipe ends
7751 close(from_prog[0]);
7752 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7753 dup2(from_prog[1], 1);
7754 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7755 close(from_prog[1]); // and closing again loses one of the pipes!
7756 if(fileno(stderr) >= 2) // better safe than sorry...
7757 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7759 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7764 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7766 execvp(argv[0], argv);
7768 /* If we get here, exec failed */
7773 /* Parent process */
7775 close(from_prog[1]);
7777 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7780 cp->fdFrom = from_prog[0];
7781 cp->fdTo = to_prog[1];
7786 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7787 static RETSIGTYPE AlarmCallBack(int n)
7793 DestroyChildProcess(pr, signalType)
7797 ChildProc *cp = (ChildProc *) pr;
7799 if (cp->kind != CPReal) return;
7801 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7802 signal(SIGALRM, AlarmCallBack);
7804 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7805 kill(cp->pid, SIGKILL); // kill it forcefully
7806 wait((int *) 0); // and wait again
7810 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7812 /* Process is exiting either because of the kill or because of
7813 a quit command sent by the backend; either way, wait for it to die.
7822 InterruptChildProcess(pr)
7825 ChildProc *cp = (ChildProc *) pr;
7827 if (cp->kind != CPReal) return;
7828 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7831 int OpenTelnet(host, port, pr)
7836 char cmdLine[MSG_SIZ];
7838 if (port[0] == NULLCHAR) {
7839 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7841 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7843 return StartChildProcess(cmdLine, "", pr);
7846 int OpenTCP(host, port, pr)
7852 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7853 #else /* !OMIT_SOCKETS */
7855 struct sockaddr_in sa;
7857 unsigned short uport;
7860 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7864 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7865 sa.sin_family = AF_INET;
7866 sa.sin_addr.s_addr = INADDR_ANY;
7867 uport = (unsigned short) 0;
7868 sa.sin_port = htons(uport);
7869 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7873 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7874 if (!(hp = gethostbyname(host))) {
7876 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7877 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7878 hp->h_addrtype = AF_INET;
7880 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7881 hp->h_addr_list[0] = (char *) malloc(4);
7882 hp->h_addr_list[0][0] = b0;
7883 hp->h_addr_list[0][1] = b1;
7884 hp->h_addr_list[0][2] = b2;
7885 hp->h_addr_list[0][3] = b3;
7890 sa.sin_family = hp->h_addrtype;
7891 uport = (unsigned short) atoi(port);
7892 sa.sin_port = htons(uport);
7893 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7895 if (connect(s, (struct sockaddr *) &sa,
7896 sizeof(struct sockaddr_in)) < 0) {
7900 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7907 #endif /* !OMIT_SOCKETS */
7912 int OpenCommPort(name, pr)
7919 fd = open(name, 2, 0);
7920 if (fd < 0) return errno;
7922 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7932 int OpenLoopback(pr)
7938 SetUpChildIO(to, from);
7940 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7943 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7950 int OpenRcmd(host, user, cmd, pr)
7951 char *host, *user, *cmd;
7954 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7958 #define INPUT_SOURCE_BUF_SIZE 8192
7967 char buf[INPUT_SOURCE_BUF_SIZE];
7972 DoInputCallback(closure, source, xid)
7977 InputSource *is = (InputSource *) closure;
7982 if (is->lineByLine) {
7983 count = read(is->fd, is->unused,
7984 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7986 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7989 is->unused += count;
7991 while (p < is->unused) {
7992 q = memchr(p, '\n', is->unused - p);
7993 if (q == NULL) break;
7995 (is->func)(is, is->closure, p, q - p, 0);
7999 while (p < is->unused) {
8004 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8009 (is->func)(is, is->closure, is->buf, count, error);
8013 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8020 ChildProc *cp = (ChildProc *) pr;
8022 is = (InputSource *) calloc(1, sizeof(InputSource));
8023 is->lineByLine = lineByLine;
8027 is->fd = fileno(stdin);
8029 is->kind = cp->kind;
8030 is->fd = cp->fdFrom;
8033 is->unused = is->buf;
8036 is->xid = XtAppAddInput(appContext, is->fd,
8037 (XtPointer) (XtInputReadMask),
8038 (XtInputCallbackProc) DoInputCallback,
8040 is->closure = closure;
8041 return (InputSourceRef) is;
8045 RemoveInputSource(isr)
8048 InputSource *is = (InputSource *) isr;
8050 if (is->xid == 0) return;
8051 XtRemoveInput(is->xid);
8055 int OutputToProcess(pr, message, count, outError)
8061 static int line = 0;
8062 ChildProc *cp = (ChildProc *) pr;
8067 if (appData.noJoin || !appData.useInternalWrap)
8068 outCount = fwrite(message, 1, count, stdout);
8071 int width = get_term_width();
8072 int len = wrap(NULL, message, count, width, &line);
8073 char *msg = malloc(len);
8077 outCount = fwrite(message, 1, count, stdout);
8080 dbgchk = wrap(msg, message, count, width, &line);
8081 if (dbgchk != len && appData.debugMode)
8082 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8083 outCount = fwrite(msg, 1, dbgchk, stdout);
8089 outCount = write(cp->fdTo, message, count);
8099 /* Output message to process, with "ms" milliseconds of delay
8100 between each character. This is needed when sending the logon
8101 script to ICC, which for some reason doesn't like the
8102 instantaneous send. */
8103 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8110 ChildProc *cp = (ChildProc *) pr;
8115 r = write(cp->fdTo, message++, 1);
8128 /**** Animation code by Hugh Fisher, DCS, ANU.
8130 Known problem: if a window overlapping the board is
8131 moved away while a piece is being animated underneath,
8132 the newly exposed area won't be updated properly.
8133 I can live with this.
8135 Known problem: if you look carefully at the animation
8136 of pieces in mono mode, they are being drawn as solid
8137 shapes without interior detail while moving. Fixing
8138 this would be a major complication for minimal return.
8141 /* Masks for XPM pieces. Black and white pieces can have
8142 different shapes, but in the interest of retaining my
8143 sanity pieces must have the same outline on both light
8144 and dark squares, and all pieces must use the same
8145 background square colors/images. */
8147 static int xpmDone = 0;
8150 CreateAnimMasks (pieceDepth)
8157 unsigned long plane;
8160 /* Need a bitmap just to get a GC with right depth */
8161 buf = XCreatePixmap(xDisplay, xBoardWindow,
8163 values.foreground = 1;
8164 values.background = 0;
8165 /* Don't use XtGetGC, not read only */
8166 maskGC = XCreateGC(xDisplay, buf,
8167 GCForeground | GCBackground, &values);
8168 XFreePixmap(xDisplay, buf);
8170 buf = XCreatePixmap(xDisplay, xBoardWindow,
8171 squareSize, squareSize, pieceDepth);
8172 values.foreground = XBlackPixel(xDisplay, xScreen);
8173 values.background = XWhitePixel(xDisplay, xScreen);
8174 bufGC = XCreateGC(xDisplay, buf,
8175 GCForeground | GCBackground, &values);
8177 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8178 /* Begin with empty mask */
8179 if(!xpmDone) // [HGM] pieces: keep using existing
8180 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8181 squareSize, squareSize, 1);
8182 XSetFunction(xDisplay, maskGC, GXclear);
8183 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8184 0, 0, squareSize, squareSize);
8186 /* Take a copy of the piece */
8191 XSetFunction(xDisplay, bufGC, GXcopy);
8192 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8194 0, 0, squareSize, squareSize, 0, 0);
8196 /* XOR the background (light) over the piece */
8197 XSetFunction(xDisplay, bufGC, GXxor);
8199 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8200 0, 0, squareSize, squareSize, 0, 0);
8202 XSetForeground(xDisplay, bufGC, lightSquareColor);
8203 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8206 /* We now have an inverted piece image with the background
8207 erased. Construct mask by just selecting all the non-zero
8208 pixels - no need to reconstruct the original image. */
8209 XSetFunction(xDisplay, maskGC, GXor);
8211 /* Might be quicker to download an XImage and create bitmap
8212 data from it rather than this N copies per piece, but it
8213 only takes a fraction of a second and there is a much
8214 longer delay for loading the pieces. */
8215 for (n = 0; n < pieceDepth; n ++) {
8216 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8217 0, 0, squareSize, squareSize,
8223 XFreePixmap(xDisplay, buf);
8224 XFreeGC(xDisplay, bufGC);
8225 XFreeGC(xDisplay, maskGC);
8229 InitAnimState (anim, info)
8231 XWindowAttributes * info;
8236 /* Each buffer is square size, same depth as window */
8237 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8238 squareSize, squareSize, info->depth);
8239 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8240 squareSize, squareSize, info->depth);
8242 /* Create a plain GC for blitting */
8243 mask = GCForeground | GCBackground | GCFunction |
8244 GCPlaneMask | GCGraphicsExposures;
8245 values.foreground = XBlackPixel(xDisplay, xScreen);
8246 values.background = XWhitePixel(xDisplay, xScreen);
8247 values.function = GXcopy;
8248 values.plane_mask = AllPlanes;
8249 values.graphics_exposures = False;
8250 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8252 /* Piece will be copied from an existing context at
8253 the start of each new animation/drag. */
8254 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8256 /* Outline will be a read-only copy of an existing */
8257 anim->outlineGC = None;
8263 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8264 XWindowAttributes info;
8266 if (xpmDone && gameInfo.variant == old) return;
8267 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8268 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8270 InitAnimState(&game, &info);
8271 InitAnimState(&player, &info);
8273 /* For XPM pieces, we need bitmaps to use as masks. */
8275 CreateAnimMasks(info.depth);
8281 static Boolean frameWaiting;
8283 static RETSIGTYPE FrameAlarm (sig)
8286 frameWaiting = False;
8287 /* In case System-V style signals. Needed?? */
8288 signal(SIGALRM, FrameAlarm);
8295 struct itimerval delay;
8297 XSync(xDisplay, False);
8300 frameWaiting = True;
8301 signal(SIGALRM, FrameAlarm);
8302 delay.it_interval.tv_sec =
8303 delay.it_value.tv_sec = time / 1000;
8304 delay.it_interval.tv_usec =
8305 delay.it_value.tv_usec = (time % 1000) * 1000;
8306 setitimer(ITIMER_REAL, &delay, NULL);
8307 while (frameWaiting) pause();
8308 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8309 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8310 setitimer(ITIMER_REAL, &delay, NULL);
8320 XSync(xDisplay, False);
8322 usleep(time * 1000);
8327 /* Convert board position to corner of screen rect and color */
8330 ScreenSquare(column, row, pt, color)
8331 int column; int row; XPoint * pt; int * color;
8334 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8335 pt->y = lineGap + row * (squareSize + lineGap);
8337 pt->x = lineGap + column * (squareSize + lineGap);
8338 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8340 *color = SquareColor(row, column);
8343 /* Convert window coords to square */
8346 BoardSquare(x, y, column, row)
8347 int x; int y; int * column; int * row;
8349 *column = EventToSquare(x, BOARD_WIDTH);
8350 if (flipView && *column >= 0)
8351 *column = BOARD_WIDTH - 1 - *column;
8352 *row = EventToSquare(y, BOARD_HEIGHT);
8353 if (!flipView && *row >= 0)
8354 *row = BOARD_HEIGHT - 1 - *row;
8359 #undef Max /* just in case */
8361 #define Max(a, b) ((a) > (b) ? (a) : (b))
8362 #define Min(a, b) ((a) < (b) ? (a) : (b))
8365 SetRect(rect, x, y, width, height)
8366 XRectangle * rect; int x; int y; int width; int height;
8370 rect->width = width;
8371 rect->height = height;
8374 /* Test if two frames overlap. If they do, return
8375 intersection rect within old and location of
8376 that rect within new. */
8379 Intersect(old, new, size, area, pt)
8380 XPoint * old; XPoint * new;
8381 int size; XRectangle * area; XPoint * pt;
8383 if (old->x > new->x + size || new->x > old->x + size ||
8384 old->y > new->y + size || new->y > old->y + size) {
8387 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8388 size - abs(old->x - new->x), size - abs(old->y - new->y));
8389 pt->x = Max(old->x - new->x, 0);
8390 pt->y = Max(old->y - new->y, 0);
8395 /* For two overlapping frames, return the rect(s)
8396 in the old that do not intersect with the new. */
8399 CalcUpdateRects(old, new, size, update, nUpdates)
8400 XPoint * old; XPoint * new; int size;
8401 XRectangle update[]; int * nUpdates;
8405 /* If old = new (shouldn't happen) then nothing to draw */
8406 if (old->x == new->x && old->y == new->y) {
8410 /* Work out what bits overlap. Since we know the rects
8411 are the same size we don't need a full intersect calc. */
8413 /* Top or bottom edge? */
8414 if (new->y > old->y) {
8415 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8417 } else if (old->y > new->y) {
8418 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8419 size, old->y - new->y);
8422 /* Left or right edge - don't overlap any update calculated above. */
8423 if (new->x > old->x) {
8424 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8425 new->x - old->x, size - abs(new->y - old->y));
8427 } else if (old->x > new->x) {
8428 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8429 old->x - new->x, size - abs(new->y - old->y));
8436 /* Generate a series of frame coords from start->mid->finish.
8437 The movement rate doubles until the half way point is
8438 reached, then halves back down to the final destination,
8439 which gives a nice slow in/out effect. The algorithmn
8440 may seem to generate too many intermediates for short
8441 moves, but remember that the purpose is to attract the
8442 viewers attention to the piece about to be moved and
8443 then to where it ends up. Too few frames would be less
8447 Tween(start, mid, finish, factor, frames, nFrames)
8448 XPoint * start; XPoint * mid;
8449 XPoint * finish; int factor;
8450 XPoint frames[]; int * nFrames;
8452 int fraction, n, count;
8456 /* Slow in, stepping 1/16th, then 1/8th, ... */
8458 for (n = 0; n < factor; n++)
8460 for (n = 0; n < factor; n++) {
8461 frames[count].x = start->x + (mid->x - start->x) / fraction;
8462 frames[count].y = start->y + (mid->y - start->y) / fraction;
8464 fraction = fraction / 2;
8468 frames[count] = *mid;
8471 /* Slow out, stepping 1/2, then 1/4, ... */
8473 for (n = 0; n < factor; n++) {
8474 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8475 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8477 fraction = fraction * 2;
8482 /* Draw a piece on the screen without disturbing what's there */
8485 SelectGCMask(piece, clip, outline, mask)
8486 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8490 /* Bitmap for piece being moved. */
8491 if (appData.monoMode) {
8492 *mask = *pieceToSolid(piece);
8493 } else if (useImages) {
8495 *mask = xpmMask[piece];
8497 *mask = ximMaskPm[piece];
8500 *mask = *pieceToSolid(piece);
8503 /* GC for piece being moved. Square color doesn't matter, but
8504 since it gets modified we make a copy of the original. */
8506 if (appData.monoMode)
8511 if (appData.monoMode)
8516 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8518 /* Outline only used in mono mode and is not modified */
8520 *outline = bwPieceGC;
8522 *outline = wbPieceGC;
8526 OverlayPiece(piece, clip, outline, dest)
8527 ChessSquare piece; GC clip; GC outline; Drawable dest;
8532 /* Draw solid rectangle which will be clipped to shape of piece */
8533 XFillRectangle(xDisplay, dest, clip,
8534 0, 0, squareSize, squareSize);
8535 if (appData.monoMode)
8536 /* Also draw outline in contrasting color for black
8537 on black / white on white cases */
8538 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8539 0, 0, squareSize, squareSize, 0, 0, 1);
8541 /* Copy the piece */
8546 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8548 0, 0, squareSize, squareSize,
8553 /* Animate the movement of a single piece */
8556 BeginAnimation(anim, piece, startColor, start)
8564 /* The old buffer is initialised with the start square (empty) */
8565 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8566 anim->prevFrame = *start;
8568 /* The piece will be drawn using its own bitmap as a matte */
8569 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8570 XSetClipMask(xDisplay, anim->pieceGC, mask);
8574 AnimationFrame(anim, frame, piece)
8579 XRectangle updates[4];
8584 /* Save what we are about to draw into the new buffer */
8585 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8586 frame->x, frame->y, squareSize, squareSize,
8589 /* Erase bits of the previous frame */
8590 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8591 /* Where the new frame overlapped the previous,
8592 the contents in newBuf are wrong. */
8593 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8594 overlap.x, overlap.y,
8595 overlap.width, overlap.height,
8597 /* Repaint the areas in the old that don't overlap new */
8598 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8599 for (i = 0; i < count; i++)
8600 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8601 updates[i].x - anim->prevFrame.x,
8602 updates[i].y - anim->prevFrame.y,
8603 updates[i].width, updates[i].height,
8604 updates[i].x, updates[i].y);
8606 /* Easy when no overlap */
8607 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8608 0, 0, squareSize, squareSize,
8609 anim->prevFrame.x, anim->prevFrame.y);
8612 /* Save this frame for next time round */
8613 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8614 0, 0, squareSize, squareSize,
8616 anim->prevFrame = *frame;
8618 /* Draw piece over original screen contents, not current,
8619 and copy entire rect. Wipes out overlapping piece images. */
8620 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8621 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8622 0, 0, squareSize, squareSize,
8623 frame->x, frame->y);
8627 EndAnimation (anim, finish)
8631 XRectangle updates[4];
8636 /* The main code will redraw the final square, so we
8637 only need to erase the bits that don't overlap. */
8638 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8639 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8640 for (i = 0; i < count; i++)
8641 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8642 updates[i].x - anim->prevFrame.x,
8643 updates[i].y - anim->prevFrame.y,
8644 updates[i].width, updates[i].height,
8645 updates[i].x, updates[i].y);
8647 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8648 0, 0, squareSize, squareSize,
8649 anim->prevFrame.x, anim->prevFrame.y);
8654 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8656 ChessSquare piece; int startColor;
8657 XPoint * start; XPoint * finish;
8658 XPoint frames[]; int nFrames;
8662 BeginAnimation(anim, piece, startColor, start);
8663 for (n = 0; n < nFrames; n++) {
8664 AnimationFrame(anim, &(frames[n]), piece);
8665 FrameDelay(appData.animSpeed);
8667 EndAnimation(anim, finish);
8670 /* Main control logic for deciding what to animate and how */
8673 AnimateMove(board, fromX, fromY, toX, toY)
8682 XPoint start, finish, mid;
8683 XPoint frames[kFactor * 2 + 1];
8684 int nFrames, startColor, endColor;
8686 /* Are we animating? */
8687 if (!appData.animate || appData.blindfold)
8690 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8691 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8692 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8694 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8695 piece = board[fromY][fromX];
8696 if (piece >= EmptySquare) return;
8701 hop = (piece == WhiteKnight || piece == BlackKnight);
8704 if (appData.debugMode) {
8705 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8706 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8707 piece, fromX, fromY, toX, toY); }
8709 ScreenSquare(fromX, fromY, &start, &startColor);
8710 ScreenSquare(toX, toY, &finish, &endColor);
8713 /* Knight: make diagonal movement then straight */
8714 if (abs(toY - fromY) < abs(toX - fromX)) {
8715 mid.x = start.x + (finish.x - start.x) / 2;
8719 mid.y = start.y + (finish.y - start.y) / 2;
8722 mid.x = start.x + (finish.x - start.x) / 2;
8723 mid.y = start.y + (finish.y - start.y) / 2;
8726 /* Don't use as many frames for very short moves */
8727 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8728 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8730 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8731 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8733 /* Be sure end square is redrawn */
8734 damage[toY][toX] = True;
8738 DragPieceBegin(x, y)
8741 int boardX, boardY, color;
8744 /* Are we animating? */
8745 if (!appData.animateDragging || appData.blindfold)
8748 /* Figure out which square we start in and the
8749 mouse position relative to top left corner. */
8750 BoardSquare(x, y, &boardX, &boardY);
8751 player.startBoardX = boardX;
8752 player.startBoardY = boardY;
8753 ScreenSquare(boardX, boardY, &corner, &color);
8754 player.startSquare = corner;
8755 player.startColor = color;
8756 /* As soon as we start dragging, the piece will jump slightly to
8757 be centered over the mouse pointer. */
8758 player.mouseDelta.x = squareSize/2;
8759 player.mouseDelta.y = squareSize/2;
8760 /* Initialise animation */
8761 player.dragPiece = PieceForSquare(boardX, boardY);
8763 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8764 player.dragActive = True;
8765 BeginAnimation(&player, player.dragPiece, color, &corner);
8766 /* Mark this square as needing to be redrawn. Note that
8767 we don't remove the piece though, since logically (ie
8768 as seen by opponent) the move hasn't been made yet. */
8769 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8770 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8771 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8772 corner.x, corner.y, squareSize, squareSize,
8773 0, 0); // [HGM] zh: unstack in stead of grab
8774 damage[boardY][boardX] = True;
8776 player.dragActive = False;
8786 /* Are we animating? */
8787 if (!appData.animateDragging || appData.blindfold)
8791 if (! player.dragActive)
8793 /* Move piece, maintaining same relative position
8794 of mouse within square */
8795 corner.x = x - player.mouseDelta.x;
8796 corner.y = y - player.mouseDelta.y;
8797 AnimationFrame(&player, &corner, player.dragPiece);
8799 if (appData.highlightDragging) {
8801 BoardSquare(x, y, &boardX, &boardY);
8802 SetHighlights(fromX, fromY, boardX, boardY);
8811 int boardX, boardY, color;
8814 /* Are we animating? */
8815 if (!appData.animateDragging || appData.blindfold)
8819 if (! player.dragActive)
8821 /* Last frame in sequence is square piece is
8822 placed on, which may not match mouse exactly. */
8823 BoardSquare(x, y, &boardX, &boardY);
8824 ScreenSquare(boardX, boardY, &corner, &color);
8825 EndAnimation(&player, &corner);
8827 /* Be sure end square is redrawn */
8828 damage[boardY][boardX] = True;
8830 /* This prevents weird things happening with fast successive
8831 clicks which on my Sun at least can cause motion events
8832 without corresponding press/release. */
8833 player.dragActive = False;
8836 /* Handle expose event while piece being dragged */
8841 if (!player.dragActive || appData.blindfold)
8844 /* What we're doing: logically, the move hasn't been made yet,
8845 so the piece is still in it's original square. But visually
8846 it's being dragged around the board. So we erase the square
8847 that the piece is on and draw it at the last known drag point. */
8848 BlankSquare(player.startSquare.x, player.startSquare.y,
8849 player.startColor, EmptySquare, xBoardWindow);
8850 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8851 damage[player.startBoardY][player.startBoardX] = TRUE;
8854 #include <sys/ioctl.h>
8855 int get_term_width()
8857 int fd, default_width;
8860 default_width = 79; // this is FICS default anyway...
8862 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8864 if (!ioctl(fd, TIOCGSIZE, &win))
8865 default_width = win.ts_cols;
8866 #elif defined(TIOCGWINSZ)
8868 if (!ioctl(fd, TIOCGWINSZ, &win))
8869 default_width = win.ws_col;
8871 return default_width;
8874 void update_ics_width()
8876 static int old_width = 0;
8877 int new_width = get_term_width();
8879 if (old_width != new_width)
8880 ics_printf("set width %d\n", new_width);
8881 old_width = new_width;
8884 void NotifyFrontendLogin()