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()
2535 XtSetKeyboardFocus(shellWidget, formWidget);
2537 XtAppMainLoop(appContext);
2538 if (appData.debugMode) fclose(debugFP); // [DM] debug
2545 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2546 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2548 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2549 unlink(gameCopyFilename);
2550 unlink(gamePasteFilename);
2553 RETSIGTYPE TermSizeSigHandler(int sig)
2566 CmailSigHandler(sig)
2572 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2574 /* Activate call-back function CmailSigHandlerCallBack() */
2575 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2577 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2581 CmailSigHandlerCallBack(isr, closure, message, count, error)
2589 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2591 /**** end signal code ****/
2601 f = fopen(appData.icsLogon, "r");
2607 strcat(buf, appData.icsLogon);
2608 f = fopen(buf, "r");
2612 ProcessICSInitScript(f);
2619 EditCommentPopDown();
2634 if (!menuBarWidget) return;
2635 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2637 DisplayError("menuStep.Revert", 0);
2639 XtSetSensitive(w, !grey);
2641 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2643 DisplayError("menuStep.Annotate", 0);
2645 XtSetSensitive(w, !grey);
2650 SetMenuEnables(enab)
2654 if (!menuBarWidget) return;
2655 while (enab->name != NULL) {
2656 w = XtNameToWidget(menuBarWidget, enab->name);
2658 DisplayError(enab->name, 0);
2660 XtSetSensitive(w, enab->value);
2666 Enables icsEnables[] = {
2667 { "menuFile.Mail Move", False },
2668 { "menuFile.Reload CMail Message", False },
2669 { "menuMode.Machine Black", False },
2670 { "menuMode.Machine White", False },
2671 { "menuMode.Analysis Mode", False },
2672 { "menuMode.Analyze File", False },
2673 { "menuMode.Two Machines", False },
2675 { "menuHelp.Hint", False },
2676 { "menuHelp.Book", False },
2677 { "menuStep.Move Now", False },
2678 { "menuOptions.Periodic Updates", False },
2679 { "menuOptions.Hide Thinking", False },
2680 { "menuOptions.Ponder Next Move", False },
2682 { "menuStep.Annotate", False },
2686 Enables ncpEnables[] = {
2687 { "menuFile.Mail Move", False },
2688 { "menuFile.Reload CMail Message", False },
2689 { "menuMode.Machine White", False },
2690 { "menuMode.Machine Black", False },
2691 { "menuMode.Analysis Mode", False },
2692 { "menuMode.Analyze File", False },
2693 { "menuMode.Two Machines", False },
2694 { "menuMode.ICS Client", False },
2695 { "menuMode.ICS Input Box", False },
2696 { "Action", False },
2697 { "menuStep.Revert", False },
2698 { "menuStep.Annotate", False },
2699 { "menuStep.Move Now", False },
2700 { "menuStep.Retract Move", False },
2701 { "menuOptions.Auto Comment", False },
2702 { "menuOptions.Auto Flag", False },
2703 { "menuOptions.Auto Flip View", False },
2704 { "menuOptions.Auto Observe", False },
2705 { "menuOptions.Auto Raise Board", False },
2706 { "menuOptions.Get Move List", False },
2707 { "menuOptions.ICS Alarm", False },
2708 { "menuOptions.Move Sound", False },
2709 { "menuOptions.Quiet Play", False },
2710 { "menuOptions.Hide Thinking", False },
2711 { "menuOptions.Periodic Updates", False },
2712 { "menuOptions.Ponder Next Move", False },
2713 { "menuHelp.Hint", False },
2714 { "menuHelp.Book", False },
2718 Enables gnuEnables[] = {
2719 { "menuMode.ICS Client", False },
2720 { "menuMode.ICS Input Box", False },
2721 { "menuAction.Accept", False },
2722 { "menuAction.Decline", False },
2723 { "menuAction.Rematch", False },
2724 { "menuAction.Adjourn", False },
2725 { "menuAction.Stop Examining", False },
2726 { "menuAction.Stop Observing", False },
2727 { "menuAction.Upload to Examine", False },
2728 { "menuStep.Revert", False },
2729 { "menuStep.Annotate", False },
2730 { "menuOptions.Auto Comment", False },
2731 { "menuOptions.Auto Observe", False },
2732 { "menuOptions.Auto Raise Board", False },
2733 { "menuOptions.Get Move List", False },
2734 { "menuOptions.Premove", False },
2735 { "menuOptions.Quiet Play", False },
2737 /* The next two options rely on SetCmailMode being called *after* */
2738 /* SetGNUMode so that when GNU is being used to give hints these */
2739 /* menu options are still available */
2741 { "menuFile.Mail Move", False },
2742 { "menuFile.Reload CMail Message", False },
2746 Enables cmailEnables[] = {
2748 { "menuAction.Call Flag", False },
2749 { "menuAction.Draw", True },
2750 { "menuAction.Adjourn", False },
2751 { "menuAction.Abort", False },
2752 { "menuAction.Stop Observing", False },
2753 { "menuAction.Stop Examining", False },
2754 { "menuFile.Mail Move", True },
2755 { "menuFile.Reload CMail Message", True },
2759 Enables trainingOnEnables[] = {
2760 { "menuMode.Edit Comment", False },
2761 { "menuMode.Pause", False },
2762 { "menuStep.Forward", False },
2763 { "menuStep.Backward", False },
2764 { "menuStep.Forward to End", False },
2765 { "menuStep.Back to Start", False },
2766 { "menuStep.Move Now", False },
2767 { "menuStep.Truncate Game", False },
2771 Enables trainingOffEnables[] = {
2772 { "menuMode.Edit Comment", True },
2773 { "menuMode.Pause", True },
2774 { "menuStep.Forward", True },
2775 { "menuStep.Backward", True },
2776 { "menuStep.Forward to End", True },
2777 { "menuStep.Back to Start", True },
2778 { "menuStep.Move Now", True },
2779 { "menuStep.Truncate Game", True },
2783 Enables machineThinkingEnables[] = {
2784 { "menuFile.Load Game", False },
2785 { "menuFile.Load Next Game", False },
2786 { "menuFile.Load Previous Game", False },
2787 { "menuFile.Reload Same Game", False },
2788 { "menuFile.Paste Game", False },
2789 { "menuFile.Load Position", False },
2790 { "menuFile.Load Next Position", False },
2791 { "menuFile.Load Previous Position", False },
2792 { "menuFile.Reload Same Position", False },
2793 { "menuFile.Paste Position", False },
2794 { "menuMode.Machine White", False },
2795 { "menuMode.Machine Black", False },
2796 { "menuMode.Two Machines", False },
2797 { "menuStep.Retract Move", False },
2801 Enables userThinkingEnables[] = {
2802 { "menuFile.Load Game", True },
2803 { "menuFile.Load Next Game", True },
2804 { "menuFile.Load Previous Game", True },
2805 { "menuFile.Reload Same Game", True },
2806 { "menuFile.Paste Game", True },
2807 { "menuFile.Load Position", True },
2808 { "menuFile.Load Next Position", True },
2809 { "menuFile.Load Previous Position", True },
2810 { "menuFile.Reload Same Position", True },
2811 { "menuFile.Paste Position", True },
2812 { "menuMode.Machine White", True },
2813 { "menuMode.Machine Black", True },
2814 { "menuMode.Two Machines", True },
2815 { "menuStep.Retract Move", True },
2821 SetMenuEnables(icsEnables);
2824 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2825 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2832 SetMenuEnables(ncpEnables);
2838 SetMenuEnables(gnuEnables);
2844 SetMenuEnables(cmailEnables);
2850 SetMenuEnables(trainingOnEnables);
2851 if (appData.showButtonBar) {
2852 XtSetSensitive(buttonBarWidget, False);
2858 SetTrainingModeOff()
2860 SetMenuEnables(trainingOffEnables);
2861 if (appData.showButtonBar) {
2862 XtSetSensitive(buttonBarWidget, True);
2867 SetUserThinkingEnables()
2869 if (appData.noChessProgram) return;
2870 SetMenuEnables(userThinkingEnables);
2874 SetMachineThinkingEnables()
2876 if (appData.noChessProgram) return;
2877 SetMenuEnables(machineThinkingEnables);
2879 case MachinePlaysBlack:
2880 case MachinePlaysWhite:
2881 case TwoMachinesPlay:
2882 XtSetSensitive(XtNameToWidget(menuBarWidget,
2883 ModeToWidgetName(gameMode)), True);
2890 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2891 #define HISTORY_SIZE 64
\r
2892 static char *history[HISTORY_SIZE];
\r
2893 int histIn = 0, histP = 0;
\r
2896 SaveInHistory(char *cmd)
\r
2898 if (history[histIn] != NULL) {
\r
2899 free(history[histIn]);
\r
2900 history[histIn] = NULL;
\r
2902 if (*cmd == NULLCHAR) return;
\r
2903 history[histIn] = StrSave(cmd);
\r
2904 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2905 if (history[histIn] != NULL) {
\r
2906 free(history[histIn]);
\r
2907 history[histIn] = NULL;
\r
2913 PrevInHistory(char *cmd)
\r
2916 if (histP == histIn) {
\r
2917 if (history[histIn] != NULL) free(history[histIn]);
\r
2918 history[histIn] = StrSave(cmd);
\r
2920 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2921 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2923 return history[histP];
\r
2929 if (histP == histIn) return NULL;
\r
2930 histP = (histP + 1) % HISTORY_SIZE;
\r
2931 return history[histP];
\r
2933 // end of borrowed code
\r
2935 #define Abs(n) ((n)<0 ? -(n) : (n))
2938 * Find a font that matches "pattern" that is as close as
2939 * possible to the targetPxlSize. Prefer fonts that are k
2940 * pixels smaller to fonts that are k pixels larger. The
2941 * pattern must be in the X Consortium standard format,
2942 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2943 * The return value should be freed with XtFree when no
2946 char *FindFont(pattern, targetPxlSize)
2950 char **fonts, *p, *best, *scalable, *scalableTail;
2951 int i, j, nfonts, minerr, err, pxlSize;
2954 char **missing_list;
2956 char *def_string, *base_fnt_lst, strInt[3];
2958 XFontStruct **fnt_list;
2960 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2961 sprintf(strInt, "%d", targetPxlSize);
2962 p = strstr(pattern, "--");
2963 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2964 strcat(base_fnt_lst, strInt);
2965 strcat(base_fnt_lst, strchr(p + 2, '-'));
2967 if ((fntSet = XCreateFontSet(xDisplay,
2971 &def_string)) == NULL) {
2973 fprintf(stderr, _("Unable to create font set.\n"));
2977 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2979 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2981 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2982 programName, pattern);
2990 for (i=0; i<nfonts; i++) {
2993 if (*p != '-') continue;
2995 if (*p == NULLCHAR) break;
2996 if (*p++ == '-') j++;
2998 if (j < 7) continue;
3001 scalable = fonts[i];
3004 err = pxlSize - targetPxlSize;
3005 if (Abs(err) < Abs(minerr) ||
3006 (minerr > 0 && err < 0 && -err == minerr)) {
3012 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3013 /* If the error is too big and there is a scalable font,
3014 use the scalable font. */
3015 int headlen = scalableTail - scalable;
3016 p = (char *) XtMalloc(strlen(scalable) + 10);
3017 while (isdigit(*scalableTail)) scalableTail++;
3018 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3020 p = (char *) XtMalloc(strlen(best) + 1);
3023 if (appData.debugMode) {
3024 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3025 pattern, targetPxlSize, p);
3028 if (missing_count > 0)
3029 XFreeStringList(missing_list);
3030 XFreeFontSet(xDisplay, fntSet);
3032 XFreeFontNames(fonts);
3039 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3040 | GCBackground | GCFunction | GCPlaneMask;
3041 XGCValues gc_values;
3044 gc_values.plane_mask = AllPlanes;
3045 gc_values.line_width = lineGap;
3046 gc_values.line_style = LineSolid;
3047 gc_values.function = GXcopy;
3049 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3050 gc_values.background = XBlackPixel(xDisplay, xScreen);
3051 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3053 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3054 gc_values.background = XWhitePixel(xDisplay, xScreen);
3055 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3056 XSetFont(xDisplay, coordGC, coordFontID);
3058 // [HGM] make font for holdings counts (white on black0
3059 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3060 gc_values.background = XBlackPixel(xDisplay, xScreen);
3061 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3062 XSetFont(xDisplay, countGC, countFontID);
3064 if (appData.monoMode) {
3065 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3066 gc_values.background = XWhitePixel(xDisplay, xScreen);
3067 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3069 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3070 gc_values.background = XBlackPixel(xDisplay, xScreen);
3071 lightSquareGC = wbPieceGC
3072 = XtGetGC(shellWidget, value_mask, &gc_values);
3074 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3075 gc_values.background = XWhitePixel(xDisplay, xScreen);
3076 darkSquareGC = bwPieceGC
3077 = XtGetGC(shellWidget, value_mask, &gc_values);
3079 if (DefaultDepth(xDisplay, xScreen) == 1) {
3080 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3081 gc_values.function = GXcopyInverted;
3082 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3083 gc_values.function = GXcopy;
3084 if (XBlackPixel(xDisplay, xScreen) == 1) {
3085 bwPieceGC = darkSquareGC;
3086 wbPieceGC = copyInvertedGC;
3088 bwPieceGC = copyInvertedGC;
3089 wbPieceGC = lightSquareGC;
3093 gc_values.foreground = highlightSquareColor;
3094 gc_values.background = highlightSquareColor;
3095 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3097 gc_values.foreground = premoveHighlightColor;
3098 gc_values.background = premoveHighlightColor;
3099 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3101 gc_values.foreground = lightSquareColor;
3102 gc_values.background = darkSquareColor;
3103 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3105 gc_values.foreground = darkSquareColor;
3106 gc_values.background = lightSquareColor;
3107 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3109 gc_values.foreground = jailSquareColor;
3110 gc_values.background = jailSquareColor;
3111 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3113 gc_values.foreground = whitePieceColor;
3114 gc_values.background = darkSquareColor;
3115 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3117 gc_values.foreground = whitePieceColor;
3118 gc_values.background = lightSquareColor;
3119 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3121 gc_values.foreground = whitePieceColor;
3122 gc_values.background = jailSquareColor;
3123 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3125 gc_values.foreground = blackPieceColor;
3126 gc_values.background = darkSquareColor;
3127 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3129 gc_values.foreground = blackPieceColor;
3130 gc_values.background = lightSquareColor;
3131 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3133 gc_values.foreground = blackPieceColor;
3134 gc_values.background = jailSquareColor;
3135 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3139 void loadXIM(xim, xmask, filename, dest, mask)
3152 fp = fopen(filename, "rb");
3154 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3161 for (y=0; y<h; ++y) {
3162 for (x=0; x<h; ++x) {
3167 XPutPixel(xim, x, y, blackPieceColor);
3169 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3172 XPutPixel(xim, x, y, darkSquareColor);
3174 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3177 XPutPixel(xim, x, y, whitePieceColor);
3179 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3182 XPutPixel(xim, x, y, lightSquareColor);
3184 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3190 /* create Pixmap of piece */
3191 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3193 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3196 /* create Pixmap of clipmask
3197 Note: We assume the white/black pieces have the same
3198 outline, so we make only 6 masks. This is okay
3199 since the XPM clipmask routines do the same. */
3201 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3203 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3206 /* now create the 1-bit version */
3207 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3210 values.foreground = 1;
3211 values.background = 0;
3213 /* Don't use XtGetGC, not read only */
3214 maskGC = XCreateGC(xDisplay, *mask,
3215 GCForeground | GCBackground, &values);
3216 XCopyPlane(xDisplay, temp, *mask, maskGC,
3217 0, 0, squareSize, squareSize, 0, 0, 1);
3218 XFreePixmap(xDisplay, temp);
3223 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3225 void CreateXIMPieces()
3230 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3235 /* The XSynchronize calls were copied from CreatePieces.
3236 Not sure if needed, but can't hurt */
3237 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3240 /* temp needed by loadXIM() */
3241 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3242 0, 0, ss, ss, AllPlanes, XYPixmap);
3244 if (strlen(appData.pixmapDirectory) == 0) {
3248 if (appData.monoMode) {
3249 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3253 fprintf(stderr, _("\nLoading XIMs...\n"));
3255 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3256 fprintf(stderr, "%d", piece+1);
3257 for (kind=0; kind<4; kind++) {
3258 fprintf(stderr, ".");
3259 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3260 ExpandPathName(appData.pixmapDirectory),
3261 piece <= (int) WhiteKing ? "" : "w",
3262 pieceBitmapNames[piece],
3264 ximPieceBitmap[kind][piece] =
3265 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3266 0, 0, ss, ss, AllPlanes, XYPixmap);
3267 if (appData.debugMode)
3268 fprintf(stderr, _("(File:%s:) "), buf);
3269 loadXIM(ximPieceBitmap[kind][piece],
3271 &(xpmPieceBitmap2[kind][piece]),
3272 &(ximMaskPm2[piece]));
3273 if(piece <= (int)WhiteKing)
3274 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3276 fprintf(stderr," ");
3278 /* Load light and dark squares */
3279 /* If the LSQ and DSQ pieces don't exist, we will
3280 draw them with solid squares. */
3281 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3282 if (access(buf, 0) != 0) {
3286 fprintf(stderr, _("light square "));
3288 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3289 0, 0, ss, ss, AllPlanes, XYPixmap);
3290 if (appData.debugMode)
3291 fprintf(stderr, _("(File:%s:) "), buf);
3293 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3294 fprintf(stderr, _("dark square "));
3295 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3296 ExpandPathName(appData.pixmapDirectory), ss);
3297 if (appData.debugMode)
3298 fprintf(stderr, _("(File:%s:) "), buf);
3300 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3301 0, 0, ss, ss, AllPlanes, XYPixmap);
3302 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3303 xpmJailSquare = xpmLightSquare;
3305 fprintf(stderr, _("Done.\n"));
3307 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3311 void CreateXPMPieces()
3315 u_int ss = squareSize;
3317 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3318 XpmColorSymbol symbols[4];
3320 /* The XSynchronize calls were copied from CreatePieces.
3321 Not sure if needed, but can't hurt */
3322 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3324 /* Setup translations so piece colors match square colors */
3325 symbols[0].name = "light_piece";
3326 symbols[0].value = appData.whitePieceColor;
3327 symbols[1].name = "dark_piece";
3328 symbols[1].value = appData.blackPieceColor;
3329 symbols[2].name = "light_square";
3330 symbols[2].value = appData.lightSquareColor;
3331 symbols[3].name = "dark_square";
3332 symbols[3].value = appData.darkSquareColor;
3334 attr.valuemask = XpmColorSymbols;
3335 attr.colorsymbols = symbols;
3336 attr.numsymbols = 4;
3338 if (appData.monoMode) {
3339 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3343 if (strlen(appData.pixmapDirectory) == 0) {
3344 XpmPieces* pieces = builtInXpms;
3347 while (pieces->size != squareSize && pieces->size) pieces++;
3348 if (!pieces->size) {
3349 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3352 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3353 for (kind=0; kind<4; kind++) {
3355 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3356 pieces->xpm[piece][kind],
3357 &(xpmPieceBitmap2[kind][piece]),
3358 NULL, &attr)) != 0) {
3359 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3363 if(piece <= (int) WhiteKing)
3364 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3368 xpmJailSquare = xpmLightSquare;
3372 fprintf(stderr, _("\nLoading XPMs...\n"));
3375 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3376 fprintf(stderr, "%d ", piece+1);
3377 for (kind=0; kind<4; kind++) {
3378 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3379 ExpandPathName(appData.pixmapDirectory),
3380 piece > (int) WhiteKing ? "w" : "",
3381 pieceBitmapNames[piece],
3383 if (appData.debugMode) {
3384 fprintf(stderr, _("(File:%s:) "), buf);
3386 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3387 &(xpmPieceBitmap2[kind][piece]),
3388 NULL, &attr)) != 0) {
3389 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3390 // [HGM] missing: read of unorthodox piece failed; substitute King.
3391 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3392 ExpandPathName(appData.pixmapDirectory),
3394 if (appData.debugMode) {
3395 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3397 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3398 &(xpmPieceBitmap2[kind][piece]),
3402 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3407 if(piece <= (int) WhiteKing)
3408 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3411 /* Load light and dark squares */
3412 /* If the LSQ and DSQ pieces don't exist, we will
3413 draw them with solid squares. */
3414 fprintf(stderr, _("light square "));
3415 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3416 if (access(buf, 0) != 0) {
3420 if (appData.debugMode)
3421 fprintf(stderr, _("(File:%s:) "), buf);
3423 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3424 &xpmLightSquare, NULL, &attr)) != 0) {
3425 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3428 fprintf(stderr, _("dark square "));
3429 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3430 ExpandPathName(appData.pixmapDirectory), ss);
3431 if (appData.debugMode) {
3432 fprintf(stderr, _("(File:%s:) "), buf);
3434 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3435 &xpmDarkSquare, NULL, &attr)) != 0) {
3436 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3440 xpmJailSquare = xpmLightSquare;
3441 fprintf(stderr, _("Done.\n"));
3443 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3446 #endif /* HAVE_LIBXPM */
3449 /* No built-in bitmaps */
3454 u_int ss = squareSize;
3456 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3459 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3460 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3461 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3462 pieceBitmapNames[piece],
3463 ss, kind == SOLID ? 's' : 'o');
3464 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3465 if(piece <= (int)WhiteKing)
3466 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3470 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3474 /* With built-in bitmaps */
3477 BuiltInBits* bib = builtInBits;
3480 u_int ss = squareSize;
3482 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3485 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3487 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3488 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3489 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3490 pieceBitmapNames[piece],
3491 ss, kind == SOLID ? 's' : 'o');
3492 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3493 bib->bits[kind][piece], ss, ss);
3494 if(piece <= (int)WhiteKing)
3495 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3499 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3504 void ReadBitmap(pm, name, bits, wreq, hreq)
3507 unsigned char bits[];
3513 char msg[MSG_SIZ], fullname[MSG_SIZ];
3515 if (*appData.bitmapDirectory != NULLCHAR) {
3516 strcpy(fullname, appData.bitmapDirectory);
3517 strcat(fullname, "/");
3518 strcat(fullname, name);
3519 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3520 &w, &h, pm, &x_hot, &y_hot);
3521 fprintf(stderr, "load %s\n", name);
3522 if (errcode != BitmapSuccess) {
3524 case BitmapOpenFailed:
3525 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3527 case BitmapFileInvalid:
3528 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3530 case BitmapNoMemory:
3531 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3535 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3539 fprintf(stderr, _("%s: %s...using built-in\n"),
3541 } else if (w != wreq || h != hreq) {
3543 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3544 programName, fullname, w, h, wreq, hreq);
3550 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3559 if (lineGap == 0) return;
3561 /* [HR] Split this into 2 loops for non-square boards. */
3563 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3564 gridSegments[i].x1 = 0;
3565 gridSegments[i].x2 =
3566 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3567 gridSegments[i].y1 = gridSegments[i].y2
3568 = lineGap / 2 + (i * (squareSize + lineGap));
3571 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3572 gridSegments[j + i].y1 = 0;
3573 gridSegments[j + i].y2 =
3574 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3575 gridSegments[j + i].x1 = gridSegments[j + i].x2
3576 = lineGap / 2 + (j * (squareSize + lineGap));
3580 static void MenuBarSelect(w, addr, index)
3585 XtActionProc proc = (XtActionProc) addr;
3587 (proc)(NULL, NULL, NULL, NULL);
3590 void CreateMenuBarPopup(parent, name, mb)
3600 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3603 XtSetArg(args[j], XtNleftMargin, 20); j++;
3604 XtSetArg(args[j], XtNrightMargin, 20); j++;
3606 while (mi->string != NULL) {
3607 if (strcmp(mi->string, "----") == 0) {
3608 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3611 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3612 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3614 XtAddCallback(entry, XtNcallback,
3615 (XtCallbackProc) MenuBarSelect,
3616 (caddr_t) mi->proc);
3622 Widget CreateMenuBar(mb)
3626 Widget anchor, menuBar;
3628 char menuName[MSG_SIZ];
3631 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3632 XtSetArg(args[j], XtNvSpace, 0); j++;
3633 XtSetArg(args[j], XtNborderWidth, 0); j++;
3634 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3635 formWidget, args, j);
3637 while (mb->name != NULL) {
3638 strcpy(menuName, "menu");
3639 strcat(menuName, mb->name);
3641 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3644 shortName[0] = _(mb->name)[0];
3645 shortName[1] = NULLCHAR;
3646 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3649 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3652 XtSetArg(args[j], XtNborderWidth, 0); j++;
3653 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3655 CreateMenuBarPopup(menuBar, menuName, mb);
3661 Widget CreateButtonBar(mi)
3665 Widget button, buttonBar;
3669 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3671 XtSetArg(args[j], XtNhSpace, 0); j++;
3673 XtSetArg(args[j], XtNborderWidth, 0); j++;
3674 XtSetArg(args[j], XtNvSpace, 0); j++;
3675 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3676 formWidget, args, j);
3678 while (mi->string != NULL) {
3681 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3682 XtSetArg(args[j], XtNborderWidth, 0); j++;
3684 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3685 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3686 buttonBar, args, j);
3687 XtAddCallback(button, XtNcallback,
3688 (XtCallbackProc) MenuBarSelect,
3689 (caddr_t) mi->proc);
3696 CreatePieceMenu(name, color)
3703 ChessSquare selection;
3705 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3706 boardWidget, args, 0);
3708 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3709 String item = pieceMenuStrings[color][i];
3711 if (strcmp(item, "----") == 0) {
3712 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3715 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3716 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3718 selection = pieceMenuTranslation[color][i];
3719 XtAddCallback(entry, XtNcallback,
3720 (XtCallbackProc) PieceMenuSelect,
3721 (caddr_t) selection);
3722 if (selection == WhitePawn || selection == BlackPawn) {
3723 XtSetArg(args[0], XtNpopupOnEntry, entry);
3724 XtSetValues(menu, args, 1);
3737 ChessSquare selection;
3739 whitePieceMenu = CreatePieceMenu("menuW", 0);
3740 blackPieceMenu = CreatePieceMenu("menuB", 1);
3742 XtRegisterGrabAction(PieceMenuPopup, True,
3743 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3744 GrabModeAsync, GrabModeAsync);
3746 XtSetArg(args[0], XtNlabel, _("Drop"));
3747 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3748 boardWidget, args, 1);
3749 for (i = 0; i < DROP_MENU_SIZE; i++) {
3750 String item = dropMenuStrings[i];
3752 if (strcmp(item, "----") == 0) {
3753 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3756 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3757 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3759 selection = dropMenuTranslation[i];
3760 XtAddCallback(entry, XtNcallback,
3761 (XtCallbackProc) DropMenuSelect,
3762 (caddr_t) selection);
3767 void SetupDropMenu()
3775 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3776 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3777 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3778 dmEnables[i].piece);
3779 XtSetSensitive(entry, p != NULL || !appData.testLegality
3780 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3781 && !appData.icsActive));
3783 while (p && *p++ == dmEnables[i].piece) count++;
3784 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3786 XtSetArg(args[j], XtNlabel, label); j++;
3787 XtSetValues(entry, args, j);
3791 void PieceMenuPopup(w, event, params, num_params)
3795 Cardinal *num_params;
3797 String whichMenu; int menuNr;
3798 if (event->type == ButtonRelease)
3799 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3800 else if (event->type == ButtonPress)
3801 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3803 case 0: whichMenu = params[0]; break;
3804 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3806 case -1: if (errorUp) ErrorPopDown();
3809 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3812 static void PieceMenuSelect(w, piece, junk)
3817 if (pmFromX < 0 || pmFromY < 0) return;
3818 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3821 static void DropMenuSelect(w, piece, junk)
3826 if (pmFromX < 0 || pmFromY < 0) return;
3827 DropMenuEvent(piece, pmFromX, pmFromY);
3830 void WhiteClock(w, event, prms, nprms)
3836 if (gameMode == EditPosition || gameMode == IcsExamining) {
3837 SetWhiteToPlayEvent();
3838 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3843 void BlackClock(w, event, prms, nprms)
3849 if (gameMode == EditPosition || gameMode == IcsExamining) {
3850 SetBlackToPlayEvent();
3851 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3858 * If the user selects on a border boundary, return -1; if off the board,
3859 * return -2. Otherwise map the event coordinate to the square.
3861 int EventToSquare(x, limit)
3869 if ((x % (squareSize + lineGap)) >= squareSize)
3871 x /= (squareSize + lineGap);
3877 static void do_flash_delay(msec)
3883 static void drawHighlight(file, rank, gc)
3889 if (lineGap == 0 || appData.blindfold) return;
3892 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3893 (squareSize + lineGap);
3894 y = lineGap/2 + rank * (squareSize + lineGap);
3896 x = lineGap/2 + file * (squareSize + lineGap);
3897 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3898 (squareSize + lineGap);
3901 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3902 squareSize+lineGap, squareSize+lineGap);
3905 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3906 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3909 SetHighlights(fromX, fromY, toX, toY)
3910 int fromX, fromY, toX, toY;
3912 if (hi1X != fromX || hi1Y != fromY) {
3913 if (hi1X >= 0 && hi1Y >= 0) {
3914 drawHighlight(hi1X, hi1Y, lineGC);
3916 } // [HGM] first erase both, then draw new!
3917 if (hi2X != toX || hi2Y != toY) {
3918 if (hi2X >= 0 && hi2Y >= 0) {
3919 drawHighlight(hi2X, hi2Y, lineGC);
3922 if (hi1X != fromX || hi1Y != fromY) {
3923 if (fromX >= 0 && fromY >= 0) {
3924 drawHighlight(fromX, fromY, highlineGC);
3927 if (hi2X != toX || hi2Y != toY) {
3928 if (toX >= 0 && toY >= 0) {
3929 drawHighlight(toX, toY, highlineGC);
3941 SetHighlights(-1, -1, -1, -1);
3946 SetPremoveHighlights(fromX, fromY, toX, toY)
3947 int fromX, fromY, toX, toY;
3949 if (pm1X != fromX || pm1Y != fromY) {
3950 if (pm1X >= 0 && pm1Y >= 0) {
3951 drawHighlight(pm1X, pm1Y, lineGC);
3953 if (fromX >= 0 && fromY >= 0) {
3954 drawHighlight(fromX, fromY, prelineGC);
3957 if (pm2X != toX || pm2Y != toY) {
3958 if (pm2X >= 0 && pm2Y >= 0) {
3959 drawHighlight(pm2X, pm2Y, lineGC);
3961 if (toX >= 0 && toY >= 0) {
3962 drawHighlight(toX, toY, prelineGC);
3972 ClearPremoveHighlights()
3974 SetPremoveHighlights(-1, -1, -1, -1);
3977 static void BlankSquare(x, y, color, piece, dest)
3982 if (useImages && useImageSqs) {
3986 pm = xpmLightSquare;
3991 case 2: /* neutral */
3996 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3997 squareSize, squareSize, x, y);
4007 case 2: /* neutral */
4012 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4017 I split out the routines to draw a piece so that I could
4018 make a generic flash routine.
4020 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4022 int square_color, x, y;
4025 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4026 switch (square_color) {
4028 case 2: /* neutral */
4030 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4031 ? *pieceToOutline(piece)
4032 : *pieceToSolid(piece),
4033 dest, bwPieceGC, 0, 0,
4034 squareSize, squareSize, x, y);
4037 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4038 ? *pieceToSolid(piece)
4039 : *pieceToOutline(piece),
4040 dest, wbPieceGC, 0, 0,
4041 squareSize, squareSize, x, y);
4046 static void monoDrawPiece(piece, square_color, x, y, dest)
4048 int square_color, x, y;
4051 switch (square_color) {
4053 case 2: /* neutral */
4055 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4056 ? *pieceToOutline(piece)
4057 : *pieceToSolid(piece),
4058 dest, bwPieceGC, 0, 0,
4059 squareSize, squareSize, x, y, 1);
4062 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4063 ? *pieceToSolid(piece)
4064 : *pieceToOutline(piece),
4065 dest, wbPieceGC, 0, 0,
4066 squareSize, squareSize, x, y, 1);
4071 static void colorDrawPiece(piece, square_color, x, y, dest)
4073 int square_color, x, y;
4076 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4077 switch (square_color) {
4079 XCopyPlane(xDisplay, *pieceToSolid(piece),
4080 dest, (int) piece < (int) BlackPawn
4081 ? wlPieceGC : blPieceGC, 0, 0,
4082 squareSize, squareSize, x, y, 1);
4085 XCopyPlane(xDisplay, *pieceToSolid(piece),
4086 dest, (int) piece < (int) BlackPawn
4087 ? wdPieceGC : bdPieceGC, 0, 0,
4088 squareSize, squareSize, x, y, 1);
4090 case 2: /* neutral */
4092 XCopyPlane(xDisplay, *pieceToSolid(piece),
4093 dest, (int) piece < (int) BlackPawn
4094 ? wjPieceGC : bjPieceGC, 0, 0,
4095 squareSize, squareSize, x, y, 1);
4100 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4102 int square_color, x, y;
4107 switch (square_color) {
4109 case 2: /* neutral */
4111 if ((int)piece < (int) BlackPawn) {
4119 if ((int)piece < (int) BlackPawn) {
4127 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4128 dest, wlPieceGC, 0, 0,
4129 squareSize, squareSize, x, y);
4132 typedef void (*DrawFunc)();
4134 DrawFunc ChooseDrawFunc()
4136 if (appData.monoMode) {
4137 if (DefaultDepth(xDisplay, xScreen) == 1) {
4138 return monoDrawPiece_1bit;
4140 return monoDrawPiece;
4144 return colorDrawPieceImage;
4146 return colorDrawPiece;
4150 /* [HR] determine square color depending on chess variant. */
4151 static int SquareColor(row, column)
4156 if (gameInfo.variant == VariantXiangqi) {
4157 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4159 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4161 } else if (row <= 4) {
4167 square_color = ((column + row) % 2) == 1;
4170 /* [hgm] holdings: next line makes all holdings squares light */
4171 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4173 return square_color;
4176 void DrawSquare(row, column, piece, do_flash)
4177 int row, column, do_flash;
4180 int square_color, x, y, direction, font_ascent, font_descent;
4183 XCharStruct overall;
4187 /* Calculate delay in milliseconds (2-delays per complete flash) */
4188 flash_delay = 500 / appData.flashRate;
4191 x = lineGap + ((BOARD_WIDTH-1)-column) *
4192 (squareSize + lineGap);
4193 y = lineGap + row * (squareSize + lineGap);
4195 x = lineGap + column * (squareSize + lineGap);
4196 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4197 (squareSize + lineGap);
4200 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4202 square_color = SquareColor(row, column);
4204 if ( // [HGM] holdings: blank out area between board and holdings
4205 column == BOARD_LEFT-1 || column == BOARD_RGHT
4206 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4207 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4208 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4210 // [HGM] print piece counts next to holdings
4211 string[1] = NULLCHAR;
4212 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4213 string[0] = '0' + piece;
4214 XTextExtents(countFontStruct, string, 1, &direction,
4215 &font_ascent, &font_descent, &overall);
4216 if (appData.monoMode) {
4217 XDrawImageString(xDisplay, xBoardWindow, countGC,
4218 x + squareSize - overall.width - 2,
4219 y + font_ascent + 1, string, 1);
4221 XDrawString(xDisplay, xBoardWindow, countGC,
4222 x + squareSize - overall.width - 2,
4223 y + font_ascent + 1, string, 1);
4226 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4227 string[0] = '0' + piece;
4228 XTextExtents(countFontStruct, string, 1, &direction,
4229 &font_ascent, &font_descent, &overall);
4230 if (appData.monoMode) {
4231 XDrawImageString(xDisplay, xBoardWindow, countGC,
4232 x + 2, y + font_ascent + 1, string, 1);
4234 XDrawString(xDisplay, xBoardWindow, countGC,
4235 x + 2, y + font_ascent + 1, string, 1);
4239 if (piece == EmptySquare || appData.blindfold) {
4240 BlankSquare(x, y, square_color, piece, xBoardWindow);
4242 drawfunc = ChooseDrawFunc();
4243 if (do_flash && appData.flashCount > 0) {
4244 for (i=0; i<appData.flashCount; ++i) {
4246 drawfunc(piece, square_color, x, y, xBoardWindow);
4247 XSync(xDisplay, False);
4248 do_flash_delay(flash_delay);
4250 BlankSquare(x, y, square_color, piece, xBoardWindow);
4251 XSync(xDisplay, False);
4252 do_flash_delay(flash_delay);
4255 drawfunc(piece, square_color, x, y, xBoardWindow);
4259 string[1] = NULLCHAR;
4260 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4261 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4262 string[0] = 'a' + column - BOARD_LEFT;
4263 XTextExtents(coordFontStruct, string, 1, &direction,
4264 &font_ascent, &font_descent, &overall);
4265 if (appData.monoMode) {
4266 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4267 x + squareSize - overall.width - 2,
4268 y + squareSize - font_descent - 1, string, 1);
4270 XDrawString(xDisplay, xBoardWindow, coordGC,
4271 x + squareSize - overall.width - 2,
4272 y + squareSize - font_descent - 1, string, 1);
4275 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4276 string[0] = ONE + row;
4277 XTextExtents(coordFontStruct, string, 1, &direction,
4278 &font_ascent, &font_descent, &overall);
4279 if (appData.monoMode) {
4280 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4281 x + 2, y + font_ascent + 1, string, 1);
4283 XDrawString(xDisplay, xBoardWindow, coordGC,
4284 x + 2, y + font_ascent + 1, string, 1);
4287 if(!partnerUp && marker[row][column]) {
4288 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4289 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4294 /* Why is this needed on some versions of X? */
4295 void EventProc(widget, unused, event)
4300 if (!XtIsRealized(widget))
4303 switch (event->type) {
4305 if (event->xexpose.count > 0) return; /* no clipping is done */
4306 XDrawPosition(widget, True, NULL);
4307 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4308 flipView = !flipView; partnerUp = !partnerUp;
4309 XDrawPosition(widget, True, NULL);
4310 flipView = !flipView; partnerUp = !partnerUp;
4314 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4321 void DrawPosition(fullRedraw, board)
4322 /*Boolean*/int fullRedraw;
4325 XDrawPosition(boardWidget, fullRedraw, board);
4328 /* Returns 1 if there are "too many" differences between b1 and b2
4329 (i.e. more than 1 move was made) */
4330 static int too_many_diffs(b1, b2)
4336 for (i=0; i<BOARD_HEIGHT; ++i) {
4337 for (j=0; j<BOARD_WIDTH; ++j) {
4338 if (b1[i][j] != b2[i][j]) {
4339 if (++c > 4) /* Castling causes 4 diffs */
4348 /* Matrix describing castling maneuvers */
4349 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4350 static int castling_matrix[4][5] = {
4351 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4352 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4353 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4354 { 7, 7, 4, 5, 6 } /* 0-0, black */
4357 /* Checks whether castling occurred. If it did, *rrow and *rcol
4358 are set to the destination (row,col) of the rook that moved.
4360 Returns 1 if castling occurred, 0 if not.
4362 Note: Only handles a max of 1 castling move, so be sure
4363 to call too_many_diffs() first.
4365 static int check_castle_draw(newb, oldb, rrow, rcol)
4372 /* For each type of castling... */
4373 for (i=0; i<4; ++i) {
4374 r = castling_matrix[i];
4376 /* Check the 4 squares involved in the castling move */
4378 for (j=1; j<=4; ++j) {
4379 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4386 /* All 4 changed, so it must be a castling move */
4395 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4396 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4398 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4401 void DrawSeekBackground( int left, int top, int right, int bottom )
4403 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4406 void DrawSeekText(char *buf, int x, int y)
4408 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4411 void DrawSeekDot(int x, int y, int colorNr)
4413 int square = colorNr & 0x80;
4416 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4418 XFillRectangle(xDisplay, xBoardWindow, color,
4419 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4421 XFillArc(xDisplay, xBoardWindow, color,
4422 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4425 static int damage[2][BOARD_RANKS][BOARD_FILES];
4428 * event handler for redrawing the board
4430 void XDrawPosition(w, repaint, board)
4432 /*Boolean*/int repaint;
4436 static int lastFlipView = 0;
4437 static int lastBoardValid[2] = {0, 0};
4438 static Board lastBoard[2];
4441 int nr = twoBoards*partnerUp;
4443 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4445 if (board == NULL) {
4446 if (!lastBoardValid) return;
4447 board = lastBoard[nr];
4449 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4450 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4451 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4456 * It would be simpler to clear the window with XClearWindow()
4457 * but this causes a very distracting flicker.
4460 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4462 /* If too much changes (begin observing new game, etc.), don't
4464 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4466 /* Special check for castling so we don't flash both the king
4467 and the rook (just flash the king). */
4469 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4470 /* Draw rook with NO flashing. King will be drawn flashing later */
4471 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4472 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4476 /* First pass -- Draw (newly) empty squares and repair damage.
4477 This prevents you from having a piece show up twice while it
4478 is flashing on its new square */
4479 for (i = 0; i < BOARD_HEIGHT; i++)
4480 for (j = 0; j < BOARD_WIDTH; j++)
4481 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4482 || damage[nr][i][j]) {
4483 DrawSquare(i, j, board[i][j], 0);
4484 damage[nr][i][j] = False;
4487 /* Second pass -- Draw piece(s) in new position and flash them */
4488 for (i = 0; i < BOARD_HEIGHT; i++)
4489 for (j = 0; j < BOARD_WIDTH; j++)
4490 if (board[i][j] != lastBoard[nr][i][j]) {
4491 DrawSquare(i, j, board[i][j], do_flash);
4495 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4496 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4497 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4499 for (i = 0; i < BOARD_HEIGHT; i++)
4500 for (j = 0; j < BOARD_WIDTH; j++) {
4501 DrawSquare(i, j, board[i][j], 0);
4502 damage[nr][i][j] = False;
4506 CopyBoard(lastBoard[nr], board);
4507 lastBoardValid[nr] = 1;
4508 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4509 lastFlipView = flipView;
4511 /* Draw highlights */
4512 if (pm1X >= 0 && pm1Y >= 0) {
4513 drawHighlight(pm1X, pm1Y, prelineGC);
4515 if (pm2X >= 0 && pm2Y >= 0) {
4516 drawHighlight(pm2X, pm2Y, prelineGC);
4518 if (hi1X >= 0 && hi1Y >= 0) {
4519 drawHighlight(hi1X, hi1Y, highlineGC);
4521 if (hi2X >= 0 && hi2Y >= 0) {
4522 drawHighlight(hi2X, hi2Y, highlineGC);
4525 /* If piece being dragged around board, must redraw that too */
4528 XSync(xDisplay, False);
4533 * event handler for redrawing the board
4535 void DrawPositionProc(w, event, prms, nprms)
4541 XDrawPosition(w, True, NULL);
4546 * event handler for parsing user moves
4548 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4549 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4550 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4551 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4552 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4553 // and at the end FinishMove() to perform the move after optional promotion popups.
4554 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4555 void HandleUserMove(w, event, prms, nprms)
4561 if (w != boardWidget || errorExitStatus != -1) return;
4564 if (event->type == ButtonPress) {
4565 XtPopdown(promotionShell);
4566 XtDestroyWidget(promotionShell);
4567 promotionUp = False;
4575 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4576 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4577 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4580 void AnimateUserMove (Widget w, XEvent * event,
4581 String * params, Cardinal * nParams)
4583 DragPieceMove(event->xmotion.x, event->xmotion.y);
4586 void HandlePV (Widget w, XEvent * event,
4587 String * params, Cardinal * nParams)
4588 { // [HGM] pv: walk PV
4589 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4592 Widget CommentCreate(name, text, mutable, callback, lines)
4594 int /*Boolean*/ mutable;
4595 XtCallbackProc callback;
4599 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4604 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4605 XtGetValues(boardWidget, args, j);
4608 XtSetArg(args[j], XtNresizable, True); j++;
4611 XtCreatePopupShell(name, topLevelShellWidgetClass,
4612 shellWidget, args, j);
4615 XtCreatePopupShell(name, transientShellWidgetClass,
4616 shellWidget, args, j);
4619 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4620 layoutArgs, XtNumber(layoutArgs));
4622 XtCreateManagedWidget("form", formWidgetClass, layout,
4623 formArgs, XtNumber(formArgs));
4627 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4628 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4630 XtSetArg(args[j], XtNstring, text); j++;
4631 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4632 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4633 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4634 XtSetArg(args[j], XtNright, XtChainRight); j++;
4635 XtSetArg(args[j], XtNresizable, True); j++;
4636 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4637 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4638 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4639 XtSetArg(args[j], XtNautoFill, True); j++;
4640 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4642 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4646 XtSetArg(args[j], XtNfromVert, edit); j++;
4647 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4648 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4649 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4650 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4652 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4653 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4656 XtSetArg(args[j], XtNfromVert, edit); j++;
4657 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4658 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4659 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4660 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4661 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4663 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4664 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4667 XtSetArg(args[j], XtNfromVert, edit); j++;
4668 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4669 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4670 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4671 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4672 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4674 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4675 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4678 XtSetArg(args[j], XtNfromVert, edit); j++;
4679 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4680 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4681 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4682 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4684 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4685 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4688 XtSetArg(args[j], XtNfromVert, edit); j++;
4689 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4690 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4691 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4692 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4693 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4695 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4696 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4699 XtRealizeWidget(shell);
4701 if (commentX == -1) {
4704 Dimension pw_height;
4705 Dimension ew_height;
4708 XtSetArg(args[j], XtNheight, &ew_height); j++;
4709 XtGetValues(edit, args, j);
4712 XtSetArg(args[j], XtNheight, &pw_height); j++;
4713 XtGetValues(shell, args, j);
4714 commentH = pw_height + (lines - 1) * ew_height;
4715 commentW = bw_width - 16;
4717 XSync(xDisplay, False);
4719 /* This code seems to tickle an X bug if it is executed too soon
4720 after xboard starts up. The coordinates get transformed as if
4721 the main window was positioned at (0, 0).
4723 XtTranslateCoords(shellWidget,
4724 (bw_width - commentW) / 2, 0 - commentH / 2,
4725 &commentX, &commentY);
4727 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4728 RootWindowOfScreen(XtScreen(shellWidget)),
4729 (bw_width - commentW) / 2, 0 - commentH / 2,
4734 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4737 if(wpComment.width > 0) {
4738 commentX = wpComment.x;
4739 commentY = wpComment.y;
4740 commentW = wpComment.width;
4741 commentH = wpComment.height;
4745 XtSetArg(args[j], XtNheight, commentH); j++;
4746 XtSetArg(args[j], XtNwidth, commentW); j++;
4747 XtSetArg(args[j], XtNx, commentX); j++;
4748 XtSetArg(args[j], XtNy, commentY); j++;
4749 XtSetValues(shell, args, j);
4750 XtSetKeyboardFocus(shell, edit);
4755 /* Used for analysis window and ICS input window */
4756 Widget MiscCreate(name, text, mutable, callback, lines)
4758 int /*Boolean*/ mutable;
4759 XtCallbackProc callback;
4763 Widget shell, layout, form, edit;
4765 Dimension bw_width, pw_height, ew_height, w, h;
4771 XtSetArg(args[j], XtNresizable, True); j++;
4774 XtCreatePopupShell(name, topLevelShellWidgetClass,
4775 shellWidget, args, j);
4778 XtCreatePopupShell(name, transientShellWidgetClass,
4779 shellWidget, args, j);
4782 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4783 layoutArgs, XtNumber(layoutArgs));
4785 XtCreateManagedWidget("form", formWidgetClass, layout,
4786 formArgs, XtNumber(formArgs));
4790 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4791 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4793 XtSetArg(args[j], XtNstring, text); j++;
4794 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4795 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4796 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4797 XtSetArg(args[j], XtNright, XtChainRight); j++;
4798 XtSetArg(args[j], XtNresizable, True); j++;
4799 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4800 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4801 XtSetArg(args[j], XtNautoFill, True); j++;
4802 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4804 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4806 XtRealizeWidget(shell);
4809 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4810 XtGetValues(boardWidget, args, j);
4813 XtSetArg(args[j], XtNheight, &ew_height); j++;
4814 XtGetValues(edit, args, j);
4817 XtSetArg(args[j], XtNheight, &pw_height); j++;
4818 XtGetValues(shell, args, j);
4819 h = pw_height + (lines - 1) * ew_height;
4822 XSync(xDisplay, False);
4824 /* This code seems to tickle an X bug if it is executed too soon
4825 after xboard starts up. The coordinates get transformed as if
4826 the main window was positioned at (0, 0).
4828 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4830 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4831 RootWindowOfScreen(XtScreen(shellWidget)),
4832 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4836 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4839 XtSetArg(args[j], XtNheight, h); j++;
4840 XtSetArg(args[j], XtNwidth, w); j++;
4841 XtSetArg(args[j], XtNx, x); j++;
4842 XtSetArg(args[j], XtNy, y); j++;
4843 XtSetValues(shell, args, j);
4849 static int savedIndex; /* gross that this is global */
4851 void EditCommentPopUp(index, title, text)
4860 if (text == NULL) text = "";
4862 if (editShell == NULL) {
4864 CommentCreate(title, text, True, EditCommentCallback, 4);
4865 XtRealizeWidget(editShell);
4866 CatchDeleteWindow(editShell, "EditCommentPopDown");
4868 edit = XtNameToWidget(editShell, "*form.text");
4870 XtSetArg(args[j], XtNstring, text); j++;
4871 XtSetValues(edit, args, j);
4873 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4874 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4875 XtSetValues(editShell, args, j);
4878 XtPopup(editShell, XtGrabNone);
4882 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4883 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4887 void EditCommentCallback(w, client_data, call_data)
4889 XtPointer client_data, call_data;
4897 XtSetArg(args[j], XtNlabel, &name); j++;
4898 XtGetValues(w, args, j);
4900 if (strcmp(name, _("ok")) == 0) {
4901 edit = XtNameToWidget(editShell, "*form.text");
4903 XtSetArg(args[j], XtNstring, &val); j++;
4904 XtGetValues(edit, args, j);
4905 ReplaceComment(savedIndex, val);
4906 EditCommentPopDown();
4907 } else if (strcmp(name, _("cancel")) == 0) {
4908 EditCommentPopDown();
4909 } else if (strcmp(name, _("clear")) == 0) {
4910 edit = XtNameToWidget(editShell, "*form.text");
4911 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4912 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4916 void EditCommentPopDown()
4921 if (!editUp) return;
4923 XtSetArg(args[j], XtNx, &commentX); j++;
4924 XtSetArg(args[j], XtNy, &commentY); j++;
4925 XtSetArg(args[j], XtNheight, &commentH); j++;
4926 XtSetArg(args[j], XtNwidth, &commentW); j++;
4927 XtGetValues(editShell, args, j);
4928 XtPopdown(editShell);
4931 XtSetArg(args[j], XtNleftBitmap, None); j++;
4932 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4936 void ICSInputBoxPopUp()
4941 char *title = _("ICS Input");
4944 if (ICSInputShell == NULL) {
4945 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4946 tr = XtParseTranslationTable(ICSInputTranslations);
4947 edit = XtNameToWidget(ICSInputShell, "*form.text");
4948 XtOverrideTranslations(edit, tr);
4949 XtRealizeWidget(ICSInputShell);
4950 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4953 edit = XtNameToWidget(ICSInputShell, "*form.text");
4955 XtSetArg(args[j], XtNstring, ""); j++;
4956 XtSetValues(edit, args, j);
4958 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4959 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4960 XtSetValues(ICSInputShell, args, j);
4963 XtPopup(ICSInputShell, XtGrabNone);
4964 XtSetKeyboardFocus(ICSInputShell, edit);
4966 ICSInputBoxUp = True;
4968 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4969 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4973 void ICSInputSendText()
4980 edit = XtNameToWidget(ICSInputShell, "*form.text");
4982 XtSetArg(args[j], XtNstring, &val); j++;
4983 XtGetValues(edit, args, j);
4985 SendMultiLineToICS(val);
4986 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4987 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4990 void ICSInputBoxPopDown()
4995 if (!ICSInputBoxUp) return;
4997 XtPopdown(ICSInputShell);
4998 ICSInputBoxUp = False;
5000 XtSetArg(args[j], XtNleftBitmap, None); j++;
5001 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5005 void CommentPopUp(title, text)
5012 if (commentShell == NULL) {
5014 CommentCreate(title, text, False, CommentCallback, 4);
5015 XtRealizeWidget(commentShell);
5016 CatchDeleteWindow(commentShell, "CommentPopDown");
5018 edit = XtNameToWidget(commentShell, "*form.text");
5020 XtSetArg(args[j], XtNstring, text); j++;
5021 XtSetValues(edit, args, j);
5023 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5024 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5025 XtSetValues(commentShell, args, j);
5028 XtPopup(commentShell, XtGrabNone);
5029 XSync(xDisplay, False);
5034 void CommentCallback(w, client_data, call_data)
5036 XtPointer client_data, call_data;
5043 XtSetArg(args[j], XtNlabel, &name); j++;
5044 XtGetValues(w, args, j);
5046 if (strcmp(name, _("close")) == 0) {
5048 } else if (strcmp(name, _("edit")) == 0) {
5055 void CommentPopDown()
5060 if (!commentUp) return;
5062 XtSetArg(args[j], XtNx, &commentX); j++;
5063 XtSetArg(args[j], XtNy, &commentY); j++;
5064 XtSetArg(args[j], XtNwidth, &commentW); j++;
5065 XtSetArg(args[j], XtNheight, &commentH); j++;
5066 XtGetValues(commentShell, args, j);
5067 XtPopdown(commentShell);
5068 XSync(xDisplay, False);
5072 void FileNamePopUp(label, def, proc, openMode)
5079 Widget popup, layout, dialog, edit;
5085 fileProc = proc; /* I can't see a way not */
5086 fileOpenMode = openMode; /* to use globals here */
5087 { // [HGM] use file-selector dialog stolen from Ghostview
5089 int index; // this is not supported yet
5091 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5092 NULL, openMode, NULL, &name))
5093 (void) (*fileProc)(f, index=0, name);
5097 void FileNamePopDown()
5099 if (!filenameUp) return;
5100 XtPopdown(fileNameShell);
5101 XtDestroyWidget(fileNameShell);
5106 void FileNameCallback(w, client_data, call_data)
5108 XtPointer client_data, call_data;
5113 XtSetArg(args[0], XtNlabel, &name);
5114 XtGetValues(w, args, 1);
5116 if (strcmp(name, _("cancel")) == 0) {
5121 FileNameAction(w, NULL, NULL, NULL);
5124 void FileNameAction(w, event, prms, nprms)
5136 name = XawDialogGetValueString(w = XtParent(w));
5138 if ((name != NULL) && (*name != NULLCHAR)) {
5140 XtPopdown(w = XtParent(XtParent(w)));
5144 p = strrchr(buf, ' ');
5151 fullname = ExpandPathName(buf);
5153 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5156 f = fopen(fullname, fileOpenMode);
5158 DisplayError(_("Failed to open file"), errno);
5160 (void) (*fileProc)(f, index, buf);
5167 XtPopdown(w = XtParent(XtParent(w)));
5173 void PromotionPopUp()
5176 Widget dialog, layout;
5178 Dimension bw_width, pw_width;
5182 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5183 XtGetValues(boardWidget, args, j);
5186 XtSetArg(args[j], XtNresizable, True); j++;
5187 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5189 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5190 shellWidget, args, j);
5192 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5193 layoutArgs, XtNumber(layoutArgs));
5196 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5197 XtSetArg(args[j], XtNborderWidth, 0); j++;
5198 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5201 if(gameInfo.variant != VariantShogi) {
5202 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5203 (XtPointer) dialog);
5204 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5205 (XtPointer) dialog);
5206 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5207 (XtPointer) dialog);
5208 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5209 (XtPointer) dialog);
5210 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5211 gameInfo.variant == VariantGiveaway) {
5212 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5213 (XtPointer) dialog);
5215 if(gameInfo.variant == VariantCapablanca ||
5216 gameInfo.variant == VariantGothic ||
5217 gameInfo.variant == VariantCapaRandom) {
5218 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5219 (XtPointer) dialog);
5220 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5221 (XtPointer) dialog);
5223 } else // [HGM] shogi
5225 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5226 (XtPointer) dialog);
5227 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5228 (XtPointer) dialog);
5230 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5231 (XtPointer) dialog);
5233 XtRealizeWidget(promotionShell);
5234 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5237 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5238 XtGetValues(promotionShell, args, j);
5240 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5241 lineGap + squareSize/3 +
5242 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5243 0 : 6*(squareSize + lineGap)), &x, &y);
5246 XtSetArg(args[j], XtNx, x); j++;
5247 XtSetArg(args[j], XtNy, y); j++;
5248 XtSetValues(promotionShell, args, j);
5250 XtPopup(promotionShell, XtGrabNone);
5255 void PromotionPopDown()
5257 if (!promotionUp) return;
5258 XtPopdown(promotionShell);
5259 XtDestroyWidget(promotionShell);
5260 promotionUp = False;
5263 void PromotionCallback(w, client_data, call_data)
5265 XtPointer client_data, call_data;
5271 XtSetArg(args[0], XtNlabel, &name);
5272 XtGetValues(w, args, 1);
5276 if (fromX == -1) return;
5278 if (strcmp(name, _("cancel")) == 0) {
5282 } else if (strcmp(name, _("Knight")) == 0) {
5284 } else if (strcmp(name, _("Promote")) == 0) {
5286 } else if (strcmp(name, _("Defer")) == 0) {
5289 promoChar = ToLower(name[0]);
5292 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5294 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5295 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5300 void ErrorCallback(w, client_data, call_data)
5302 XtPointer client_data, call_data;
5305 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5307 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5313 if (!errorUp) return;
5315 XtPopdown(errorShell);
5316 XtDestroyWidget(errorShell);
5317 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5320 void ErrorPopUp(title, label, modal)
5321 char *title, *label;
5325 Widget dialog, layout;
5329 Dimension bw_width, pw_width;
5330 Dimension pw_height;
5334 XtSetArg(args[i], XtNresizable, True); i++;
5335 XtSetArg(args[i], XtNtitle, title); i++;
5337 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5338 shellWidget, args, i);
5340 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5341 layoutArgs, XtNumber(layoutArgs));
5344 XtSetArg(args[i], XtNlabel, label); i++;
5345 XtSetArg(args[i], XtNborderWidth, 0); i++;
5346 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5349 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5351 XtRealizeWidget(errorShell);
5352 CatchDeleteWindow(errorShell, "ErrorPopDown");
5355 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5356 XtGetValues(boardWidget, args, i);
5358 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5359 XtSetArg(args[i], XtNheight, &pw_height); i++;
5360 XtGetValues(errorShell, args, i);
5363 /* This code seems to tickle an X bug if it is executed too soon
5364 after xboard starts up. The coordinates get transformed as if
5365 the main window was positioned at (0, 0).
5367 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5368 0 - pw_height + squareSize / 3, &x, &y);
5370 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5371 RootWindowOfScreen(XtScreen(boardWidget)),
5372 (bw_width - pw_width) / 2,
5373 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5377 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5380 XtSetArg(args[i], XtNx, x); i++;
5381 XtSetArg(args[i], XtNy, y); i++;
5382 XtSetValues(errorShell, args, i);
5385 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5388 /* Disable all user input other than deleting the window */
5389 static int frozen = 0;
5393 /* Grab by a widget that doesn't accept input */
5394 XtAddGrab(messageWidget, TRUE, FALSE);
5398 /* Undo a FreezeUI */
5401 if (!frozen) return;
5402 XtRemoveGrab(messageWidget);
5406 char *ModeToWidgetName(mode)
5410 case BeginningOfGame:
5411 if (appData.icsActive)
5412 return "menuMode.ICS Client";
5413 else if (appData.noChessProgram ||
5414 *appData.cmailGameName != NULLCHAR)
5415 return "menuMode.Edit Game";
5417 return "menuMode.Machine Black";
5418 case MachinePlaysBlack:
5419 return "menuMode.Machine Black";
5420 case MachinePlaysWhite:
5421 return "menuMode.Machine White";
5423 return "menuMode.Analysis Mode";
5425 return "menuMode.Analyze File";
5426 case TwoMachinesPlay:
5427 return "menuMode.Two Machines";
5429 return "menuMode.Edit Game";
5430 case PlayFromGameFile:
5431 return "menuFile.Load Game";
5433 return "menuMode.Edit Position";
5435 return "menuMode.Training";
5436 case IcsPlayingWhite:
5437 case IcsPlayingBlack:
5441 return "menuMode.ICS Client";
5448 void ModeHighlight()
5451 static int oldPausing = FALSE;
5452 static GameMode oldmode = (GameMode) -1;
5455 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5457 if (pausing != oldPausing) {
5458 oldPausing = pausing;
5460 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5462 XtSetArg(args[0], XtNleftBitmap, None);
5464 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5467 if (appData.showButtonBar) {
5468 /* Always toggle, don't set. Previous code messes up when
5469 invoked while the button is pressed, as releasing it
5470 toggles the state again. */
5473 XtSetArg(args[0], XtNbackground, &oldbg);
5474 XtSetArg(args[1], XtNforeground, &oldfg);
5475 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5477 XtSetArg(args[0], XtNbackground, oldfg);
5478 XtSetArg(args[1], XtNforeground, oldbg);
5480 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5484 wname = ModeToWidgetName(oldmode);
5485 if (wname != NULL) {
5486 XtSetArg(args[0], XtNleftBitmap, None);
5487 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5489 wname = ModeToWidgetName(gameMode);
5490 if (wname != NULL) {
5491 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5492 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5496 /* Maybe all the enables should be handled here, not just this one */
5497 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5498 gameMode == Training || gameMode == PlayFromGameFile);
5503 * Button/menu procedures
5505 void ResetProc(w, event, prms, nprms)
5514 int LoadGamePopUp(f, gameNumber, title)
5519 cmailMsgLoaded = FALSE;
5520 if (gameNumber == 0) {
5521 int error = GameListBuild(f);
5523 DisplayError(_("Cannot build game list"), error);
5524 } else if (!ListEmpty(&gameList) &&
5525 ((ListGame *) gameList.tailPred)->number > 1) {
5526 GameListPopUp(f, title);
5532 return LoadGame(f, gameNumber, title, FALSE);
5535 void LoadGameProc(w, event, prms, nprms)
5541 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5544 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5547 void LoadNextGameProc(w, event, prms, nprms)
5556 void LoadPrevGameProc(w, event, prms, nprms)
5565 void ReloadGameProc(w, event, prms, nprms)
5574 void LoadNextPositionProc(w, event, prms, nprms)
5583 void LoadPrevPositionProc(w, event, prms, nprms)
5592 void ReloadPositionProc(w, event, prms, nprms)
5601 void LoadPositionProc(w, event, prms, nprms)
5607 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5610 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5613 void SaveGameProc(w, event, prms, nprms)
5619 FileNamePopUp(_("Save game file name?"),
5620 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5624 void SavePositionProc(w, event, prms, nprms)
5630 FileNamePopUp(_("Save position file name?"),
5631 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5635 void ReloadCmailMsgProc(w, event, prms, nprms)
5641 ReloadCmailMsgEvent(FALSE);
5644 void MailMoveProc(w, event, prms, nprms)
5653 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5654 char *selected_fen_position=NULL;
5657 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5658 Atom *type_return, XtPointer *value_return,
5659 unsigned long *length_return, int *format_return)
5661 char *selection_tmp;
5663 if (!selected_fen_position) return False; /* should never happen */
5664 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5665 /* note: since no XtSelectionDoneProc was registered, Xt will
5666 * automatically call XtFree on the value returned. So have to
5667 * make a copy of it allocated with XtMalloc */
5668 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5669 strcpy(selection_tmp, selected_fen_position);
5671 *value_return=selection_tmp;
5672 *length_return=strlen(selection_tmp);
5673 *type_return=*target;
5674 *format_return = 8; /* bits per byte */
5676 } else if (*target == XA_TARGETS(xDisplay)) {
5677 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5678 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5679 targets_tmp[1] = XA_STRING;
5680 *value_return = targets_tmp;
5681 *type_return = XA_ATOM;
5683 *format_return = 8 * sizeof(Atom);
5684 if (*format_return > 32) {
5685 *length_return *= *format_return / 32;
5686 *format_return = 32;
5694 /* note: when called from menu all parameters are NULL, so no clue what the
5695 * Widget which was clicked on was, or what the click event was
5697 void CopyPositionProc(w, event, prms, nprms)
5704 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5705 * have a notion of a position that is selected but not copied.
5706 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5708 if(gameMode == EditPosition) EditPositionDone(TRUE);
5709 if (selected_fen_position) free(selected_fen_position);
5710 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5711 if (!selected_fen_position) return;
5712 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5714 SendPositionSelection,
5715 NULL/* lose_ownership_proc */ ,
5716 NULL/* transfer_done_proc */);
5717 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5719 SendPositionSelection,
5720 NULL/* lose_ownership_proc */ ,
5721 NULL/* transfer_done_proc */);
5724 /* function called when the data to Paste is ready */
5726 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5727 Atom *type, XtPointer value, unsigned long *len, int *format)
5730 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5731 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5732 EditPositionPasteFEN(fenstr);
5736 /* called when Paste Position button is pressed,
5737 * all parameters will be NULL */
5738 void PastePositionProc(w, event, prms, nprms)
5744 XtGetSelectionValue(menuBarWidget,
5745 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5746 /* (XtSelectionCallbackProc) */ PastePositionCB,
5747 NULL, /* client_data passed to PastePositionCB */
5749 /* better to use the time field from the event that triggered the
5750 * call to this function, but that isn't trivial to get
5758 SendGameSelection(Widget w, Atom *selection, Atom *target,
5759 Atom *type_return, XtPointer *value_return,
5760 unsigned long *length_return, int *format_return)
5762 char *selection_tmp;
5764 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5765 FILE* f = fopen(gameCopyFilename, "r");
5768 if (f == NULL) return False;
5772 selection_tmp = XtMalloc(len + 1);
5773 count = fread(selection_tmp, 1, len, f);
5775 XtFree(selection_tmp);
5778 selection_tmp[len] = NULLCHAR;
5779 *value_return = selection_tmp;
5780 *length_return = len;
5781 *type_return = *target;
5782 *format_return = 8; /* bits per byte */
5784 } else if (*target == XA_TARGETS(xDisplay)) {
5785 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5786 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5787 targets_tmp[1] = XA_STRING;
5788 *value_return = targets_tmp;
5789 *type_return = XA_ATOM;
5791 *format_return = 8 * sizeof(Atom);
5792 if (*format_return > 32) {
5793 *length_return *= *format_return / 32;
5794 *format_return = 32;
5802 /* note: when called from menu all parameters are NULL, so no clue what the
5803 * Widget which was clicked on was, or what the click event was
5805 void CopyGameProc(w, event, prms, nprms)
5813 ret = SaveGameToFile(gameCopyFilename, FALSE);
5817 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5818 * have a notion of a game that is selected but not copied.
5819 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5821 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5824 NULL/* lose_ownership_proc */ ,
5825 NULL/* transfer_done_proc */);
5826 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5829 NULL/* lose_ownership_proc */ ,
5830 NULL/* transfer_done_proc */);
5833 /* function called when the data to Paste is ready */
5835 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5836 Atom *type, XtPointer value, unsigned long *len, int *format)
5839 if (value == NULL || *len == 0) {
5840 return; /* nothing had been selected to copy */
5842 f = fopen(gamePasteFilename, "w");
5844 DisplayError(_("Can't open temp file"), errno);
5847 fwrite(value, 1, *len, f);
5850 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5853 /* called when Paste Game button is pressed,
5854 * all parameters will be NULL */
5855 void PasteGameProc(w, event, prms, nprms)
5861 XtGetSelectionValue(menuBarWidget,
5862 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5863 /* (XtSelectionCallbackProc) */ PasteGameCB,
5864 NULL, /* client_data passed to PasteGameCB */
5866 /* better to use the time field from the event that triggered the
5867 * call to this function, but that isn't trivial to get
5877 SaveGameProc(NULL, NULL, NULL, NULL);
5881 void QuitProc(w, event, prms, nprms)
5890 void PauseProc(w, event, prms, nprms)
5900 void MachineBlackProc(w, event, prms, nprms)
5906 MachineBlackEvent();
5909 void MachineWhiteProc(w, event, prms, nprms)
5915 MachineWhiteEvent();
5918 void AnalyzeModeProc(w, event, prms, nprms)
5926 if (!first.analysisSupport) {
5927 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5928 DisplayError(buf, 0);
5931 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5932 if (appData.icsActive) {
5933 if (gameMode != IcsObserving) {
5934 sprintf(buf,_("You are not observing a game"));
5935 DisplayError(buf, 0);
5937 if (appData.icsEngineAnalyze) {
5938 if (appData.debugMode)
5939 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5945 /* if enable, use want disable icsEngineAnalyze */
5946 if (appData.icsEngineAnalyze) {
5951 appData.icsEngineAnalyze = TRUE;
5952 if (appData.debugMode)
5953 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5955 if (!appData.showThinking)
5956 ShowThinkingProc(w,event,prms,nprms);
5961 void AnalyzeFileProc(w, event, prms, nprms)
5967 if (!first.analysisSupport) {
5969 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5970 DisplayError(buf, 0);
5975 if (!appData.showThinking)
5976 ShowThinkingProc(w,event,prms,nprms);
5979 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5980 AnalysisPeriodicEvent(1);
5983 void TwoMachinesProc(w, event, prms, nprms)
5992 void IcsClientProc(w, event, prms, nprms)
6001 void EditGameProc(w, event, prms, nprms)
6010 void EditPositionProc(w, event, prms, nprms)
6016 EditPositionEvent();
6019 void TrainingProc(w, event, prms, nprms)
6028 void EditCommentProc(w, event, prms, nprms)
6035 EditCommentPopDown();
6041 void IcsInputBoxProc(w, event, prms, nprms)
6047 if (ICSInputBoxUp) {
6048 ICSInputBoxPopDown();
6054 void AcceptProc(w, event, prms, nprms)
6063 void DeclineProc(w, event, prms, nprms)
6072 void RematchProc(w, event, prms, nprms)
6081 void CallFlagProc(w, event, prms, nprms)
6090 void DrawProc(w, event, prms, nprms)
6099 void AbortProc(w, event, prms, nprms)
6108 void AdjournProc(w, event, prms, nprms)
6117 void ResignProc(w, event, prms, nprms)
6126 void AdjuWhiteProc(w, event, prms, nprms)
6132 UserAdjudicationEvent(+1);
6135 void AdjuBlackProc(w, event, prms, nprms)
6141 UserAdjudicationEvent(-1);
6144 void AdjuDrawProc(w, event, prms, nprms)
6150 UserAdjudicationEvent(0);
6153 void EnterKeyProc(w, event, prms, nprms)
6159 if (ICSInputBoxUp == True)
6163 void UpKeyProc(w, event, prms, nprms)
6168 { // [HGM] input: let up-arrow recall previous line from history
6175 if (!ICSInputBoxUp) return;
6176 edit = XtNameToWidget(ICSInputShell, "*form.text");
6178 XtSetArg(args[j], XtNstring, &val); j++;
6179 XtGetValues(edit, args, j);
6180 val = PrevInHistory(val);
6181 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6182 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6184 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6185 XawTextReplace(edit, 0, 0, &t);
6186 XawTextSetInsertionPoint(edit, 9999);
6190 void DownKeyProc(w, event, prms, nprms)
6195 { // [HGM] input: let down-arrow recall next line from history
6200 if (!ICSInputBoxUp) return;
6201 edit = XtNameToWidget(ICSInputShell, "*form.text");
6202 val = NextInHistory();
6203 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6204 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6206 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6207 XawTextReplace(edit, 0, 0, &t);
6208 XawTextSetInsertionPoint(edit, 9999);
6212 void StopObservingProc(w, event, prms, nprms)
6218 StopObservingEvent();
6221 void StopExaminingProc(w, event, prms, nprms)
6227 StopExaminingEvent();
6230 void UploadProc(w, event, prms, nprms)
6240 void ForwardProc(w, event, prms, nprms)
6250 void BackwardProc(w, event, prms, nprms)
6259 void ToStartProc(w, event, prms, nprms)
6268 void ToEndProc(w, event, prms, nprms)
6277 void RevertProc(w, event, prms, nprms)
6286 void AnnotateProc(w, event, prms, nprms)
6295 void TruncateGameProc(w, event, prms, nprms)
6301 TruncateGameEvent();
6303 void RetractMoveProc(w, event, prms, nprms)
6312 void MoveNowProc(w, event, prms, nprms)
6322 void AlwaysQueenProc(w, event, prms, nprms)
6330 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6332 if (appData.alwaysPromoteToQueen) {
6333 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6335 XtSetArg(args[0], XtNleftBitmap, None);
6337 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6341 void AnimateDraggingProc(w, event, prms, nprms)
6349 appData.animateDragging = !appData.animateDragging;
6351 if (appData.animateDragging) {
6352 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6355 XtSetArg(args[0], XtNleftBitmap, None);
6357 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6361 void AnimateMovingProc(w, event, prms, nprms)
6369 appData.animate = !appData.animate;
6371 if (appData.animate) {
6372 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6375 XtSetArg(args[0], XtNleftBitmap, None);
6377 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6381 void AutocommProc(w, event, prms, nprms)
6389 appData.autoComment = !appData.autoComment;
6391 if (appData.autoComment) {
6392 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6394 XtSetArg(args[0], XtNleftBitmap, None);
6396 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6401 void AutoflagProc(w, event, prms, nprms)
6409 appData.autoCallFlag = !appData.autoCallFlag;
6411 if (appData.autoCallFlag) {
6412 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6414 XtSetArg(args[0], XtNleftBitmap, None);
6416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6420 void AutoflipProc(w, event, prms, nprms)
6428 appData.autoFlipView = !appData.autoFlipView;
6430 if (appData.autoFlipView) {
6431 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6433 XtSetArg(args[0], XtNleftBitmap, None);
6435 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6439 void AutobsProc(w, event, prms, nprms)
6447 appData.autoObserve = !appData.autoObserve;
6449 if (appData.autoObserve) {
6450 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6452 XtSetArg(args[0], XtNleftBitmap, None);
6454 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6458 void AutoraiseProc(w, event, prms, nprms)
6466 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6468 if (appData.autoRaiseBoard) {
6469 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6471 XtSetArg(args[0], XtNleftBitmap, None);
6473 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6477 void AutosaveProc(w, event, prms, nprms)
6485 appData.autoSaveGames = !appData.autoSaveGames;
6487 if (appData.autoSaveGames) {
6488 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6490 XtSetArg(args[0], XtNleftBitmap, None);
6492 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6496 void BlindfoldProc(w, event, prms, nprms)
6504 appData.blindfold = !appData.blindfold;
6506 if (appData.blindfold) {
6507 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6509 XtSetArg(args[0], XtNleftBitmap, None);
6511 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6514 DrawPosition(True, NULL);
6517 void TestLegalityProc(w, event, prms, nprms)
6525 appData.testLegality = !appData.testLegality;
6527 if (appData.testLegality) {
6528 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6530 XtSetArg(args[0], XtNleftBitmap, None);
6532 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6537 void FlashMovesProc(w, event, prms, nprms)
6545 if (appData.flashCount == 0) {
6546 appData.flashCount = 3;
6548 appData.flashCount = -appData.flashCount;
6551 if (appData.flashCount > 0) {
6552 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6554 XtSetArg(args[0], XtNleftBitmap, None);
6556 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6560 void FlipViewProc(w, event, prms, nprms)
6566 flipView = !flipView;
6567 DrawPosition(True, NULL);
6570 void GetMoveListProc(w, event, prms, nprms)
6578 appData.getMoveList = !appData.getMoveList;
6580 if (appData.getMoveList) {
6581 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6584 XtSetArg(args[0], XtNleftBitmap, None);
6586 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6591 void HighlightDraggingProc(w, event, prms, nprms)
6599 appData.highlightDragging = !appData.highlightDragging;
6601 if (appData.highlightDragging) {
6602 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6604 XtSetArg(args[0], XtNleftBitmap, None);
6606 XtSetValues(XtNameToWidget(menuBarWidget,
6607 "menuOptions.Highlight Dragging"), args, 1);
6611 void HighlightLastMoveProc(w, event, prms, nprms)
6619 appData.highlightLastMove = !appData.highlightLastMove;
6621 if (appData.highlightLastMove) {
6622 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6624 XtSetArg(args[0], XtNleftBitmap, None);
6626 XtSetValues(XtNameToWidget(menuBarWidget,
6627 "menuOptions.Highlight Last Move"), args, 1);
6630 void IcsAlarmProc(w, event, prms, nprms)
6638 appData.icsAlarm = !appData.icsAlarm;
6640 if (appData.icsAlarm) {
6641 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6643 XtSetArg(args[0], XtNleftBitmap, None);
6645 XtSetValues(XtNameToWidget(menuBarWidget,
6646 "menuOptions.ICS Alarm"), args, 1);
6649 void MoveSoundProc(w, event, prms, nprms)
6657 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6659 if (appData.ringBellAfterMoves) {
6660 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6662 XtSetArg(args[0], XtNleftBitmap, None);
6664 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6669 void OldSaveStyleProc(w, event, prms, nprms)
6677 appData.oldSaveStyle = !appData.oldSaveStyle;
6679 if (appData.oldSaveStyle) {
6680 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6682 XtSetArg(args[0], XtNleftBitmap, None);
6684 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6688 void PeriodicUpdatesProc(w, event, prms, nprms)
6696 PeriodicUpdatesEvent(!appData.periodicUpdates);
6698 if (appData.periodicUpdates) {
6699 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6701 XtSetArg(args[0], XtNleftBitmap, None);
6703 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6707 void PonderNextMoveProc(w, event, prms, nprms)
6715 PonderNextMoveEvent(!appData.ponderNextMove);
6717 if (appData.ponderNextMove) {
6718 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6720 XtSetArg(args[0], XtNleftBitmap, None);
6722 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6726 void PopupExitMessageProc(w, event, prms, nprms)
6734 appData.popupExitMessage = !appData.popupExitMessage;
6736 if (appData.popupExitMessage) {
6737 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6739 XtSetArg(args[0], XtNleftBitmap, None);
6741 XtSetValues(XtNameToWidget(menuBarWidget,
6742 "menuOptions.Popup Exit Message"), args, 1);
6745 void PopupMoveErrorsProc(w, event, prms, nprms)
6753 appData.popupMoveErrors = !appData.popupMoveErrors;
6755 if (appData.popupMoveErrors) {
6756 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6758 XtSetArg(args[0], XtNleftBitmap, None);
6760 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6764 void PremoveProc(w, event, prms, nprms)
6772 appData.premove = !appData.premove;
6774 if (appData.premove) {
6775 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6777 XtSetArg(args[0], XtNleftBitmap, None);
6779 XtSetValues(XtNameToWidget(menuBarWidget,
6780 "menuOptions.Premove"), args, 1);
6783 void QuietPlayProc(w, event, prms, nprms)
6791 appData.quietPlay = !appData.quietPlay;
6793 if (appData.quietPlay) {
6794 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6796 XtSetArg(args[0], XtNleftBitmap, None);
6798 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6802 void ShowCoordsProc(w, event, prms, nprms)
6810 appData.showCoords = !appData.showCoords;
6812 if (appData.showCoords) {
6813 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6815 XtSetArg(args[0], XtNleftBitmap, None);
6817 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6820 DrawPosition(True, NULL);
6823 void ShowThinkingProc(w, event, prms, nprms)
6829 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6830 ShowThinkingEvent();
6833 void HideThinkingProc(w, event, prms, nprms)
6841 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6842 ShowThinkingEvent();
6844 if (appData.hideThinkingFromHuman) {
6845 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6847 XtSetArg(args[0], XtNleftBitmap, None);
6849 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6853 void SaveOnExitProc(w, event, prms, nprms)
6861 saveSettingsOnExit = !saveSettingsOnExit;
6863 if (saveSettingsOnExit) {
6864 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6866 XtSetArg(args[0], XtNleftBitmap, None);
6868 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6872 void SaveSettingsProc(w, event, prms, nprms)
6878 SaveSettings(settingsFileName);
6881 void InfoProc(w, event, prms, nprms)
6888 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6893 void ManProc(w, event, prms, nprms)
6901 if (nprms && *nprms > 0)
6905 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6909 void HintProc(w, event, prms, nprms)
6918 void BookProc(w, event, prms, nprms)
6927 void AboutProc(w, event, prms, nprms)
6935 char *zippy = " (with Zippy code)";
6939 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6940 programVersion, zippy,
6941 "Copyright 1991 Digital Equipment Corporation",
6942 "Enhancements Copyright 1992-2009 Free Software Foundation",
6943 "Enhancements Copyright 2005 Alessandro Scotti",
6944 PACKAGE, " is free software and carries NO WARRANTY;",
6945 "see the file COPYING for more information.");
6946 ErrorPopUp(_("About XBoard"), buf, FALSE);
6949 void DebugProc(w, event, prms, nprms)
6955 appData.debugMode = !appData.debugMode;
6958 void AboutGameProc(w, event, prms, nprms)
6967 void NothingProc(w, event, prms, nprms)
6976 void Iconify(w, event, prms, nprms)
6985 XtSetArg(args[0], XtNiconic, True);
6986 XtSetValues(shellWidget, args, 1);
6989 void DisplayMessage(message, extMessage)
6990 char *message, *extMessage;
6992 /* display a message in the message widget */
7001 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7006 message = extMessage;
7010 /* need to test if messageWidget already exists, since this function
7011 can also be called during the startup, if for example a Xresource
7012 is not set up correctly */
7015 XtSetArg(arg, XtNlabel, message);
7016 XtSetValues(messageWidget, &arg, 1);
7022 void DisplayTitle(text)
7027 char title[MSG_SIZ];
7030 if (text == NULL) text = "";
7032 if (appData.titleInWindow) {
7034 XtSetArg(args[i], XtNlabel, text); i++;
7035 XtSetValues(titleWidget, args, i);
7038 if (*text != NULLCHAR) {
7040 strcpy(title, text);
7041 } else if (appData.icsActive) {
7042 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7043 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7044 } else if (appData.cmailGameName[0] != NULLCHAR) {
7045 snprintf(icon, sizeof(icon), "%s", "CMail");
7046 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7048 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7049 } else if (gameInfo.variant == VariantGothic) {
7050 strcpy(icon, programName);
7051 strcpy(title, GOTHIC);
7054 } else if (gameInfo.variant == VariantFalcon) {
7055 strcpy(icon, programName);
7056 strcpy(title, FALCON);
7058 } else if (appData.noChessProgram) {
7059 strcpy(icon, programName);
7060 strcpy(title, programName);
7062 strcpy(icon, first.tidy);
7063 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7066 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7067 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7068 XtSetValues(shellWidget, args, i);
7072 void DisplayError(message, error)
7079 if (appData.debugMode || appData.matchMode) {
7080 fprintf(stderr, "%s: %s\n", programName, message);
7083 if (appData.debugMode || appData.matchMode) {
7084 fprintf(stderr, "%s: %s: %s\n",
7085 programName, message, strerror(error));
7087 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7090 ErrorPopUp(_("Error"), message, FALSE);
7094 void DisplayMoveError(message)
7099 DrawPosition(FALSE, NULL);
7100 if (appData.debugMode || appData.matchMode) {
7101 fprintf(stderr, "%s: %s\n", programName, message);
7103 if (appData.popupMoveErrors) {
7104 ErrorPopUp(_("Error"), message, FALSE);
7106 DisplayMessage(message, "");
7111 void DisplayFatalError(message, error, status)
7117 errorExitStatus = status;
7119 fprintf(stderr, "%s: %s\n", programName, message);
7121 fprintf(stderr, "%s: %s: %s\n",
7122 programName, message, strerror(error));
7123 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7126 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7127 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7133 void DisplayInformation(message)
7137 ErrorPopUp(_("Information"), message, TRUE);
7140 void DisplayNote(message)
7144 ErrorPopUp(_("Note"), message, FALSE);
7148 NullXErrorCheck(dpy, error_event)
7150 XErrorEvent *error_event;
7155 void DisplayIcsInteractionTitle(message)
7158 if (oldICSInteractionTitle == NULL) {
7159 /* Magic to find the old window title, adapted from vim */
7160 char *wina = getenv("WINDOWID");
7162 Window win = (Window) atoi(wina);
7163 Window root, parent, *children;
7164 unsigned int nchildren;
7165 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7167 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7168 if (!XQueryTree(xDisplay, win, &root, &parent,
7169 &children, &nchildren)) break;
7170 if (children) XFree((void *)children);
7171 if (parent == root || parent == 0) break;
7174 XSetErrorHandler(oldHandler);
7176 if (oldICSInteractionTitle == NULL) {
7177 oldICSInteractionTitle = "xterm";
7180 printf("\033]0;%s\007", message);
7184 char pendingReplyPrefix[MSG_SIZ];
7185 ProcRef pendingReplyPR;
7187 void AskQuestionProc(w, event, prms, nprms)
7194 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7198 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7201 void AskQuestionPopDown()
7203 if (!askQuestionUp) return;
7204 XtPopdown(askQuestionShell);
7205 XtDestroyWidget(askQuestionShell);
7206 askQuestionUp = False;
7209 void AskQuestionReplyAction(w, event, prms, nprms)
7219 reply = XawDialogGetValueString(w = XtParent(w));
7220 strcpy(buf, pendingReplyPrefix);
7221 if (*buf) strcat(buf, " ");
7224 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7225 AskQuestionPopDown();
7227 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7230 void AskQuestionCallback(w, client_data, call_data)
7232 XtPointer client_data, call_data;
7237 XtSetArg(args[0], XtNlabel, &name);
7238 XtGetValues(w, args, 1);
7240 if (strcmp(name, _("cancel")) == 0) {
7241 AskQuestionPopDown();
7243 AskQuestionReplyAction(w, NULL, NULL, NULL);
7247 void AskQuestion(title, question, replyPrefix, pr)
7248 char *title, *question, *replyPrefix;
7252 Widget popup, layout, dialog, edit;
7258 strcpy(pendingReplyPrefix, replyPrefix);
7259 pendingReplyPR = pr;
7262 XtSetArg(args[i], XtNresizable, True); i++;
7263 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7264 askQuestionShell = popup =
7265 XtCreatePopupShell(title, transientShellWidgetClass,
7266 shellWidget, args, i);
7269 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7270 layoutArgs, XtNumber(layoutArgs));
7273 XtSetArg(args[i], XtNlabel, question); i++;
7274 XtSetArg(args[i], XtNvalue, ""); i++;
7275 XtSetArg(args[i], XtNborderWidth, 0); i++;
7276 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7279 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7280 (XtPointer) dialog);
7281 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7282 (XtPointer) dialog);
7284 XtRealizeWidget(popup);
7285 CatchDeleteWindow(popup, "AskQuestionPopDown");
7287 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7288 &x, &y, &win_x, &win_y, &mask);
7290 XtSetArg(args[0], XtNx, x - 10);
7291 XtSetArg(args[1], XtNy, y - 30);
7292 XtSetValues(popup, args, 2);
7294 XtPopup(popup, XtGrabExclusive);
7295 askQuestionUp = True;
7297 edit = XtNameToWidget(dialog, "*value");
7298 XtSetKeyboardFocus(popup, edit);
7306 if (*name == NULLCHAR) {
7308 } else if (strcmp(name, "$") == 0) {
7309 putc(BELLCHAR, stderr);
7312 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7320 PlaySound(appData.soundMove);
7326 PlaySound(appData.soundIcsWin);
7332 PlaySound(appData.soundIcsLoss);
7338 PlaySound(appData.soundIcsDraw);
7342 PlayIcsUnfinishedSound()
7344 PlaySound(appData.soundIcsUnfinished);
7350 PlaySound(appData.soundIcsAlarm);
7356 system("stty echo");
7362 system("stty -echo");
7366 Colorize(cc, continuation)
7371 int count, outCount, error;
7373 if (textColors[(int)cc].bg > 0) {
7374 if (textColors[(int)cc].fg > 0) {
7375 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7376 textColors[(int)cc].fg, textColors[(int)cc].bg);
7378 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7379 textColors[(int)cc].bg);
7382 if (textColors[(int)cc].fg > 0) {
7383 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7384 textColors[(int)cc].fg);
7386 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7389 count = strlen(buf);
7390 outCount = OutputToProcess(NoProc, buf, count, &error);
7391 if (outCount < count) {
7392 DisplayFatalError(_("Error writing to display"), error, 1);
7395 if (continuation) return;
7398 PlaySound(appData.soundShout);
7401 PlaySound(appData.soundSShout);
7404 PlaySound(appData.soundChannel1);
7407 PlaySound(appData.soundChannel);
7410 PlaySound(appData.soundKibitz);
7413 PlaySound(appData.soundTell);
7415 case ColorChallenge:
7416 PlaySound(appData.soundChallenge);
7419 PlaySound(appData.soundRequest);
7422 PlaySound(appData.soundSeek);
7433 return getpwuid(getuid())->pw_name;
7436 static char *ExpandPathName(path)
7439 static char static_buf[2000];
7440 char *d, *s, buf[2000];
7446 while (*s && isspace(*s))
7455 if (*(s+1) == '/') {
7456 strcpy(d, getpwuid(getuid())->pw_dir);
7461 *strchr(buf, '/') = 0;
7462 pwd = getpwnam(buf);
7465 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7469 strcpy(d, pwd->pw_dir);
7470 strcat(d, strchr(s+1, '/'));
7481 static char host_name[MSG_SIZ];
7483 #if HAVE_GETHOSTNAME
7484 gethostname(host_name, MSG_SIZ);
7486 #else /* not HAVE_GETHOSTNAME */
7487 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7488 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7490 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7492 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7493 #endif /* not HAVE_GETHOSTNAME */
7496 XtIntervalId delayedEventTimerXID = 0;
7497 DelayedEventCallback delayedEventCallback = 0;
7502 delayedEventTimerXID = 0;
7503 delayedEventCallback();
7507 ScheduleDelayedEvent(cb, millisec)
7508 DelayedEventCallback cb; long millisec;
7510 if(delayedEventTimerXID && delayedEventCallback == cb)
7511 // [HGM] alive: replace, rather than add or flush identical event
7512 XtRemoveTimeOut(delayedEventTimerXID);
7513 delayedEventCallback = cb;
7514 delayedEventTimerXID =
7515 XtAppAddTimeOut(appContext, millisec,
7516 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7519 DelayedEventCallback
7522 if (delayedEventTimerXID) {
7523 return delayedEventCallback;
7530 CancelDelayedEvent()
7532 if (delayedEventTimerXID) {
7533 XtRemoveTimeOut(delayedEventTimerXID);
7534 delayedEventTimerXID = 0;
7538 XtIntervalId loadGameTimerXID = 0;
7540 int LoadGameTimerRunning()
7542 return loadGameTimerXID != 0;
7545 int StopLoadGameTimer()
7547 if (loadGameTimerXID != 0) {
7548 XtRemoveTimeOut(loadGameTimerXID);
7549 loadGameTimerXID = 0;
7557 LoadGameTimerCallback(arg, id)
7561 loadGameTimerXID = 0;
7566 StartLoadGameTimer(millisec)
7570 XtAppAddTimeOut(appContext, millisec,
7571 (XtTimerCallbackProc) LoadGameTimerCallback,
7575 XtIntervalId analysisClockXID = 0;
7578 AnalysisClockCallback(arg, id)
7582 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7583 || appData.icsEngineAnalyze) { // [DM]
7584 AnalysisPeriodicEvent(0);
7585 StartAnalysisClock();
7590 StartAnalysisClock()
7593 XtAppAddTimeOut(appContext, 2000,
7594 (XtTimerCallbackProc) AnalysisClockCallback,
7598 XtIntervalId clockTimerXID = 0;
7600 int ClockTimerRunning()
7602 return clockTimerXID != 0;
7605 int StopClockTimer()
7607 if (clockTimerXID != 0) {
7608 XtRemoveTimeOut(clockTimerXID);
7617 ClockTimerCallback(arg, id)
7626 StartClockTimer(millisec)
7630 XtAppAddTimeOut(appContext, millisec,
7631 (XtTimerCallbackProc) ClockTimerCallback,
7636 DisplayTimerLabel(w, color, timer, highlight)
7645 /* check for low time warning */
7646 Pixel foregroundOrWarningColor = timerForegroundPixel;
7649 appData.lowTimeWarning &&
7650 (timer / 1000) < appData.icsAlarmTime)
7651 foregroundOrWarningColor = lowTimeWarningColor;
7653 if (appData.clockMode) {
7654 sprintf(buf, "%s: %s", color, TimeString(timer));
7655 XtSetArg(args[0], XtNlabel, buf);
7657 sprintf(buf, "%s ", color);
7658 XtSetArg(args[0], XtNlabel, buf);
7663 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7664 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7666 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7667 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7670 XtSetValues(w, args, 3);
7674 DisplayWhiteClock(timeRemaining, highlight)
7680 if(appData.noGUI) return;
7681 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7682 if (highlight && iconPixmap == bIconPixmap) {
7683 iconPixmap = wIconPixmap;
7684 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7685 XtSetValues(shellWidget, args, 1);
7690 DisplayBlackClock(timeRemaining, highlight)
7696 if(appData.noGUI) return;
7697 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7698 if (highlight && iconPixmap == wIconPixmap) {
7699 iconPixmap = bIconPixmap;
7700 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7701 XtSetValues(shellWidget, args, 1);
7719 int StartChildProcess(cmdLine, dir, pr)
7726 int to_prog[2], from_prog[2];
7730 if (appData.debugMode) {
7731 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7734 /* We do NOT feed the cmdLine to the shell; we just
7735 parse it into blank-separated arguments in the
7736 most simple-minded way possible.
7739 strcpy(buf, cmdLine);
7742 while(*p == ' ') p++;
7744 if(*p == '"' || *p == '\'')
7745 p = strchr(++argv[i-1], *p);
7746 else p = strchr(p, ' ');
7747 if (p == NULL) break;
7752 SetUpChildIO(to_prog, from_prog);
7754 if ((pid = fork()) == 0) {
7756 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7757 close(to_prog[1]); // first close the unused pipe ends
7758 close(from_prog[0]);
7759 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7760 dup2(from_prog[1], 1);
7761 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7762 close(from_prog[1]); // and closing again loses one of the pipes!
7763 if(fileno(stderr) >= 2) // better safe than sorry...
7764 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7766 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7771 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7773 execvp(argv[0], argv);
7775 /* If we get here, exec failed */
7780 /* Parent process */
7782 close(from_prog[1]);
7784 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7787 cp->fdFrom = from_prog[0];
7788 cp->fdTo = to_prog[1];
7793 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7794 static RETSIGTYPE AlarmCallBack(int n)
7800 DestroyChildProcess(pr, signalType)
7804 ChildProc *cp = (ChildProc *) pr;
7806 if (cp->kind != CPReal) return;
7808 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7809 signal(SIGALRM, AlarmCallBack);
7811 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7812 kill(cp->pid, SIGKILL); // kill it forcefully
7813 wait((int *) 0); // and wait again
7817 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7819 /* Process is exiting either because of the kill or because of
7820 a quit command sent by the backend; either way, wait for it to die.
7829 InterruptChildProcess(pr)
7832 ChildProc *cp = (ChildProc *) pr;
7834 if (cp->kind != CPReal) return;
7835 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7838 int OpenTelnet(host, port, pr)
7843 char cmdLine[MSG_SIZ];
7845 if (port[0] == NULLCHAR) {
7846 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7848 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7850 return StartChildProcess(cmdLine, "", pr);
7853 int OpenTCP(host, port, pr)
7859 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7860 #else /* !OMIT_SOCKETS */
7862 struct sockaddr_in sa;
7864 unsigned short uport;
7867 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7871 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7872 sa.sin_family = AF_INET;
7873 sa.sin_addr.s_addr = INADDR_ANY;
7874 uport = (unsigned short) 0;
7875 sa.sin_port = htons(uport);
7876 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7880 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7881 if (!(hp = gethostbyname(host))) {
7883 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7884 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7885 hp->h_addrtype = AF_INET;
7887 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7888 hp->h_addr_list[0] = (char *) malloc(4);
7889 hp->h_addr_list[0][0] = b0;
7890 hp->h_addr_list[0][1] = b1;
7891 hp->h_addr_list[0][2] = b2;
7892 hp->h_addr_list[0][3] = b3;
7897 sa.sin_family = hp->h_addrtype;
7898 uport = (unsigned short) atoi(port);
7899 sa.sin_port = htons(uport);
7900 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7902 if (connect(s, (struct sockaddr *) &sa,
7903 sizeof(struct sockaddr_in)) < 0) {
7907 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7914 #endif /* !OMIT_SOCKETS */
7919 int OpenCommPort(name, pr)
7926 fd = open(name, 2, 0);
7927 if (fd < 0) return errno;
7929 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7939 int OpenLoopback(pr)
7945 SetUpChildIO(to, from);
7947 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7950 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7957 int OpenRcmd(host, user, cmd, pr)
7958 char *host, *user, *cmd;
7961 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7965 #define INPUT_SOURCE_BUF_SIZE 8192
7974 char buf[INPUT_SOURCE_BUF_SIZE];
7979 DoInputCallback(closure, source, xid)
7984 InputSource *is = (InputSource *) closure;
7989 if (is->lineByLine) {
7990 count = read(is->fd, is->unused,
7991 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7993 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7996 is->unused += count;
7998 while (p < is->unused) {
7999 q = memchr(p, '\n', is->unused - p);
8000 if (q == NULL) break;
8002 (is->func)(is, is->closure, p, q - p, 0);
8006 while (p < is->unused) {
8011 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8016 (is->func)(is, is->closure, is->buf, count, error);
8020 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8027 ChildProc *cp = (ChildProc *) pr;
8029 is = (InputSource *) calloc(1, sizeof(InputSource));
8030 is->lineByLine = lineByLine;
8034 is->fd = fileno(stdin);
8036 is->kind = cp->kind;
8037 is->fd = cp->fdFrom;
8040 is->unused = is->buf;
8043 is->xid = XtAppAddInput(appContext, is->fd,
8044 (XtPointer) (XtInputReadMask),
8045 (XtInputCallbackProc) DoInputCallback,
8047 is->closure = closure;
8048 return (InputSourceRef) is;
8052 RemoveInputSource(isr)
8055 InputSource *is = (InputSource *) isr;
8057 if (is->xid == 0) return;
8058 XtRemoveInput(is->xid);
8062 int OutputToProcess(pr, message, count, outError)
8068 static int line = 0;
8069 ChildProc *cp = (ChildProc *) pr;
8074 if (appData.noJoin || !appData.useInternalWrap)
8075 outCount = fwrite(message, 1, count, stdout);
8078 int width = get_term_width();
8079 int len = wrap(NULL, message, count, width, &line);
8080 char *msg = malloc(len);
8084 outCount = fwrite(message, 1, count, stdout);
8087 dbgchk = wrap(msg, message, count, width, &line);
8088 if (dbgchk != len && appData.debugMode)
8089 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8090 outCount = fwrite(msg, 1, dbgchk, stdout);
8096 outCount = write(cp->fdTo, message, count);
8106 /* Output message to process, with "ms" milliseconds of delay
8107 between each character. This is needed when sending the logon
8108 script to ICC, which for some reason doesn't like the
8109 instantaneous send. */
8110 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8117 ChildProc *cp = (ChildProc *) pr;
8122 r = write(cp->fdTo, message++, 1);
8135 /**** Animation code by Hugh Fisher, DCS, ANU.
8137 Known problem: if a window overlapping the board is
8138 moved away while a piece is being animated underneath,
8139 the newly exposed area won't be updated properly.
8140 I can live with this.
8142 Known problem: if you look carefully at the animation
8143 of pieces in mono mode, they are being drawn as solid
8144 shapes without interior detail while moving. Fixing
8145 this would be a major complication for minimal return.
8148 /* Masks for XPM pieces. Black and white pieces can have
8149 different shapes, but in the interest of retaining my
8150 sanity pieces must have the same outline on both light
8151 and dark squares, and all pieces must use the same
8152 background square colors/images. */
8154 static int xpmDone = 0;
8157 CreateAnimMasks (pieceDepth)
8164 unsigned long plane;
8167 /* Need a bitmap just to get a GC with right depth */
8168 buf = XCreatePixmap(xDisplay, xBoardWindow,
8170 values.foreground = 1;
8171 values.background = 0;
8172 /* Don't use XtGetGC, not read only */
8173 maskGC = XCreateGC(xDisplay, buf,
8174 GCForeground | GCBackground, &values);
8175 XFreePixmap(xDisplay, buf);
8177 buf = XCreatePixmap(xDisplay, xBoardWindow,
8178 squareSize, squareSize, pieceDepth);
8179 values.foreground = XBlackPixel(xDisplay, xScreen);
8180 values.background = XWhitePixel(xDisplay, xScreen);
8181 bufGC = XCreateGC(xDisplay, buf,
8182 GCForeground | GCBackground, &values);
8184 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8185 /* Begin with empty mask */
8186 if(!xpmDone) // [HGM] pieces: keep using existing
8187 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8188 squareSize, squareSize, 1);
8189 XSetFunction(xDisplay, maskGC, GXclear);
8190 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8191 0, 0, squareSize, squareSize);
8193 /* Take a copy of the piece */
8198 XSetFunction(xDisplay, bufGC, GXcopy);
8199 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8201 0, 0, squareSize, squareSize, 0, 0);
8203 /* XOR the background (light) over the piece */
8204 XSetFunction(xDisplay, bufGC, GXxor);
8206 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8207 0, 0, squareSize, squareSize, 0, 0);
8209 XSetForeground(xDisplay, bufGC, lightSquareColor);
8210 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8213 /* We now have an inverted piece image with the background
8214 erased. Construct mask by just selecting all the non-zero
8215 pixels - no need to reconstruct the original image. */
8216 XSetFunction(xDisplay, maskGC, GXor);
8218 /* Might be quicker to download an XImage and create bitmap
8219 data from it rather than this N copies per piece, but it
8220 only takes a fraction of a second and there is a much
8221 longer delay for loading the pieces. */
8222 for (n = 0; n < pieceDepth; n ++) {
8223 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8224 0, 0, squareSize, squareSize,
8230 XFreePixmap(xDisplay, buf);
8231 XFreeGC(xDisplay, bufGC);
8232 XFreeGC(xDisplay, maskGC);
8236 InitAnimState (anim, info)
8238 XWindowAttributes * info;
8243 /* Each buffer is square size, same depth as window */
8244 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8245 squareSize, squareSize, info->depth);
8246 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8247 squareSize, squareSize, info->depth);
8249 /* Create a plain GC for blitting */
8250 mask = GCForeground | GCBackground | GCFunction |
8251 GCPlaneMask | GCGraphicsExposures;
8252 values.foreground = XBlackPixel(xDisplay, xScreen);
8253 values.background = XWhitePixel(xDisplay, xScreen);
8254 values.function = GXcopy;
8255 values.plane_mask = AllPlanes;
8256 values.graphics_exposures = False;
8257 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8259 /* Piece will be copied from an existing context at
8260 the start of each new animation/drag. */
8261 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8263 /* Outline will be a read-only copy of an existing */
8264 anim->outlineGC = None;
8270 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8271 XWindowAttributes info;
8273 if (xpmDone && gameInfo.variant == old) return;
8274 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8275 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8277 InitAnimState(&game, &info);
8278 InitAnimState(&player, &info);
8280 /* For XPM pieces, we need bitmaps to use as masks. */
8282 CreateAnimMasks(info.depth);
8288 static Boolean frameWaiting;
8290 static RETSIGTYPE FrameAlarm (sig)
8293 frameWaiting = False;
8294 /* In case System-V style signals. Needed?? */
8295 signal(SIGALRM, FrameAlarm);
8302 struct itimerval delay;
8304 XSync(xDisplay, False);
8307 frameWaiting = True;
8308 signal(SIGALRM, FrameAlarm);
8309 delay.it_interval.tv_sec =
8310 delay.it_value.tv_sec = time / 1000;
8311 delay.it_interval.tv_usec =
8312 delay.it_value.tv_usec = (time % 1000) * 1000;
8313 setitimer(ITIMER_REAL, &delay, NULL);
8314 while (frameWaiting) pause();
8315 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8316 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8317 setitimer(ITIMER_REAL, &delay, NULL);
8327 XSync(xDisplay, False);
8329 usleep(time * 1000);
8334 /* Convert board position to corner of screen rect and color */
8337 ScreenSquare(column, row, pt, color)
8338 int column; int row; XPoint * pt; int * color;
8341 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8342 pt->y = lineGap + row * (squareSize + lineGap);
8344 pt->x = lineGap + column * (squareSize + lineGap);
8345 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8347 *color = SquareColor(row, column);
8350 /* Convert window coords to square */
8353 BoardSquare(x, y, column, row)
8354 int x; int y; int * column; int * row;
8356 *column = EventToSquare(x, BOARD_WIDTH);
8357 if (flipView && *column >= 0)
8358 *column = BOARD_WIDTH - 1 - *column;
8359 *row = EventToSquare(y, BOARD_HEIGHT);
8360 if (!flipView && *row >= 0)
8361 *row = BOARD_HEIGHT - 1 - *row;
8366 #undef Max /* just in case */
8368 #define Max(a, b) ((a) > (b) ? (a) : (b))
8369 #define Min(a, b) ((a) < (b) ? (a) : (b))
8372 SetRect(rect, x, y, width, height)
8373 XRectangle * rect; int x; int y; int width; int height;
8377 rect->width = width;
8378 rect->height = height;
8381 /* Test if two frames overlap. If they do, return
8382 intersection rect within old and location of
8383 that rect within new. */
8386 Intersect(old, new, size, area, pt)
8387 XPoint * old; XPoint * new;
8388 int size; XRectangle * area; XPoint * pt;
8390 if (old->x > new->x + size || new->x > old->x + size ||
8391 old->y > new->y + size || new->y > old->y + size) {
8394 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8395 size - abs(old->x - new->x), size - abs(old->y - new->y));
8396 pt->x = Max(old->x - new->x, 0);
8397 pt->y = Max(old->y - new->y, 0);
8402 /* For two overlapping frames, return the rect(s)
8403 in the old that do not intersect with the new. */
8406 CalcUpdateRects(old, new, size, update, nUpdates)
8407 XPoint * old; XPoint * new; int size;
8408 XRectangle update[]; int * nUpdates;
8412 /* If old = new (shouldn't happen) then nothing to draw */
8413 if (old->x == new->x && old->y == new->y) {
8417 /* Work out what bits overlap. Since we know the rects
8418 are the same size we don't need a full intersect calc. */
8420 /* Top or bottom edge? */
8421 if (new->y > old->y) {
8422 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8424 } else if (old->y > new->y) {
8425 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8426 size, old->y - new->y);
8429 /* Left or right edge - don't overlap any update calculated above. */
8430 if (new->x > old->x) {
8431 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8432 new->x - old->x, size - abs(new->y - old->y));
8434 } else if (old->x > new->x) {
8435 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8436 old->x - new->x, size - abs(new->y - old->y));
8443 /* Generate a series of frame coords from start->mid->finish.
8444 The movement rate doubles until the half way point is
8445 reached, then halves back down to the final destination,
8446 which gives a nice slow in/out effect. The algorithmn
8447 may seem to generate too many intermediates for short
8448 moves, but remember that the purpose is to attract the
8449 viewers attention to the piece about to be moved and
8450 then to where it ends up. Too few frames would be less
8454 Tween(start, mid, finish, factor, frames, nFrames)
8455 XPoint * start; XPoint * mid;
8456 XPoint * finish; int factor;
8457 XPoint frames[]; int * nFrames;
8459 int fraction, n, count;
8463 /* Slow in, stepping 1/16th, then 1/8th, ... */
8465 for (n = 0; n < factor; n++)
8467 for (n = 0; n < factor; n++) {
8468 frames[count].x = start->x + (mid->x - start->x) / fraction;
8469 frames[count].y = start->y + (mid->y - start->y) / fraction;
8471 fraction = fraction / 2;
8475 frames[count] = *mid;
8478 /* Slow out, stepping 1/2, then 1/4, ... */
8480 for (n = 0; n < factor; n++) {
8481 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8482 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8484 fraction = fraction * 2;
8489 /* Draw a piece on the screen without disturbing what's there */
8492 SelectGCMask(piece, clip, outline, mask)
8493 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8497 /* Bitmap for piece being moved. */
8498 if (appData.monoMode) {
8499 *mask = *pieceToSolid(piece);
8500 } else if (useImages) {
8502 *mask = xpmMask[piece];
8504 *mask = ximMaskPm[piece];
8507 *mask = *pieceToSolid(piece);
8510 /* GC for piece being moved. Square color doesn't matter, but
8511 since it gets modified we make a copy of the original. */
8513 if (appData.monoMode)
8518 if (appData.monoMode)
8523 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8525 /* Outline only used in mono mode and is not modified */
8527 *outline = bwPieceGC;
8529 *outline = wbPieceGC;
8533 OverlayPiece(piece, clip, outline, dest)
8534 ChessSquare piece; GC clip; GC outline; Drawable dest;
8539 /* Draw solid rectangle which will be clipped to shape of piece */
8540 XFillRectangle(xDisplay, dest, clip,
8541 0, 0, squareSize, squareSize);
8542 if (appData.monoMode)
8543 /* Also draw outline in contrasting color for black
8544 on black / white on white cases */
8545 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8546 0, 0, squareSize, squareSize, 0, 0, 1);
8548 /* Copy the piece */
8553 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8555 0, 0, squareSize, squareSize,
8560 /* Animate the movement of a single piece */
8563 BeginAnimation(anim, piece, startColor, start)
8571 /* The old buffer is initialised with the start square (empty) */
8572 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8573 anim->prevFrame = *start;
8575 /* The piece will be drawn using its own bitmap as a matte */
8576 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8577 XSetClipMask(xDisplay, anim->pieceGC, mask);
8581 AnimationFrame(anim, frame, piece)
8586 XRectangle updates[4];
8591 /* Save what we are about to draw into the new buffer */
8592 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8593 frame->x, frame->y, squareSize, squareSize,
8596 /* Erase bits of the previous frame */
8597 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8598 /* Where the new frame overlapped the previous,
8599 the contents in newBuf are wrong. */
8600 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8601 overlap.x, overlap.y,
8602 overlap.width, overlap.height,
8604 /* Repaint the areas in the old that don't overlap new */
8605 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8606 for (i = 0; i < count; i++)
8607 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8608 updates[i].x - anim->prevFrame.x,
8609 updates[i].y - anim->prevFrame.y,
8610 updates[i].width, updates[i].height,
8611 updates[i].x, updates[i].y);
8613 /* Easy when no overlap */
8614 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8615 0, 0, squareSize, squareSize,
8616 anim->prevFrame.x, anim->prevFrame.y);
8619 /* Save this frame for next time round */
8620 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8621 0, 0, squareSize, squareSize,
8623 anim->prevFrame = *frame;
8625 /* Draw piece over original screen contents, not current,
8626 and copy entire rect. Wipes out overlapping piece images. */
8627 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8628 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8629 0, 0, squareSize, squareSize,
8630 frame->x, frame->y);
8634 EndAnimation (anim, finish)
8638 XRectangle updates[4];
8643 /* The main code will redraw the final square, so we
8644 only need to erase the bits that don't overlap. */
8645 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8646 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8647 for (i = 0; i < count; i++)
8648 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8649 updates[i].x - anim->prevFrame.x,
8650 updates[i].y - anim->prevFrame.y,
8651 updates[i].width, updates[i].height,
8652 updates[i].x, updates[i].y);
8654 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8655 0, 0, squareSize, squareSize,
8656 anim->prevFrame.x, anim->prevFrame.y);
8661 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8663 ChessSquare piece; int startColor;
8664 XPoint * start; XPoint * finish;
8665 XPoint frames[]; int nFrames;
8669 BeginAnimation(anim, piece, startColor, start);
8670 for (n = 0; n < nFrames; n++) {
8671 AnimationFrame(anim, &(frames[n]), piece);
8672 FrameDelay(appData.animSpeed);
8674 EndAnimation(anim, finish);
8677 /* Main control logic for deciding what to animate and how */
8680 AnimateMove(board, fromX, fromY, toX, toY)
8689 XPoint start, finish, mid;
8690 XPoint frames[kFactor * 2 + 1];
8691 int nFrames, startColor, endColor;
8693 /* Are we animating? */
8694 if (!appData.animate || appData.blindfold)
8697 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8698 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8699 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8701 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8702 piece = board[fromY][fromX];
8703 if (piece >= EmptySquare) return;
8708 hop = (piece == WhiteKnight || piece == BlackKnight);
8711 if (appData.debugMode) {
8712 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8713 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8714 piece, fromX, fromY, toX, toY); }
8716 ScreenSquare(fromX, fromY, &start, &startColor);
8717 ScreenSquare(toX, toY, &finish, &endColor);
8720 /* Knight: make diagonal movement then straight */
8721 if (abs(toY - fromY) < abs(toX - fromX)) {
8722 mid.x = start.x + (finish.x - start.x) / 2;
8726 mid.y = start.y + (finish.y - start.y) / 2;
8729 mid.x = start.x + (finish.x - start.x) / 2;
8730 mid.y = start.y + (finish.y - start.y) / 2;
8733 /* Don't use as many frames for very short moves */
8734 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8735 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8737 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8738 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8740 /* Be sure end square is redrawn */
8741 damage[0][toY][toX] = True;
8745 DragPieceBegin(x, y)
8748 int boardX, boardY, color;
8751 /* Are we animating? */
8752 if (!appData.animateDragging || appData.blindfold)
8755 /* Figure out which square we start in and the
8756 mouse position relative to top left corner. */
8757 BoardSquare(x, y, &boardX, &boardY);
8758 player.startBoardX = boardX;
8759 player.startBoardY = boardY;
8760 ScreenSquare(boardX, boardY, &corner, &color);
8761 player.startSquare = corner;
8762 player.startColor = color;
8763 /* As soon as we start dragging, the piece will jump slightly to
8764 be centered over the mouse pointer. */
8765 player.mouseDelta.x = squareSize/2;
8766 player.mouseDelta.y = squareSize/2;
8767 /* Initialise animation */
8768 player.dragPiece = PieceForSquare(boardX, boardY);
8770 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8771 player.dragActive = True;
8772 BeginAnimation(&player, player.dragPiece, color, &corner);
8773 /* Mark this square as needing to be redrawn. Note that
8774 we don't remove the piece though, since logically (ie
8775 as seen by opponent) the move hasn't been made yet. */
8776 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8777 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8778 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8779 corner.x, corner.y, squareSize, squareSize,
8780 0, 0); // [HGM] zh: unstack in stead of grab
8781 damage[0][boardY][boardX] = True;
8783 player.dragActive = False;
8793 /* Are we animating? */
8794 if (!appData.animateDragging || appData.blindfold)
8798 if (! player.dragActive)
8800 /* Move piece, maintaining same relative position
8801 of mouse within square */
8802 corner.x = x - player.mouseDelta.x;
8803 corner.y = y - player.mouseDelta.y;
8804 AnimationFrame(&player, &corner, player.dragPiece);
8806 if (appData.highlightDragging) {
8808 BoardSquare(x, y, &boardX, &boardY);
8809 SetHighlights(fromX, fromY, boardX, boardY);
8818 int boardX, boardY, color;
8821 /* Are we animating? */
8822 if (!appData.animateDragging || appData.blindfold)
8826 if (! player.dragActive)
8828 /* Last frame in sequence is square piece is
8829 placed on, which may not match mouse exactly. */
8830 BoardSquare(x, y, &boardX, &boardY);
8831 ScreenSquare(boardX, boardY, &corner, &color);
8832 EndAnimation(&player, &corner);
8834 /* Be sure end square is redrawn */
8835 damage[0][boardY][boardX] = True;
8837 /* This prevents weird things happening with fast successive
8838 clicks which on my Sun at least can cause motion events
8839 without corresponding press/release. */
8840 player.dragActive = False;
8843 /* Handle expose event while piece being dragged */
8848 if (!player.dragActive || appData.blindfold)
8851 /* What we're doing: logically, the move hasn't been made yet,
8852 so the piece is still in it's original square. But visually
8853 it's being dragged around the board. So we erase the square
8854 that the piece is on and draw it at the last known drag point. */
8855 BlankSquare(player.startSquare.x, player.startSquare.y,
8856 player.startColor, EmptySquare, xBoardWindow);
8857 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8858 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8861 #include <sys/ioctl.h>
8862 int get_term_width()
8864 int fd, default_width;
8867 default_width = 79; // this is FICS default anyway...
8869 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8871 if (!ioctl(fd, TIOCGSIZE, &win))
8872 default_width = win.ts_cols;
8873 #elif defined(TIOCGWINSZ)
8875 if (!ioctl(fd, TIOCGWINSZ, &win))
8876 default_width = win.ws_col;
8878 return default_width;
8881 void update_ics_width()
8883 static int old_width = 0;
8884 int new_width = get_term_width();
8886 if (old_width != new_width)
8887 ics_printf("set width %d\n", new_width);
8888 old_width = new_width;
8891 void NotifyFrontendLogin()