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 SelectPV P((Widget w, XEvent * event,
266 String * params, Cardinal * nParams));
267 void StopPV P((Widget w, XEvent * event,
268 String * params, Cardinal * nParams));
269 void WhiteClock P((Widget w, XEvent *event,
270 String *prms, Cardinal *nprms));
271 void BlackClock P((Widget w, XEvent *event,
272 String *prms, Cardinal *nprms));
273 void DrawPositionProc P((Widget w, XEvent *event,
274 String *prms, Cardinal *nprms));
275 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
277 void CommentClick P((Widget w, XEvent * event,
278 String * params, Cardinal * nParams));
279 void CommentPopUp P((char *title, char *label));
280 void CommentPopDown P((void));
281 void CommentCallback P((Widget w, XtPointer client_data,
282 XtPointer call_data));
283 void ICSInputBoxPopUp P((void));
284 void ICSInputBoxPopDown P((void));
285 void FileNamePopUp P((char *label, char *def,
286 FileProc proc, char *openMode));
287 void FileNamePopDown P((void));
288 void FileNameCallback P((Widget w, XtPointer client_data,
289 XtPointer call_data));
290 void FileNameAction P((Widget w, XEvent *event,
291 String *prms, Cardinal *nprms));
292 void AskQuestionReplyAction P((Widget w, XEvent *event,
293 String *prms, Cardinal *nprms));
294 void AskQuestionProc P((Widget w, XEvent *event,
295 String *prms, Cardinal *nprms));
296 void AskQuestionPopDown P((void));
297 void PromotionPopDown P((void));
298 void PromotionCallback P((Widget w, XtPointer client_data,
299 XtPointer call_data));
300 void EditCommentPopDown P((void));
301 void EditCommentCallback P((Widget w, XtPointer client_data,
302 XtPointer call_data));
303 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
304 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
305 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
306 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
308 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
310 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
312 void LoadPositionProc P((Widget w, XEvent *event,
313 String *prms, Cardinal *nprms));
314 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
316 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
318 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
320 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
322 void PastePositionProc P((Widget w, XEvent *event, String *prms,
324 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void SavePositionProc P((Widget w, XEvent *event,
328 String *prms, Cardinal *nprms));
329 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
332 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
336 void MachineWhiteProc P((Widget w, XEvent *event,
337 String *prms, Cardinal *nprms));
338 void AnalyzeModeProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AnalyzeFileProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
344 void IcsClientProc P((Widget w, XEvent *event, String *prms,
346 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void EditPositionProc P((Widget w, XEvent *event,
348 String *prms, Cardinal *nprms));
349 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void EditCommentProc P((Widget w, XEvent *event,
351 String *prms, Cardinal *nprms));
352 void IcsInputBoxProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void StopObservingProc P((Widget w, XEvent *event, String *prms,
370 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
372 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
381 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
383 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
386 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
388 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
390 void AutocommProc P((Widget w, XEvent *event, String *prms,
392 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void AutobsProc P((Widget w, XEvent *event, String *prms,
396 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
401 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
404 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
406 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
408 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
412 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
414 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
416 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
418 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
420 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
424 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
426 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
428 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
430 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void DisplayMove P((int moveNumber));
442 void DisplayTitle P((char *title));
443 void ICSInitScript P((void));
444 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
445 void ErrorPopUp P((char *title, char *text, int modal));
446 void ErrorPopDown P((void));
447 static char *ExpandPathName P((char *path));
448 static void CreateAnimVars P((void));
449 static void DragPieceMove P((int x, int y));
450 static void DrawDragPiece P((void));
451 char *ModeToWidgetName P((GameMode mode));
452 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void GameListOptionsPopDown P(());
461 void ShufflePopDown P(());
462 void EnginePopDown P(());
463 void UciPopDown P(());
464 void TimeControlPopDown P(());
465 void NewVariantPopDown P(());
466 void SettingsPopDown P(());
467 void update_ics_width P(());
468 int get_term_width P(());
469 int CopyMemoProc P(());
471 * XBoard depends on Xt R4 or higher
473 int xtVersion = XtSpecificationRelease;
478 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
479 jailSquareColor, highlightSquareColor, premoveHighlightColor;
480 Pixel lowTimeWarningColor;
481 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
482 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
483 wjPieceGC, bjPieceGC, prelineGC, countGC;
484 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
485 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
486 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
487 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
488 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
489 ICSInputShell, fileNameShell, askQuestionShell;
490 Widget historyShell, evalGraphShell, gameListShell;
491 int hOffset; // [HGM] dual
492 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
493 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
494 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
495 Font clockFontID, coordFontID, countFontID;
496 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
497 XtAppContext appContext;
499 char *oldICSInteractionTitle;
503 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
505 Position commentX = -1, commentY = -1;
506 Dimension commentW, commentH;
507 typedef unsigned int BoardSize;
509 Boolean chessProgram;
511 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
512 int squareSize, smallLayout = 0, tinyLayout = 0,
513 marginW, marginH, // [HGM] for run-time resizing
514 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
515 ICSInputBoxUp = False, askQuestionUp = False,
516 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
517 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
518 Pixel timerForegroundPixel, timerBackgroundPixel;
519 Pixel buttonForegroundPixel, buttonBackgroundPixel;
520 char *chessDir, *programName, *programVersion,
521 *gameCopyFilename, *gamePasteFilename;
522 Boolean alwaysOnTop = False;
523 Boolean saveSettingsOnExit;
524 char *settingsFileName;
525 char *icsTextMenuString;
527 char *firstChessProgramNames;
528 char *secondChessProgramNames;
530 WindowPlacement wpMain;
531 WindowPlacement wpConsole;
532 WindowPlacement wpComment;
533 WindowPlacement wpMoveHistory;
534 WindowPlacement wpEvalGraph;
535 WindowPlacement wpEngineOutput;
536 WindowPlacement wpGameList;
537 WindowPlacement wpTags;
541 Pixmap pieceBitmap[2][(int)BlackPawn];
542 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
543 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
544 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
545 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
546 int useImages, useImageSqs;
547 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
548 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
549 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
550 XImage *ximLightSquare, *ximDarkSquare;
553 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
554 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
556 #define White(piece) ((int)(piece) < (int)BlackPawn)
558 /* Variables for doing smooth animation. This whole thing
559 would be much easier if the board was double-buffered,
560 but that would require a fairly major rewrite. */
565 GC blitGC, pieceGC, outlineGC;
566 XPoint startSquare, prevFrame, mouseDelta;
570 int startBoardX, startBoardY;
573 /* There can be two pieces being animated at once: a player
574 can begin dragging a piece before the remote opponent has moved. */
576 static AnimState game, player;
578 /* Bitmaps for use as masks when drawing XPM pieces.
579 Need one for each black and white piece. */
580 static Pixmap xpmMask[BlackKing + 1];
582 /* This magic number is the number of intermediate frames used
583 in each half of the animation. For short moves it's reduced
584 by 1. The total number of frames will be factor * 2 + 1. */
587 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
589 MenuItem fileMenu[] = {
590 {N_("New Game"), ResetProc},
591 {N_("New Shuffle Game ..."), ShuffleMenuProc},
592 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
593 {"----", NothingProc},
594 {N_("Load Game"), LoadGameProc},
595 {N_("Load Next Game"), LoadNextGameProc},
596 {N_("Load Previous Game"), LoadPrevGameProc},
597 {N_("Reload Same Game"), ReloadGameProc},
598 {N_("Save Game"), SaveGameProc},
599 {"----", NothingProc},
600 {N_("Copy Game"), CopyGameProc},
601 {N_("Paste Game"), PasteGameProc},
602 {"----", NothingProc},
603 {N_("Load Position"), LoadPositionProc},
604 {N_("Load Next Position"), LoadNextPositionProc},
605 {N_("Load Previous Position"), LoadPrevPositionProc},
606 {N_("Reload Same Position"), ReloadPositionProc},
607 {N_("Save Position"), SavePositionProc},
608 {"----", NothingProc},
609 {N_("Copy Position"), CopyPositionProc},
610 {N_("Paste Position"), PastePositionProc},
611 {"----", NothingProc},
612 {N_("Mail Move"), MailMoveProc},
613 {N_("Reload CMail Message"), ReloadCmailMsgProc},
614 {"----", NothingProc},
615 {N_("Exit"), QuitProc},
619 MenuItem modeMenu[] = {
620 {N_("Machine White"), MachineWhiteProc},
621 {N_("Machine Black"), MachineBlackProc},
622 {N_("Two Machines"), TwoMachinesProc},
623 {N_("Analysis Mode"), AnalyzeModeProc},
624 {N_("Analyze File"), AnalyzeFileProc },
625 {N_("ICS Client"), IcsClientProc},
626 {N_("Edit Game"), EditGameProc},
627 {N_("Edit Position"), EditPositionProc},
628 {N_("Training"), TrainingProc},
629 {"----", NothingProc},
630 {N_("Show Engine Output"), EngineOutputProc},
631 {N_("Show Evaluation Graph"), EvalGraphProc},
632 {N_("Show Game List"), ShowGameListProc},
633 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
634 {"----", NothingProc},
635 {N_("Edit Tags"), EditTagsProc},
636 {N_("Edit Comment"), EditCommentProc},
637 {N_("ICS Input Box"), IcsInputBoxProc},
638 {N_("Pause"), PauseProc},
642 MenuItem actionMenu[] = {
643 {N_("Accept"), AcceptProc},
644 {N_("Decline"), DeclineProc},
645 {N_("Rematch"), RematchProc},
646 {"----", NothingProc},
647 {N_("Call Flag"), CallFlagProc},
648 {N_("Draw"), DrawProc},
649 {N_("Adjourn"), AdjournProc},
650 {N_("Abort"), AbortProc},
651 {N_("Resign"), ResignProc},
652 {"----", NothingProc},
653 {N_("Stop Observing"), StopObservingProc},
654 {N_("Stop Examining"), StopExaminingProc},
655 {N_("Upload to Examine"), UploadProc},
656 {"----", NothingProc},
657 {N_("Adjudicate to White"), AdjuWhiteProc},
658 {N_("Adjudicate to Black"), AdjuBlackProc},
659 {N_("Adjudicate Draw"), AdjuDrawProc},
663 MenuItem stepMenu[] = {
664 {N_("Backward"), BackwardProc},
665 {N_("Forward"), ForwardProc},
666 {N_("Back to Start"), ToStartProc},
667 {N_("Forward to End"), ToEndProc},
668 {N_("Revert"), RevertProc},
669 {N_("Annotate"), AnnotateProc},
670 {N_("Truncate Game"), TruncateGameProc},
671 {"----", NothingProc},
672 {N_("Move Now"), MoveNowProc},
673 {N_("Retract Move"), RetractMoveProc},
677 MenuItem optionsMenu[] = {
678 {N_("Flip View"), FlipViewProc},
679 {"----", NothingProc},
680 {N_("Adjudications ..."), EngineMenuProc},
681 {N_("General Settings ..."), UciMenuProc},
682 {N_("Engine #1 Settings ..."), FirstSettingsProc},
683 {N_("Engine #2 Settings ..."), SecondSettingsProc},
684 {N_("Time Control ..."), TimeControlProc},
685 {N_("Game List ..."), GameListOptionsPopUp},
686 {"----", NothingProc},
687 {N_("Always Queen"), AlwaysQueenProc},
688 {N_("Animate Dragging"), AnimateDraggingProc},
689 {N_("Animate Moving"), AnimateMovingProc},
690 {N_("Auto Comment"), AutocommProc},
691 {N_("Auto Flag"), AutoflagProc},
692 {N_("Auto Flip View"), AutoflipProc},
693 {N_("Auto Observe"), AutobsProc},
694 {N_("Auto Raise Board"), AutoraiseProc},
695 {N_("Auto Save"), AutosaveProc},
696 {N_("Blindfold"), BlindfoldProc},
697 {N_("Flash Moves"), FlashMovesProc},
698 {N_("Get Move List"), GetMoveListProc},
700 {N_("Highlight Dragging"), HighlightDraggingProc},
702 {N_("Highlight Last Move"), HighlightLastMoveProc},
703 {N_("Move Sound"), MoveSoundProc},
704 {N_("ICS Alarm"), IcsAlarmProc},
705 {N_("Old Save Style"), OldSaveStyleProc},
706 {N_("Periodic Updates"), PeriodicUpdatesProc},
707 {N_("Ponder Next Move"), PonderNextMoveProc},
708 {N_("Popup Exit Message"), PopupExitMessageProc},
709 {N_("Popup Move Errors"), PopupMoveErrorsProc},
710 {N_("Premove"), PremoveProc},
711 {N_("Quiet Play"), QuietPlayProc},
712 {N_("Show Coords"), ShowCoordsProc},
713 {N_("Hide Thinking"), HideThinkingProc},
714 {N_("Test Legality"), TestLegalityProc},
715 {"----", NothingProc},
716 {N_("Save Settings Now"), SaveSettingsProc},
717 {N_("Save Settings on Exit"), SaveOnExitProc},
721 MenuItem helpMenu[] = {
722 {N_("Info XBoard"), InfoProc},
723 {N_("Man XBoard"), ManProc},
724 {"----", NothingProc},
725 {N_("Hint"), HintProc},
726 {N_("Book"), BookProc},
727 {"----", NothingProc},
728 {N_("About XBoard"), AboutProc},
733 {N_("File"), fileMenu},
734 {N_("Mode"), modeMenu},
735 {N_("Action"), actionMenu},
736 {N_("Step"), stepMenu},
737 {N_("Options"), optionsMenu},
738 {N_("Help"), helpMenu},
742 #define PAUSE_BUTTON N_("P")
743 MenuItem buttonBar[] = {
746 {PAUSE_BUTTON, PauseProc},
752 #define PIECE_MENU_SIZE 18
753 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
754 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
755 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
756 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
757 N_("Empty square"), N_("Clear board") },
758 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
759 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
760 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
761 N_("Empty square"), N_("Clear board") }
763 /* must be in same order as PieceMenuStrings! */
764 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
765 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
766 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
767 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
768 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
769 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
770 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
771 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
772 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
775 #define DROP_MENU_SIZE 6
776 String dropMenuStrings[DROP_MENU_SIZE] = {
777 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
779 /* must be in same order as PieceMenuStrings! */
780 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
781 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
782 WhiteRook, WhiteQueen
790 DropMenuEnables dmEnables[] = {
808 { XtNborderWidth, 0 },
809 { XtNdefaultDistance, 0 },
813 { XtNborderWidth, 0 },
814 { XtNresizable, (XtArgVal) True },
818 { XtNborderWidth, 0 },
824 { XtNjustify, (XtArgVal) XtJustifyRight },
825 { XtNlabel, (XtArgVal) "..." },
826 { XtNresizable, (XtArgVal) True },
827 { XtNresize, (XtArgVal) False }
830 Arg messageArgs[] = {
831 { XtNjustify, (XtArgVal) XtJustifyLeft },
832 { XtNlabel, (XtArgVal) "..." },
833 { XtNresizable, (XtArgVal) True },
834 { XtNresize, (XtArgVal) False }
838 { XtNborderWidth, 0 },
839 { XtNjustify, (XtArgVal) XtJustifyLeft }
842 XtResource clientResources[] = {
843 { "flashCount", "flashCount", XtRInt, sizeof(int),
844 XtOffset(AppDataPtr, flashCount), XtRImmediate,
845 (XtPointer) FLASH_COUNT },
848 XrmOptionDescRec shellOptions[] = {
849 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
850 { "-flash", "flashCount", XrmoptionNoArg, "3" },
851 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
854 XtActionsRec boardActions[] = {
855 { "DrawPosition", DrawPositionProc },
856 { "HandleUserMove", HandleUserMove },
857 { "AnimateUserMove", AnimateUserMove },
858 { "HandlePV", HandlePV },
859 { "SelectPV", SelectPV },
860 { "StopPV", StopPV },
861 { "FileNameAction", FileNameAction },
862 { "AskQuestionProc", AskQuestionProc },
863 { "AskQuestionReplyAction", AskQuestionReplyAction },
864 { "PieceMenuPopup", PieceMenuPopup },
865 { "WhiteClock", WhiteClock },
866 { "BlackClock", BlackClock },
867 { "Iconify", Iconify },
868 { "ResetProc", ResetProc },
869 { "LoadGameProc", LoadGameProc },
870 { "LoadNextGameProc", LoadNextGameProc },
871 { "LoadPrevGameProc", LoadPrevGameProc },
872 { "LoadSelectedProc", LoadSelectedProc },
873 { "SetFilterProc", SetFilterProc },
874 { "ReloadGameProc", ReloadGameProc },
875 { "LoadPositionProc", LoadPositionProc },
876 { "LoadNextPositionProc", LoadNextPositionProc },
877 { "LoadPrevPositionProc", LoadPrevPositionProc },
878 { "ReloadPositionProc", ReloadPositionProc },
879 { "CopyPositionProc", CopyPositionProc },
880 { "PastePositionProc", PastePositionProc },
881 { "CopyGameProc", CopyGameProc },
882 { "PasteGameProc", PasteGameProc },
883 { "SaveGameProc", SaveGameProc },
884 { "SavePositionProc", SavePositionProc },
885 { "MailMoveProc", MailMoveProc },
886 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
887 { "QuitProc", QuitProc },
888 { "MachineWhiteProc", MachineWhiteProc },
889 { "MachineBlackProc", MachineBlackProc },
890 { "AnalysisModeProc", AnalyzeModeProc },
891 { "AnalyzeFileProc", AnalyzeFileProc },
892 { "TwoMachinesProc", TwoMachinesProc },
893 { "IcsClientProc", IcsClientProc },
894 { "EditGameProc", EditGameProc },
895 { "EditPositionProc", EditPositionProc },
896 { "TrainingProc", EditPositionProc },
897 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
898 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
899 { "ShowGameListProc", ShowGameListProc },
900 { "ShowMoveListProc", HistoryShowProc},
901 { "EditTagsProc", EditCommentProc },
902 { "EditCommentProc", EditCommentProc },
903 { "IcsAlarmProc", IcsAlarmProc },
904 { "IcsInputBoxProc", IcsInputBoxProc },
905 { "PauseProc", PauseProc },
906 { "AcceptProc", AcceptProc },
907 { "DeclineProc", DeclineProc },
908 { "RematchProc", RematchProc },
909 { "CallFlagProc", CallFlagProc },
910 { "DrawProc", DrawProc },
911 { "AdjournProc", AdjournProc },
912 { "AbortProc", AbortProc },
913 { "ResignProc", ResignProc },
914 { "AdjuWhiteProc", AdjuWhiteProc },
915 { "AdjuBlackProc", AdjuBlackProc },
916 { "AdjuDrawProc", AdjuDrawProc },
917 { "EnterKeyProc", EnterKeyProc },
918 { "UpKeyProc", UpKeyProc },
919 { "DownKeyProc", DownKeyProc },
920 { "StopObservingProc", StopObservingProc },
921 { "StopExaminingProc", StopExaminingProc },
922 { "UploadProc", UploadProc },
923 { "BackwardProc", BackwardProc },
924 { "ForwardProc", ForwardProc },
925 { "ToStartProc", ToStartProc },
926 { "ToEndProc", ToEndProc },
927 { "RevertProc", RevertProc },
928 { "AnnotateProc", AnnotateProc },
929 { "TruncateGameProc", TruncateGameProc },
930 { "MoveNowProc", MoveNowProc },
931 { "RetractMoveProc", RetractMoveProc },
932 { "AlwaysQueenProc", AlwaysQueenProc },
933 { "AnimateDraggingProc", AnimateDraggingProc },
934 { "AnimateMovingProc", AnimateMovingProc },
935 { "AutoflagProc", AutoflagProc },
936 { "AutoflipProc", AutoflipProc },
937 { "AutobsProc", AutobsProc },
938 { "AutoraiseProc", AutoraiseProc },
939 { "AutosaveProc", AutosaveProc },
940 { "BlindfoldProc", BlindfoldProc },
941 { "FlashMovesProc", FlashMovesProc },
942 { "FlipViewProc", FlipViewProc },
943 { "GetMoveListProc", GetMoveListProc },
945 { "HighlightDraggingProc", HighlightDraggingProc },
947 { "HighlightLastMoveProc", HighlightLastMoveProc },
948 { "IcsAlarmProc", IcsAlarmProc },
949 { "MoveSoundProc", MoveSoundProc },
950 { "OldSaveStyleProc", OldSaveStyleProc },
951 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
952 { "PonderNextMoveProc", PonderNextMoveProc },
953 { "PopupExitMessageProc", PopupExitMessageProc },
954 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
955 { "PremoveProc", PremoveProc },
956 { "QuietPlayProc", QuietPlayProc },
957 { "ShowCoordsProc", ShowCoordsProc },
958 { "ShowThinkingProc", ShowThinkingProc },
959 { "HideThinkingProc", HideThinkingProc },
960 { "TestLegalityProc", TestLegalityProc },
961 { "SaveSettingsProc", SaveSettingsProc },
962 { "SaveOnExitProc", SaveOnExitProc },
963 { "InfoProc", InfoProc },
964 { "ManProc", ManProc },
965 { "HintProc", HintProc },
966 { "BookProc", BookProc },
967 { "AboutGameProc", AboutGameProc },
968 { "AboutProc", AboutProc },
969 { "DebugProc", DebugProc },
970 { "NothingProc", NothingProc },
971 { "CommentClick", (XtActionProc) CommentClick },
972 { "CommentPopDown", (XtActionProc) CommentPopDown },
973 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
974 { "TagsPopDown", (XtActionProc) TagsPopDown },
975 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
976 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
977 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
978 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
979 { "GameListPopDown", (XtActionProc) GameListPopDown },
980 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
981 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
982 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
983 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
984 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
985 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
986 { "EnginePopDown", (XtActionProc) EnginePopDown },
987 { "UciPopDown", (XtActionProc) UciPopDown },
988 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
989 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
990 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
991 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
994 char globalTranslations[] =
995 ":<Key>R: ResignProc() \n \
996 :<Key>r: ResetProc() \n \
997 :<Key>g: LoadGameProc() \n \
998 :<Key>N: LoadNextGameProc() \n \
999 :<Key>P: LoadPrevGameProc() \n \
1000 :<Key>Q: QuitProc() \n \
1001 :<Key>F: ToEndProc() \n \
1002 :<Key>f: ForwardProc() \n \
1003 :<Key>B: ToStartProc() \n \
1004 :<Key>b: BackwardProc() \n \
1005 :<Key>p: PauseProc() \n \
1006 :<Key>d: DrawProc() \n \
1007 :<Key>t: CallFlagProc() \n \
1008 :<Key>i: Iconify() \n \
1009 :<Key>c: Iconify() \n \
1010 :<Key>v: FlipViewProc() \n \
1011 <KeyDown>Control_L: BackwardProc() \n \
1012 <KeyUp>Control_L: ForwardProc() \n \
1013 <KeyDown>Control_R: BackwardProc() \n \
1014 <KeyUp>Control_R: ForwardProc() \n \
1015 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1016 \"Send to chess program:\",,1) \n \
1017 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1018 \"Send to second chess program:\",,2) \n";
1020 char boardTranslations[] =
1021 "<Btn1Down>: HandleUserMove() \n \
1022 <Btn1Up>: HandleUserMove() \n \
1023 <Btn1Motion>: AnimateUserMove() \n \
1024 <Btn3Motion>: HandlePV() \n \
1025 <Btn3Up>: PieceMenuPopup(menuB) \n \
1026 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1027 PieceMenuPopup(menuB) \n \
1028 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1029 PieceMenuPopup(menuW) \n \
1030 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1031 PieceMenuPopup(menuW) \n \
1032 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1033 PieceMenuPopup(menuB) \n";
1035 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1036 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1038 char ICSInputTranslations[] =
1039 "<Key>Up: UpKeyProc() \n "
1040 "<Key>Down: DownKeyProc() \n "
1041 "<Key>Return: EnterKeyProc() \n";
1043 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1044 // as the widget is destroyed before the up-click can call extend-end
1045 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1047 String xboardResources[] = {
1048 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1049 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1050 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1055 /* Max possible square size */
1056 #define MAXSQSIZE 256
1058 static int xpm_avail[MAXSQSIZE];
1060 #ifdef HAVE_DIR_STRUCT
1062 /* Extract piece size from filename */
1064 xpm_getsize(name, len, ext)
1075 if ((p=strchr(name, '.')) == NULL ||
1076 StrCaseCmp(p+1, ext) != 0)
1082 while (*p && isdigit(*p))
1089 /* Setup xpm_avail */
1091 xpm_getavail(dirname, ext)
1099 for (i=0; i<MAXSQSIZE; ++i)
1102 if (appData.debugMode)
1103 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1105 dir = opendir(dirname);
1108 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1109 programName, dirname);
1113 while ((ent=readdir(dir)) != NULL) {
1114 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1115 if (i > 0 && i < MAXSQSIZE)
1125 xpm_print_avail(fp, ext)
1131 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1132 for (i=1; i<MAXSQSIZE; ++i) {
1138 /* Return XPM piecesize closest to size */
1140 xpm_closest_to(dirname, size, ext)
1146 int sm_diff = MAXSQSIZE;
1150 xpm_getavail(dirname, ext);
1152 if (appData.debugMode)
1153 xpm_print_avail(stderr, ext);
1155 for (i=1; i<MAXSQSIZE; ++i) {
1158 diff = (diff<0) ? -diff : diff;
1159 if (diff < sm_diff) {
1167 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1173 #else /* !HAVE_DIR_STRUCT */
1174 /* If we are on a system without a DIR struct, we can't
1175 read the directory, so we can't collect a list of
1176 filenames, etc., so we can't do any size-fitting. */
1178 xpm_closest_to(dirname, size, ext)
1183 fprintf(stderr, _("\
1184 Warning: No DIR structure found on this system --\n\
1185 Unable to autosize for XPM/XIM pieces.\n\
1186 Please report this error to frankm@hiwaay.net.\n\
1187 Include system type & operating system in message.\n"));
1190 #endif /* HAVE_DIR_STRUCT */
1192 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1193 "magenta", "cyan", "white" };
1197 TextColors textColors[(int)NColorClasses];
1199 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1201 parse_color(str, which)
1205 char *p, buf[100], *d;
1208 if (strlen(str) > 99) /* watch bounds on buf */
1213 for (i=0; i<which; ++i) {
1220 /* Could be looking at something like:
1222 .. in which case we want to stop on a comma also */
1223 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1227 return -1; /* Use default for empty field */
1230 if (which == 2 || isdigit(*p))
1233 while (*p && isalpha(*p))
1238 for (i=0; i<8; ++i) {
1239 if (!StrCaseCmp(buf, cnames[i]))
1240 return which? (i+40) : (i+30);
1242 if (!StrCaseCmp(buf, "default")) return -1;
1244 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1249 parse_cpair(cc, str)
1253 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1254 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1259 /* bg and attr are optional */
1260 textColors[(int)cc].bg = parse_color(str, 1);
1261 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1262 textColors[(int)cc].attr = 0;
1268 /* Arrange to catch delete-window events */
1269 Atom wm_delete_window;
1271 CatchDeleteWindow(Widget w, String procname)
1274 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1275 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1276 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1283 XtSetArg(args[0], XtNiconic, False);
1284 XtSetValues(shellWidget, args, 1);
1286 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1289 //---------------------------------------------------------------------------------------------------------
1290 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1293 #define CW_USEDEFAULT (1<<31)
1294 #define ICS_TEXT_MENU_SIZE 90
1295 #define DEBUG_FILE "xboard.debug"
1296 #define SetCurrentDirectory chdir
1297 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1301 // these two must some day move to frontend.h, when they are implemented
1302 Boolean GameListIsUp();
1304 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1307 // front-end part of option handling
1309 // [HGM] This platform-dependent table provides the location for storing the color info
1310 extern char *crWhite, * crBlack;
1314 &appData.whitePieceColor,
1315 &appData.blackPieceColor,
1316 &appData.lightSquareColor,
1317 &appData.darkSquareColor,
1318 &appData.highlightSquareColor,
1319 &appData.premoveHighlightColor,
1320 &appData.lowTimeWarningColor,
1331 // [HGM] font: keep a font for each square size, even non-stndard ones
1332 #define NUM_SIZES 18
1333 #define MAX_SIZE 130
1334 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1335 char *fontTable[NUM_FONTS][MAX_SIZE];
1338 ParseFont(char *name, int number)
1339 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1341 if(sscanf(name, "size%d:", &size)) {
1342 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1343 // defer processing it until we know if it matches our board size
1344 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1345 fontTable[number][size] = strdup(strchr(name, ':')+1);
1346 fontValid[number][size] = True;
1351 case 0: // CLOCK_FONT
1352 appData.clockFont = strdup(name);
1354 case 1: // MESSAGE_FONT
1355 appData.font = strdup(name);
1357 case 2: // COORD_FONT
1358 appData.coordFont = strdup(name);
1363 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1368 { // only 2 fonts currently
1369 appData.clockFont = CLOCK_FONT_NAME;
1370 appData.coordFont = COORD_FONT_NAME;
1371 appData.font = DEFAULT_FONT_NAME;
1376 { // no-op, until we identify the code for this already in XBoard and move it here
1380 ParseColor(int n, char *name)
1381 { // in XBoard, just copy the color-name string
1382 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1386 ParseTextAttribs(ColorClass cc, char *s)
1388 (&appData.colorShout)[cc] = strdup(s);
1392 ParseBoardSize(void *addr, char *name)
1394 appData.boardSize = strdup(name);
1399 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1403 SetCommPortDefaults()
1404 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1407 // [HGM] args: these three cases taken out to stay in front-end
1409 SaveFontArg(FILE *f, ArgDescriptor *ad)
1411 char *name, buf[MSG_SIZ];
1412 int i, n = (int)ad->argLoc;
1414 case 0: // CLOCK_FONT
1415 name = appData.clockFont;
1417 case 1: // MESSAGE_FONT
1418 name = appData.font;
1420 case 2: // COORD_FONT
1421 name = appData.coordFont;
1426 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1427 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1428 fontTable[n][squareSize] = strdup(name);
1429 fontValid[n][squareSize] = True;
1432 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1433 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1438 { // nothing to do, as the sounds are at all times represented by their text-string names already
1442 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1443 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1444 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1448 SaveColor(FILE *f, ArgDescriptor *ad)
1449 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1450 if(colorVariable[(int)ad->argLoc])
1451 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1455 SaveBoardSize(FILE *f, char *name, void *addr)
1456 { // wrapper to shield back-end from BoardSize & sizeInfo
1457 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1461 ParseCommPortSettings(char *s)
1462 { // no such option in XBoard (yet)
1465 extern Widget engineOutputShell;
1466 extern Widget tagsShell, editTagsShell;
1468 GetActualPlacement(Widget wg, WindowPlacement *wp)
1478 XtSetArg(args[i], XtNx, &x); i++;
1479 XtSetArg(args[i], XtNy, &y); i++;
1480 XtSetArg(args[i], XtNwidth, &w); i++;
1481 XtSetArg(args[i], XtNheight, &h); i++;
1482 XtGetValues(wg, args, i);
1491 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1492 // In XBoard this will have to wait until awareness of window parameters is implemented
1493 GetActualPlacement(shellWidget, &wpMain);
1494 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1495 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1496 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1497 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1498 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1499 else GetActualPlacement(editShell, &wpComment);
1500 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1501 else GetActualPlacement(editTagsShell, &wpTags);
1505 PrintCommPortSettings(FILE *f, char *name)
1506 { // This option does not exist in XBoard
1510 MySearchPath(char *installDir, char *name, char *fullname)
1511 { // just append installDir and name. Perhaps ExpandPath should be used here?
1512 name = ExpandPathName(name);
1513 if(name && name[0] == '/') strcpy(fullname, name); else {
1514 sprintf(fullname, "%s%c%s", installDir, '/', name);
1520 MyGetFullPathName(char *name, char *fullname)
1521 { // should use ExpandPath?
1522 name = ExpandPathName(name);
1523 strcpy(fullname, name);
1528 EnsureOnScreen(int *x, int *y, int minX, int minY)
1535 { // [HGM] args: allows testing if main window is realized from back-end
1536 return xBoardWindow != 0;
1540 PopUpStartupDialog()
1541 { // start menu not implemented in XBoard
1544 ConvertToLine(int argc, char **argv)
1546 static char line[128*1024], buf[1024];
1550 for(i=1; i<argc; i++) {
1551 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1552 && argv[i][0] != '{' )
1553 sprintf(buf, "{%s} ", argv[i]);
1554 else sprintf(buf, "%s ", argv[i]);
1557 line[strlen(line)-1] = NULLCHAR;
1561 //--------------------------------------------------------------------------------------------
1563 extern Boolean twoBoards, partnerUp;
1566 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1568 #define BoardSize int
1569 void InitDrawingSizes(BoardSize boardSize, int flags)
1570 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1571 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1573 XtGeometryResult gres;
1576 if(!formWidget) return;
1579 * Enable shell resizing.
1581 shellArgs[0].value = (XtArgVal) &w;
1582 shellArgs[1].value = (XtArgVal) &h;
1583 XtGetValues(shellWidget, shellArgs, 2);
1585 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1586 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1587 XtSetValues(shellWidget, &shellArgs[2], 4);
1589 XtSetArg(args[0], XtNdefaultDistance, &sep);
1590 XtGetValues(formWidget, args, 1);
1592 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1593 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1595 hOffset = boardWidth + 10;
1596 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1597 secondSegments[i] = gridSegments[i];
1598 secondSegments[i].x1 += hOffset;
1599 secondSegments[i].x2 += hOffset;
1602 XtSetArg(args[0], XtNwidth, boardWidth);
1603 XtSetArg(args[1], XtNheight, boardHeight);
1604 XtSetValues(boardWidget, args, 2);
1606 timerWidth = (boardWidth - sep) / 2;
1607 XtSetArg(args[0], XtNwidth, timerWidth);
1608 XtSetValues(whiteTimerWidget, args, 1);
1609 XtSetValues(blackTimerWidget, args, 1);
1611 XawFormDoLayout(formWidget, False);
1613 if (appData.titleInWindow) {
1615 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1616 XtSetArg(args[i], XtNheight, &h); i++;
1617 XtGetValues(titleWidget, args, i);
1619 w = boardWidth - 2*bor;
1621 XtSetArg(args[0], XtNwidth, &w);
1622 XtGetValues(menuBarWidget, args, 1);
1623 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1626 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1627 if (gres != XtGeometryYes && appData.debugMode) {
1629 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1630 programName, gres, w, h, wr, hr);
1634 XawFormDoLayout(formWidget, True);
1637 * Inhibit shell resizing.
1639 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1640 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1641 shellArgs[4].value = shellArgs[2].value = w;
1642 shellArgs[5].value = shellArgs[3].value = h;
1643 XtSetValues(shellWidget, &shellArgs[0], 6);
1645 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1648 for(i=0; i<4; i++) {
1650 for(p=0; p<=(int)WhiteKing; p++)
1651 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1652 if(gameInfo.variant == VariantShogi) {
1653 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1654 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1655 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1656 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1657 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1660 if(gameInfo.variant == VariantGothic) {
1661 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1665 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1666 for(p=0; p<=(int)WhiteKing; p++)
1667 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1668 if(gameInfo.variant == VariantShogi) {
1669 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1670 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1671 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1672 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1673 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1676 if(gameInfo.variant == VariantGothic) {
1677 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1683 for(i=0; i<2; i++) {
1685 for(p=0; p<=(int)WhiteKing; p++)
1686 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1687 if(gameInfo.variant == VariantShogi) {
1688 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1689 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1690 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1691 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1692 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1695 if(gameInfo.variant == VariantGothic) {
1696 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1707 void EscapeExpand(char *p, char *q)
1708 { // [HGM] initstring: routine to shape up string arguments
1709 while(*p++ = *q++) if(p[-1] == '\\')
1711 case 'n': p[-1] = '\n'; break;
1712 case 'r': p[-1] = '\r'; break;
1713 case 't': p[-1] = '\t'; break;
1714 case '\\': p[-1] = '\\'; break;
1715 case 0: *p = 0; return;
1716 default: p[-1] = q[-1]; break;
1725 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1726 XSetWindowAttributes window_attributes;
1728 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1729 XrmValue vFrom, vTo;
1730 XtGeometryResult gres;
1733 int forceMono = False;
1735 srandom(time(0)); // [HGM] book: make random truly random
1737 setbuf(stdout, NULL);
1738 setbuf(stderr, NULL);
1741 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1742 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1746 programName = strrchr(argv[0], '/');
1747 if (programName == NULL)
1748 programName = argv[0];
1753 XtSetLanguageProc(NULL, NULL, NULL);
1754 bindtextdomain(PACKAGE, LOCALEDIR);
1755 textdomain(PACKAGE);
1759 XtAppInitialize(&appContext, "XBoard", shellOptions,
1760 XtNumber(shellOptions),
1761 &argc, argv, xboardResources, NULL, 0);
1762 appData.boardSize = "";
1763 InitAppData(ConvertToLine(argc, argv));
1765 if (p == NULL) p = "/tmp";
1766 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1767 gameCopyFilename = (char*) malloc(i);
1768 gamePasteFilename = (char*) malloc(i);
1769 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1770 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1772 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1773 clientResources, XtNumber(clientResources),
1776 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1777 static char buf[MSG_SIZ];
1778 EscapeExpand(buf, appData.initString);
1779 appData.initString = strdup(buf);
1780 EscapeExpand(buf, appData.secondInitString);
1781 appData.secondInitString = strdup(buf);
1782 EscapeExpand(buf, appData.firstComputerString);
1783 appData.firstComputerString = strdup(buf);
1784 EscapeExpand(buf, appData.secondComputerString);
1785 appData.secondComputerString = strdup(buf);
1788 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1791 if (chdir(chessDir) != 0) {
1792 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1798 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1799 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1800 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1801 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1804 setbuf(debugFP, NULL);
1807 /* [HGM,HR] make sure board size is acceptable */
1808 if(appData.NrFiles > BOARD_FILES ||
1809 appData.NrRanks > BOARD_RANKS )
1810 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1813 /* This feature does not work; animation needs a rewrite */
1814 appData.highlightDragging = FALSE;
1818 xDisplay = XtDisplay(shellWidget);
1819 xScreen = DefaultScreen(xDisplay);
1820 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1822 gameInfo.variant = StringToVariant(appData.variant);
1823 InitPosition(FALSE);
1826 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1828 if (isdigit(appData.boardSize[0])) {
1829 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1830 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1831 &fontPxlSize, &smallLayout, &tinyLayout);
1833 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1834 programName, appData.boardSize);
1838 /* Find some defaults; use the nearest known size */
1839 SizeDefaults *szd, *nearest;
1840 int distance = 99999;
1841 nearest = szd = sizeDefaults;
1842 while (szd->name != NULL) {
1843 if (abs(szd->squareSize - squareSize) < distance) {
1845 distance = abs(szd->squareSize - squareSize);
1846 if (distance == 0) break;
1850 if (i < 2) lineGap = nearest->lineGap;
1851 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1852 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1853 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1854 if (i < 6) smallLayout = nearest->smallLayout;
1855 if (i < 7) tinyLayout = nearest->tinyLayout;
1858 SizeDefaults *szd = sizeDefaults;
1859 if (*appData.boardSize == NULLCHAR) {
1860 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1861 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1864 if (szd->name == NULL) szd--;
1865 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1867 while (szd->name != NULL &&
1868 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1869 if (szd->name == NULL) {
1870 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1871 programName, appData.boardSize);
1875 squareSize = szd->squareSize;
1876 lineGap = szd->lineGap;
1877 clockFontPxlSize = szd->clockFontPxlSize;
1878 coordFontPxlSize = szd->coordFontPxlSize;
1879 fontPxlSize = szd->fontPxlSize;
1880 smallLayout = szd->smallLayout;
1881 tinyLayout = szd->tinyLayout;
1882 // [HGM] font: use defaults from settings file if available and not overruled
1884 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1885 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1886 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1887 appData.font = fontTable[MESSAGE_FONT][squareSize];
1888 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1889 appData.coordFont = fontTable[COORD_FONT][squareSize];
1891 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1892 if (strlen(appData.pixmapDirectory) > 0) {
1893 p = ExpandPathName(appData.pixmapDirectory);
1895 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1896 appData.pixmapDirectory);
1899 if (appData.debugMode) {
1900 fprintf(stderr, _("\
1901 XBoard square size (hint): %d\n\
1902 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1904 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1905 if (appData.debugMode) {
1906 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1910 /* [HR] height treated separately (hacked) */
1911 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1912 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1913 if (appData.showJail == 1) {
1914 /* Jail on top and bottom */
1915 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1916 XtSetArg(boardArgs[2], XtNheight,
1917 boardHeight + 2*(lineGap + squareSize));
1918 } else if (appData.showJail == 2) {
1920 XtSetArg(boardArgs[1], XtNwidth,
1921 boardWidth + 2*(lineGap + squareSize));
1922 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1925 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1926 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1930 * Determine what fonts to use.
1932 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1933 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1934 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1935 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1936 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1937 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1938 appData.font = FindFont(appData.font, fontPxlSize);
1939 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1940 countFontStruct = XQueryFont(xDisplay, countFontID);
1941 // appData.font = FindFont(appData.font, fontPxlSize);
1943 xdb = XtDatabase(xDisplay);
1944 XrmPutStringResource(&xdb, "*font", appData.font);
1947 * Detect if there are not enough colors available and adapt.
1949 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1950 appData.monoMode = True;
1953 if (!appData.monoMode) {
1954 vFrom.addr = (caddr_t) appData.lightSquareColor;
1955 vFrom.size = strlen(appData.lightSquareColor);
1956 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1957 if (vTo.addr == NULL) {
1958 appData.monoMode = True;
1961 lightSquareColor = *(Pixel *) vTo.addr;
1964 if (!appData.monoMode) {
1965 vFrom.addr = (caddr_t) appData.darkSquareColor;
1966 vFrom.size = strlen(appData.darkSquareColor);
1967 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1968 if (vTo.addr == NULL) {
1969 appData.monoMode = True;
1972 darkSquareColor = *(Pixel *) vTo.addr;
1975 if (!appData.monoMode) {
1976 vFrom.addr = (caddr_t) appData.whitePieceColor;
1977 vFrom.size = strlen(appData.whitePieceColor);
1978 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1979 if (vTo.addr == NULL) {
1980 appData.monoMode = True;
1983 whitePieceColor = *(Pixel *) vTo.addr;
1986 if (!appData.monoMode) {
1987 vFrom.addr = (caddr_t) appData.blackPieceColor;
1988 vFrom.size = strlen(appData.blackPieceColor);
1989 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1990 if (vTo.addr == NULL) {
1991 appData.monoMode = True;
1994 blackPieceColor = *(Pixel *) vTo.addr;
1998 if (!appData.monoMode) {
1999 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2000 vFrom.size = strlen(appData.highlightSquareColor);
2001 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2002 if (vTo.addr == NULL) {
2003 appData.monoMode = True;
2006 highlightSquareColor = *(Pixel *) vTo.addr;
2010 if (!appData.monoMode) {
2011 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2012 vFrom.size = strlen(appData.premoveHighlightColor);
2013 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2014 if (vTo.addr == NULL) {
2015 appData.monoMode = True;
2018 premoveHighlightColor = *(Pixel *) vTo.addr;
2023 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2026 if (appData.bitmapDirectory == NULL ||
2027 appData.bitmapDirectory[0] == NULLCHAR)
2028 appData.bitmapDirectory = DEF_BITMAP_DIR;
2031 if (appData.lowTimeWarning && !appData.monoMode) {
2032 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2033 vFrom.size = strlen(appData.lowTimeWarningColor);
2034 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2035 if (vTo.addr == NULL)
2036 appData.monoMode = True;
2038 lowTimeWarningColor = *(Pixel *) vTo.addr;
2041 if (appData.monoMode && appData.debugMode) {
2042 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2043 (unsigned long) XWhitePixel(xDisplay, xScreen),
2044 (unsigned long) XBlackPixel(xDisplay, xScreen));
2047 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2048 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2049 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2050 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2051 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2052 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2053 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2054 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2055 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2056 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2058 if (appData.colorize) {
2060 _("%s: can't parse color names; disabling colorization\n"),
2063 appData.colorize = FALSE;
2065 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2066 textColors[ColorNone].attr = 0;
2068 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2074 layoutName = "tinyLayout";
2075 } else if (smallLayout) {
2076 layoutName = "smallLayout";
2078 layoutName = "normalLayout";
2080 /* Outer layoutWidget is there only to provide a name for use in
2081 resources that depend on the layout style */
2083 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2084 layoutArgs, XtNumber(layoutArgs));
2086 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2087 formArgs, XtNumber(formArgs));
2088 XtSetArg(args[0], XtNdefaultDistance, &sep);
2089 XtGetValues(formWidget, args, 1);
2092 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2093 XtSetArg(args[0], XtNtop, XtChainTop);
2094 XtSetArg(args[1], XtNbottom, XtChainTop);
2095 XtSetArg(args[2], XtNright, XtChainLeft);
2096 XtSetValues(menuBarWidget, args, 3);
2098 widgetList[j++] = whiteTimerWidget =
2099 XtCreateWidget("whiteTime", labelWidgetClass,
2100 formWidget, timerArgs, XtNumber(timerArgs));
2101 XtSetArg(args[0], XtNfont, clockFontStruct);
2102 XtSetArg(args[1], XtNtop, XtChainTop);
2103 XtSetArg(args[2], XtNbottom, XtChainTop);
2104 XtSetValues(whiteTimerWidget, args, 3);
2106 widgetList[j++] = blackTimerWidget =
2107 XtCreateWidget("blackTime", labelWidgetClass,
2108 formWidget, timerArgs, XtNumber(timerArgs));
2109 XtSetArg(args[0], XtNfont, clockFontStruct);
2110 XtSetArg(args[1], XtNtop, XtChainTop);
2111 XtSetArg(args[2], XtNbottom, XtChainTop);
2112 XtSetValues(blackTimerWidget, args, 3);
2114 if (appData.titleInWindow) {
2115 widgetList[j++] = titleWidget =
2116 XtCreateWidget("title", labelWidgetClass, formWidget,
2117 titleArgs, XtNumber(titleArgs));
2118 XtSetArg(args[0], XtNtop, XtChainTop);
2119 XtSetArg(args[1], XtNbottom, XtChainTop);
2120 XtSetValues(titleWidget, args, 2);
2123 if (appData.showButtonBar) {
2124 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2125 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2126 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2127 XtSetArg(args[2], XtNtop, XtChainTop);
2128 XtSetArg(args[3], XtNbottom, XtChainTop);
2129 XtSetValues(buttonBarWidget, args, 4);
2132 widgetList[j++] = messageWidget =
2133 XtCreateWidget("message", labelWidgetClass, formWidget,
2134 messageArgs, XtNumber(messageArgs));
2135 XtSetArg(args[0], XtNtop, XtChainTop);
2136 XtSetArg(args[1], XtNbottom, XtChainTop);
2137 XtSetValues(messageWidget, args, 2);
2139 widgetList[j++] = boardWidget =
2140 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2141 XtNumber(boardArgs));
2143 XtManageChildren(widgetList, j);
2145 timerWidth = (boardWidth - sep) / 2;
2146 XtSetArg(args[0], XtNwidth, timerWidth);
2147 XtSetValues(whiteTimerWidget, args, 1);
2148 XtSetValues(blackTimerWidget, args, 1);
2150 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2151 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2152 XtGetValues(whiteTimerWidget, args, 2);
2154 if (appData.showButtonBar) {
2155 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2156 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2157 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2161 * formWidget uses these constraints but they are stored
2165 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2166 XtSetValues(menuBarWidget, args, i);
2167 if (appData.titleInWindow) {
2170 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2171 XtSetValues(whiteTimerWidget, args, i);
2173 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2174 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2175 XtSetValues(blackTimerWidget, args, i);
2177 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2178 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2179 XtSetValues(titleWidget, args, i);
2181 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2182 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2183 XtSetValues(messageWidget, args, i);
2184 if (appData.showButtonBar) {
2186 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2187 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2188 XtSetValues(buttonBarWidget, args, i);
2192 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2193 XtSetValues(whiteTimerWidget, args, i);
2195 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2196 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2197 XtSetValues(blackTimerWidget, args, i);
2199 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2200 XtSetValues(titleWidget, args, i);
2202 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2203 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2204 XtSetValues(messageWidget, args, i);
2205 if (appData.showButtonBar) {
2207 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2208 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2209 XtSetValues(buttonBarWidget, args, i);
2214 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2215 XtSetValues(whiteTimerWidget, args, i);
2217 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2218 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2219 XtSetValues(blackTimerWidget, args, i);
2221 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2222 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2223 XtSetValues(messageWidget, args, i);
2224 if (appData.showButtonBar) {
2226 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2227 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2228 XtSetValues(buttonBarWidget, args, i);
2232 XtSetArg(args[0], XtNfromVert, messageWidget);
2233 XtSetArg(args[1], XtNtop, XtChainTop);
2234 XtSetArg(args[2], XtNbottom, XtChainBottom);
2235 XtSetArg(args[3], XtNleft, XtChainLeft);
2236 XtSetArg(args[4], XtNright, XtChainRight);
2237 XtSetValues(boardWidget, args, 5);
2239 XtRealizeWidget(shellWidget);
2242 XtSetArg(args[0], XtNx, wpMain.x);
2243 XtSetArg(args[1], XtNy, wpMain.y);
2244 XtSetValues(shellWidget, args, 2);
2248 * Correct the width of the message and title widgets.
2249 * It is not known why some systems need the extra fudge term.
2250 * The value "2" is probably larger than needed.
2252 XawFormDoLayout(formWidget, False);
2254 #define WIDTH_FUDGE 2
2256 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2257 XtSetArg(args[i], XtNheight, &h); i++;
2258 XtGetValues(messageWidget, args, i);
2259 if (appData.showButtonBar) {
2261 XtSetArg(args[i], XtNwidth, &w); i++;
2262 XtGetValues(buttonBarWidget, args, i);
2263 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2265 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2268 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2269 if (gres != XtGeometryYes && appData.debugMode) {
2270 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2271 programName, gres, w, h, wr, hr);
2274 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2275 /* The size used for the child widget in layout lags one resize behind
2276 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2278 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2279 if (gres != XtGeometryYes && appData.debugMode) {
2280 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2281 programName, gres, w, h, wr, hr);
2284 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2285 XtSetArg(args[1], XtNright, XtChainRight);
2286 XtSetValues(messageWidget, args, 2);
2288 if (appData.titleInWindow) {
2290 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2291 XtSetArg(args[i], XtNheight, &h); i++;
2292 XtGetValues(titleWidget, args, i);
2294 w = boardWidth - 2*bor;
2296 XtSetArg(args[0], XtNwidth, &w);
2297 XtGetValues(menuBarWidget, args, 1);
2298 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2301 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2302 if (gres != XtGeometryYes && appData.debugMode) {
2304 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2305 programName, gres, w, h, wr, hr);
2308 XawFormDoLayout(formWidget, True);
2310 xBoardWindow = XtWindow(boardWidget);
2312 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2313 // not need to go into InitDrawingSizes().
2317 * Create X checkmark bitmap and initialize option menu checks.
2319 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2320 checkmark_bits, checkmark_width, checkmark_height);
2321 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2322 if (appData.alwaysPromoteToQueen) {
2323 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2326 if (appData.animateDragging) {
2327 XtSetValues(XtNameToWidget(menuBarWidget,
2328 "menuOptions.Animate Dragging"),
2331 if (appData.animate) {
2332 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2335 if (appData.autoComment) {
2336 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2339 if (appData.autoCallFlag) {
2340 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2343 if (appData.autoFlipView) {
2344 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2347 if (appData.autoObserve) {
2348 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2351 if (appData.autoRaiseBoard) {
2352 XtSetValues(XtNameToWidget(menuBarWidget,
2353 "menuOptions.Auto Raise Board"), args, 1);
2355 if (appData.autoSaveGames) {
2356 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2359 if (appData.saveGameFile[0] != NULLCHAR) {
2360 /* Can't turn this off from menu */
2361 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2363 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2367 if (appData.blindfold) {
2368 XtSetValues(XtNameToWidget(menuBarWidget,
2369 "menuOptions.Blindfold"), args, 1);
2371 if (appData.flashCount > 0) {
2372 XtSetValues(XtNameToWidget(menuBarWidget,
2373 "menuOptions.Flash Moves"),
2376 if (appData.getMoveList) {
2377 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2381 if (appData.highlightDragging) {
2382 XtSetValues(XtNameToWidget(menuBarWidget,
2383 "menuOptions.Highlight Dragging"),
2387 if (appData.highlightLastMove) {
2388 XtSetValues(XtNameToWidget(menuBarWidget,
2389 "menuOptions.Highlight Last Move"),
2392 if (appData.icsAlarm) {
2393 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2396 if (appData.ringBellAfterMoves) {
2397 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2400 if (appData.oldSaveStyle) {
2401 XtSetValues(XtNameToWidget(menuBarWidget,
2402 "menuOptions.Old Save Style"), args, 1);
2404 if (appData.periodicUpdates) {
2405 XtSetValues(XtNameToWidget(menuBarWidget,
2406 "menuOptions.Periodic Updates"), args, 1);
2408 if (appData.ponderNextMove) {
2409 XtSetValues(XtNameToWidget(menuBarWidget,
2410 "menuOptions.Ponder Next Move"), args, 1);
2412 if (appData.popupExitMessage) {
2413 XtSetValues(XtNameToWidget(menuBarWidget,
2414 "menuOptions.Popup Exit Message"), args, 1);
2416 if (appData.popupMoveErrors) {
2417 XtSetValues(XtNameToWidget(menuBarWidget,
2418 "menuOptions.Popup Move Errors"), args, 1);
2420 if (appData.premove) {
2421 XtSetValues(XtNameToWidget(menuBarWidget,
2422 "menuOptions.Premove"), args, 1);
2424 if (appData.quietPlay) {
2425 XtSetValues(XtNameToWidget(menuBarWidget,
2426 "menuOptions.Quiet Play"), args, 1);
2428 if (appData.showCoords) {
2429 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2432 if (appData.hideThinkingFromHuman) {
2433 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2436 if (appData.testLegality) {
2437 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2440 if (saveSettingsOnExit) {
2441 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2448 ReadBitmap(&wIconPixmap, "icon_white.bm",
2449 icon_white_bits, icon_white_width, icon_white_height);
2450 ReadBitmap(&bIconPixmap, "icon_black.bm",
2451 icon_black_bits, icon_black_width, icon_black_height);
2452 iconPixmap = wIconPixmap;
2454 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2455 XtSetValues(shellWidget, args, i);
2458 * Create a cursor for the board widget.
2460 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2461 XChangeWindowAttributes(xDisplay, xBoardWindow,
2462 CWCursor, &window_attributes);
2465 * Inhibit shell resizing.
2467 shellArgs[0].value = (XtArgVal) &w;
2468 shellArgs[1].value = (XtArgVal) &h;
2469 XtGetValues(shellWidget, shellArgs, 2);
2470 shellArgs[4].value = shellArgs[2].value = w;
2471 shellArgs[5].value = shellArgs[3].value = h;
2472 XtSetValues(shellWidget, &shellArgs[2], 4);
2473 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2474 marginH = h - boardHeight;
2476 CatchDeleteWindow(shellWidget, "QuitProc");
2481 if (appData.bitmapDirectory[0] != NULLCHAR) {
2488 /* Create regular pieces */
2489 if (!useImages) CreatePieces();
2494 if (appData.animate || appData.animateDragging)
2497 XtAugmentTranslations(formWidget,
2498 XtParseTranslationTable(globalTranslations));
2499 XtAugmentTranslations(boardWidget,
2500 XtParseTranslationTable(boardTranslations));
2501 XtAugmentTranslations(whiteTimerWidget,
2502 XtParseTranslationTable(whiteTranslations));
2503 XtAugmentTranslations(blackTimerWidget,
2504 XtParseTranslationTable(blackTranslations));
2506 /* Why is the following needed on some versions of X instead
2507 * of a translation? */
2508 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2509 (XtEventHandler) EventProc, NULL);
2512 /* [AS] Restore layout */
2513 if( wpMoveHistory.visible ) {
2517 if( wpEvalGraph.visible )
2522 if( wpEngineOutput.visible ) {
2523 EngineOutputPopUp();
2528 if (errorExitStatus == -1) {
2529 if (appData.icsActive) {
2530 /* We now wait until we see "login:" from the ICS before
2531 sending the logon script (problems with timestamp otherwise) */
2532 /*ICSInitScript();*/
2533 if (appData.icsInputBox) ICSInputBoxPopUp();
2537 signal(SIGWINCH, TermSizeSigHandler);
2539 signal(SIGINT, IntSigHandler);
2540 signal(SIGTERM, IntSigHandler);
2541 if (*appData.cmailGameName != NULLCHAR) {
2542 signal(SIGUSR1, CmailSigHandler);
2545 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2547 XtSetKeyboardFocus(shellWidget, formWidget);
2549 XtAppMainLoop(appContext);
2550 if (appData.debugMode) fclose(debugFP); // [DM] debug
2557 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2558 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2560 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2561 unlink(gameCopyFilename);
2562 unlink(gamePasteFilename);
2565 RETSIGTYPE TermSizeSigHandler(int sig)
2578 CmailSigHandler(sig)
2584 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2586 /* Activate call-back function CmailSigHandlerCallBack() */
2587 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2589 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2593 CmailSigHandlerCallBack(isr, closure, message, count, error)
2601 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2603 /**** end signal code ****/
2613 f = fopen(appData.icsLogon, "r");
2619 strcat(buf, appData.icsLogon);
2620 f = fopen(buf, "r");
2624 ProcessICSInitScript(f);
2631 EditCommentPopDown();
2646 if (!menuBarWidget) return;
2647 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2649 DisplayError("menuStep.Revert", 0);
2651 XtSetSensitive(w, !grey);
2653 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2655 DisplayError("menuStep.Annotate", 0);
2657 XtSetSensitive(w, !grey);
2662 SetMenuEnables(enab)
2666 if (!menuBarWidget) return;
2667 while (enab->name != NULL) {
2668 w = XtNameToWidget(menuBarWidget, enab->name);
2670 DisplayError(enab->name, 0);
2672 XtSetSensitive(w, enab->value);
2678 Enables icsEnables[] = {
2679 { "menuFile.Mail Move", False },
2680 { "menuFile.Reload CMail Message", False },
2681 { "menuMode.Machine Black", False },
2682 { "menuMode.Machine White", False },
2683 { "menuMode.Analysis Mode", False },
2684 { "menuMode.Analyze File", False },
2685 { "menuMode.Two Machines", False },
2687 { "menuHelp.Hint", False },
2688 { "menuHelp.Book", False },
2689 { "menuStep.Move Now", False },
2690 { "menuOptions.Periodic Updates", False },
2691 { "menuOptions.Hide Thinking", False },
2692 { "menuOptions.Ponder Next Move", False },
2694 { "menuStep.Annotate", False },
2698 Enables ncpEnables[] = {
2699 { "menuFile.Mail Move", False },
2700 { "menuFile.Reload CMail Message", False },
2701 { "menuMode.Machine White", False },
2702 { "menuMode.Machine Black", False },
2703 { "menuMode.Analysis Mode", False },
2704 { "menuMode.Analyze File", False },
2705 { "menuMode.Two Machines", False },
2706 { "menuMode.ICS Client", False },
2707 { "menuMode.ICS Input Box", False },
2708 { "Action", False },
2709 { "menuStep.Revert", False },
2710 { "menuStep.Annotate", False },
2711 { "menuStep.Move Now", False },
2712 { "menuStep.Retract Move", False },
2713 { "menuOptions.Auto Comment", False },
2714 { "menuOptions.Auto Flag", False },
2715 { "menuOptions.Auto Flip View", False },
2716 { "menuOptions.Auto Observe", False },
2717 { "menuOptions.Auto Raise Board", False },
2718 { "menuOptions.Get Move List", False },
2719 { "menuOptions.ICS Alarm", False },
2720 { "menuOptions.Move Sound", False },
2721 { "menuOptions.Quiet Play", False },
2722 { "menuOptions.Hide Thinking", False },
2723 { "menuOptions.Periodic Updates", False },
2724 { "menuOptions.Ponder Next Move", False },
2725 { "menuHelp.Hint", False },
2726 { "menuHelp.Book", False },
2730 Enables gnuEnables[] = {
2731 { "menuMode.ICS Client", False },
2732 { "menuMode.ICS Input Box", False },
2733 { "menuAction.Accept", False },
2734 { "menuAction.Decline", False },
2735 { "menuAction.Rematch", False },
2736 { "menuAction.Adjourn", False },
2737 { "menuAction.Stop Examining", False },
2738 { "menuAction.Stop Observing", False },
2739 { "menuAction.Upload to Examine", False },
2740 { "menuStep.Revert", False },
2741 { "menuStep.Annotate", False },
2742 { "menuOptions.Auto Comment", False },
2743 { "menuOptions.Auto Observe", False },
2744 { "menuOptions.Auto Raise Board", False },
2745 { "menuOptions.Get Move List", False },
2746 { "menuOptions.Premove", False },
2747 { "menuOptions.Quiet Play", False },
2749 /* The next two options rely on SetCmailMode being called *after* */
2750 /* SetGNUMode so that when GNU is being used to give hints these */
2751 /* menu options are still available */
2753 { "menuFile.Mail Move", False },
2754 { "menuFile.Reload CMail Message", False },
2758 Enables cmailEnables[] = {
2760 { "menuAction.Call Flag", False },
2761 { "menuAction.Draw", True },
2762 { "menuAction.Adjourn", False },
2763 { "menuAction.Abort", False },
2764 { "menuAction.Stop Observing", False },
2765 { "menuAction.Stop Examining", False },
2766 { "menuFile.Mail Move", True },
2767 { "menuFile.Reload CMail Message", True },
2771 Enables trainingOnEnables[] = {
2772 { "menuMode.Edit Comment", False },
2773 { "menuMode.Pause", False },
2774 { "menuStep.Forward", False },
2775 { "menuStep.Backward", False },
2776 { "menuStep.Forward to End", False },
2777 { "menuStep.Back to Start", False },
2778 { "menuStep.Move Now", False },
2779 { "menuStep.Truncate Game", False },
2783 Enables trainingOffEnables[] = {
2784 { "menuMode.Edit Comment", True },
2785 { "menuMode.Pause", True },
2786 { "menuStep.Forward", True },
2787 { "menuStep.Backward", True },
2788 { "menuStep.Forward to End", True },
2789 { "menuStep.Back to Start", True },
2790 { "menuStep.Move Now", True },
2791 { "menuStep.Truncate Game", True },
2795 Enables machineThinkingEnables[] = {
2796 { "menuFile.Load Game", False },
2797 { "menuFile.Load Next Game", False },
2798 { "menuFile.Load Previous Game", False },
2799 { "menuFile.Reload Same Game", False },
2800 { "menuFile.Paste Game", False },
2801 { "menuFile.Load Position", False },
2802 { "menuFile.Load Next Position", False },
2803 { "menuFile.Load Previous Position", False },
2804 { "menuFile.Reload Same Position", False },
2805 { "menuFile.Paste Position", False },
2806 { "menuMode.Machine White", False },
2807 { "menuMode.Machine Black", False },
2808 { "menuMode.Two Machines", False },
2809 { "menuStep.Retract Move", False },
2813 Enables userThinkingEnables[] = {
2814 { "menuFile.Load Game", True },
2815 { "menuFile.Load Next Game", True },
2816 { "menuFile.Load Previous Game", True },
2817 { "menuFile.Reload Same Game", True },
2818 { "menuFile.Paste Game", True },
2819 { "menuFile.Load Position", True },
2820 { "menuFile.Load Next Position", True },
2821 { "menuFile.Load Previous Position", True },
2822 { "menuFile.Reload Same Position", True },
2823 { "menuFile.Paste Position", True },
2824 { "menuMode.Machine White", True },
2825 { "menuMode.Machine Black", True },
2826 { "menuMode.Two Machines", True },
2827 { "menuStep.Retract Move", True },
2833 SetMenuEnables(icsEnables);
2836 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2837 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2844 SetMenuEnables(ncpEnables);
2850 SetMenuEnables(gnuEnables);
2856 SetMenuEnables(cmailEnables);
2862 SetMenuEnables(trainingOnEnables);
2863 if (appData.showButtonBar) {
2864 XtSetSensitive(buttonBarWidget, False);
2870 SetTrainingModeOff()
2872 SetMenuEnables(trainingOffEnables);
2873 if (appData.showButtonBar) {
2874 XtSetSensitive(buttonBarWidget, True);
2879 SetUserThinkingEnables()
2881 if (appData.noChessProgram) return;
2882 SetMenuEnables(userThinkingEnables);
2886 SetMachineThinkingEnables()
2888 if (appData.noChessProgram) return;
2889 SetMenuEnables(machineThinkingEnables);
2891 case MachinePlaysBlack:
2892 case MachinePlaysWhite:
2893 case TwoMachinesPlay:
2894 XtSetSensitive(XtNameToWidget(menuBarWidget,
2895 ModeToWidgetName(gameMode)), True);
2902 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2903 #define HISTORY_SIZE 64
\r
2904 static char *history[HISTORY_SIZE];
\r
2905 int histIn = 0, histP = 0;
\r
2908 SaveInHistory(char *cmd)
\r
2910 if (history[histIn] != NULL) {
\r
2911 free(history[histIn]);
\r
2912 history[histIn] = NULL;
\r
2914 if (*cmd == NULLCHAR) return;
\r
2915 history[histIn] = StrSave(cmd);
\r
2916 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2917 if (history[histIn] != NULL) {
\r
2918 free(history[histIn]);
\r
2919 history[histIn] = NULL;
\r
2925 PrevInHistory(char *cmd)
\r
2928 if (histP == histIn) {
\r
2929 if (history[histIn] != NULL) free(history[histIn]);
\r
2930 history[histIn] = StrSave(cmd);
\r
2932 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2933 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2935 return history[histP];
\r
2941 if (histP == histIn) return NULL;
\r
2942 histP = (histP + 1) % HISTORY_SIZE;
\r
2943 return history[histP];
\r
2945 // end of borrowed code
\r
2947 #define Abs(n) ((n)<0 ? -(n) : (n))
2950 * Find a font that matches "pattern" that is as close as
2951 * possible to the targetPxlSize. Prefer fonts that are k
2952 * pixels smaller to fonts that are k pixels larger. The
2953 * pattern must be in the X Consortium standard format,
2954 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2955 * The return value should be freed with XtFree when no
2958 char *FindFont(pattern, targetPxlSize)
2962 char **fonts, *p, *best, *scalable, *scalableTail;
2963 int i, j, nfonts, minerr, err, pxlSize;
2966 char **missing_list;
2968 char *def_string, *base_fnt_lst, strInt[3];
2970 XFontStruct **fnt_list;
2972 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2973 sprintf(strInt, "%d", targetPxlSize);
2974 p = strstr(pattern, "--");
2975 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2976 strcat(base_fnt_lst, strInt);
2977 strcat(base_fnt_lst, strchr(p + 2, '-'));
2979 if ((fntSet = XCreateFontSet(xDisplay,
2983 &def_string)) == NULL) {
2985 fprintf(stderr, _("Unable to create font set.\n"));
2989 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2991 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2993 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2994 programName, pattern);
3002 for (i=0; i<nfonts; i++) {
3005 if (*p != '-') continue;
3007 if (*p == NULLCHAR) break;
3008 if (*p++ == '-') j++;
3010 if (j < 7) continue;
3013 scalable = fonts[i];
3016 err = pxlSize - targetPxlSize;
3017 if (Abs(err) < Abs(minerr) ||
3018 (minerr > 0 && err < 0 && -err == minerr)) {
3024 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3025 /* If the error is too big and there is a scalable font,
3026 use the scalable font. */
3027 int headlen = scalableTail - scalable;
3028 p = (char *) XtMalloc(strlen(scalable) + 10);
3029 while (isdigit(*scalableTail)) scalableTail++;
3030 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3032 p = (char *) XtMalloc(strlen(best) + 1);
3035 if (appData.debugMode) {
3036 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3037 pattern, targetPxlSize, p);
3040 if (missing_count > 0)
3041 XFreeStringList(missing_list);
3042 XFreeFontSet(xDisplay, fntSet);
3044 XFreeFontNames(fonts);
3051 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3052 | GCBackground | GCFunction | GCPlaneMask;
3053 XGCValues gc_values;
3056 gc_values.plane_mask = AllPlanes;
3057 gc_values.line_width = lineGap;
3058 gc_values.line_style = LineSolid;
3059 gc_values.function = GXcopy;
3061 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3062 gc_values.background = XBlackPixel(xDisplay, xScreen);
3063 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3065 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3066 gc_values.background = XWhitePixel(xDisplay, xScreen);
3067 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3068 XSetFont(xDisplay, coordGC, coordFontID);
3070 // [HGM] make font for holdings counts (white on black0
3071 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3072 gc_values.background = XBlackPixel(xDisplay, xScreen);
3073 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3074 XSetFont(xDisplay, countGC, countFontID);
3076 if (appData.monoMode) {
3077 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3078 gc_values.background = XWhitePixel(xDisplay, xScreen);
3079 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3081 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3082 gc_values.background = XBlackPixel(xDisplay, xScreen);
3083 lightSquareGC = wbPieceGC
3084 = XtGetGC(shellWidget, value_mask, &gc_values);
3086 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3087 gc_values.background = XWhitePixel(xDisplay, xScreen);
3088 darkSquareGC = bwPieceGC
3089 = XtGetGC(shellWidget, value_mask, &gc_values);
3091 if (DefaultDepth(xDisplay, xScreen) == 1) {
3092 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3093 gc_values.function = GXcopyInverted;
3094 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3095 gc_values.function = GXcopy;
3096 if (XBlackPixel(xDisplay, xScreen) == 1) {
3097 bwPieceGC = darkSquareGC;
3098 wbPieceGC = copyInvertedGC;
3100 bwPieceGC = copyInvertedGC;
3101 wbPieceGC = lightSquareGC;
3105 gc_values.foreground = highlightSquareColor;
3106 gc_values.background = highlightSquareColor;
3107 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3109 gc_values.foreground = premoveHighlightColor;
3110 gc_values.background = premoveHighlightColor;
3111 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3113 gc_values.foreground = lightSquareColor;
3114 gc_values.background = darkSquareColor;
3115 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3117 gc_values.foreground = darkSquareColor;
3118 gc_values.background = lightSquareColor;
3119 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3121 gc_values.foreground = jailSquareColor;
3122 gc_values.background = jailSquareColor;
3123 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3125 gc_values.foreground = whitePieceColor;
3126 gc_values.background = darkSquareColor;
3127 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3129 gc_values.foreground = whitePieceColor;
3130 gc_values.background = lightSquareColor;
3131 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3133 gc_values.foreground = whitePieceColor;
3134 gc_values.background = jailSquareColor;
3135 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3137 gc_values.foreground = blackPieceColor;
3138 gc_values.background = darkSquareColor;
3139 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3141 gc_values.foreground = blackPieceColor;
3142 gc_values.background = lightSquareColor;
3143 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3145 gc_values.foreground = blackPieceColor;
3146 gc_values.background = jailSquareColor;
3147 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3151 void loadXIM(xim, xmask, filename, dest, mask)
3164 fp = fopen(filename, "rb");
3166 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3173 for (y=0; y<h; ++y) {
3174 for (x=0; x<h; ++x) {
3179 XPutPixel(xim, x, y, blackPieceColor);
3181 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3184 XPutPixel(xim, x, y, darkSquareColor);
3186 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3189 XPutPixel(xim, x, y, whitePieceColor);
3191 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3194 XPutPixel(xim, x, y, lightSquareColor);
3196 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3202 /* create Pixmap of piece */
3203 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3205 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3208 /* create Pixmap of clipmask
3209 Note: We assume the white/black pieces have the same
3210 outline, so we make only 6 masks. This is okay
3211 since the XPM clipmask routines do the same. */
3213 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3215 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3218 /* now create the 1-bit version */
3219 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3222 values.foreground = 1;
3223 values.background = 0;
3225 /* Don't use XtGetGC, not read only */
3226 maskGC = XCreateGC(xDisplay, *mask,
3227 GCForeground | GCBackground, &values);
3228 XCopyPlane(xDisplay, temp, *mask, maskGC,
3229 0, 0, squareSize, squareSize, 0, 0, 1);
3230 XFreePixmap(xDisplay, temp);
3235 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3237 void CreateXIMPieces()
3242 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3247 /* The XSynchronize calls were copied from CreatePieces.
3248 Not sure if needed, but can't hurt */
3249 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3252 /* temp needed by loadXIM() */
3253 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3254 0, 0, ss, ss, AllPlanes, XYPixmap);
3256 if (strlen(appData.pixmapDirectory) == 0) {
3260 if (appData.monoMode) {
3261 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3265 fprintf(stderr, _("\nLoading XIMs...\n"));
3267 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3268 fprintf(stderr, "%d", piece+1);
3269 for (kind=0; kind<4; kind++) {
3270 fprintf(stderr, ".");
3271 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3272 ExpandPathName(appData.pixmapDirectory),
3273 piece <= (int) WhiteKing ? "" : "w",
3274 pieceBitmapNames[piece],
3276 ximPieceBitmap[kind][piece] =
3277 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3278 0, 0, ss, ss, AllPlanes, XYPixmap);
3279 if (appData.debugMode)
3280 fprintf(stderr, _("(File:%s:) "), buf);
3281 loadXIM(ximPieceBitmap[kind][piece],
3283 &(xpmPieceBitmap2[kind][piece]),
3284 &(ximMaskPm2[piece]));
3285 if(piece <= (int)WhiteKing)
3286 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3288 fprintf(stderr," ");
3290 /* Load light and dark squares */
3291 /* If the LSQ and DSQ pieces don't exist, we will
3292 draw them with solid squares. */
3293 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3294 if (access(buf, 0) != 0) {
3298 fprintf(stderr, _("light square "));
3300 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3301 0, 0, ss, ss, AllPlanes, XYPixmap);
3302 if (appData.debugMode)
3303 fprintf(stderr, _("(File:%s:) "), buf);
3305 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3306 fprintf(stderr, _("dark square "));
3307 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3308 ExpandPathName(appData.pixmapDirectory), ss);
3309 if (appData.debugMode)
3310 fprintf(stderr, _("(File:%s:) "), buf);
3312 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3313 0, 0, ss, ss, AllPlanes, XYPixmap);
3314 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3315 xpmJailSquare = xpmLightSquare;
3317 fprintf(stderr, _("Done.\n"));
3319 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3323 void CreateXPMPieces()
3327 u_int ss = squareSize;
3329 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3330 XpmColorSymbol symbols[4];
3332 /* The XSynchronize calls were copied from CreatePieces.
3333 Not sure if needed, but can't hurt */
3334 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3336 /* Setup translations so piece colors match square colors */
3337 symbols[0].name = "light_piece";
3338 symbols[0].value = appData.whitePieceColor;
3339 symbols[1].name = "dark_piece";
3340 symbols[1].value = appData.blackPieceColor;
3341 symbols[2].name = "light_square";
3342 symbols[2].value = appData.lightSquareColor;
3343 symbols[3].name = "dark_square";
3344 symbols[3].value = appData.darkSquareColor;
3346 attr.valuemask = XpmColorSymbols;
3347 attr.colorsymbols = symbols;
3348 attr.numsymbols = 4;
3350 if (appData.monoMode) {
3351 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3355 if (strlen(appData.pixmapDirectory) == 0) {
3356 XpmPieces* pieces = builtInXpms;
3359 while (pieces->size != squareSize && pieces->size) pieces++;
3360 if (!pieces->size) {
3361 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3364 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3365 for (kind=0; kind<4; kind++) {
3367 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3368 pieces->xpm[piece][kind],
3369 &(xpmPieceBitmap2[kind][piece]),
3370 NULL, &attr)) != 0) {
3371 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3375 if(piece <= (int) WhiteKing)
3376 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3380 xpmJailSquare = xpmLightSquare;
3384 fprintf(stderr, _("\nLoading XPMs...\n"));
3387 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3388 fprintf(stderr, "%d ", piece+1);
3389 for (kind=0; kind<4; kind++) {
3390 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3391 ExpandPathName(appData.pixmapDirectory),
3392 piece > (int) WhiteKing ? "w" : "",
3393 pieceBitmapNames[piece],
3395 if (appData.debugMode) {
3396 fprintf(stderr, _("(File:%s:) "), buf);
3398 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3399 &(xpmPieceBitmap2[kind][piece]),
3400 NULL, &attr)) != 0) {
3401 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3402 // [HGM] missing: read of unorthodox piece failed; substitute King.
3403 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3404 ExpandPathName(appData.pixmapDirectory),
3406 if (appData.debugMode) {
3407 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3409 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3410 &(xpmPieceBitmap2[kind][piece]),
3414 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3419 if(piece <= (int) WhiteKing)
3420 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3423 /* Load light and dark squares */
3424 /* If the LSQ and DSQ pieces don't exist, we will
3425 draw them with solid squares. */
3426 fprintf(stderr, _("light square "));
3427 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3428 if (access(buf, 0) != 0) {
3432 if (appData.debugMode)
3433 fprintf(stderr, _("(File:%s:) "), buf);
3435 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3436 &xpmLightSquare, NULL, &attr)) != 0) {
3437 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3440 fprintf(stderr, _("dark square "));
3441 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3442 ExpandPathName(appData.pixmapDirectory), ss);
3443 if (appData.debugMode) {
3444 fprintf(stderr, _("(File:%s:) "), buf);
3446 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3447 &xpmDarkSquare, NULL, &attr)) != 0) {
3448 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3452 xpmJailSquare = xpmLightSquare;
3453 fprintf(stderr, _("Done.\n"));
3455 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3458 #endif /* HAVE_LIBXPM */
3461 /* No built-in bitmaps */
3466 u_int ss = squareSize;
3468 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3471 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3472 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3473 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3474 pieceBitmapNames[piece],
3475 ss, kind == SOLID ? 's' : 'o');
3476 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3477 if(piece <= (int)WhiteKing)
3478 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3482 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3486 /* With built-in bitmaps */
3489 BuiltInBits* bib = builtInBits;
3492 u_int ss = squareSize;
3494 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3497 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3499 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3500 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3501 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3502 pieceBitmapNames[piece],
3503 ss, kind == SOLID ? 's' : 'o');
3504 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3505 bib->bits[kind][piece], ss, ss);
3506 if(piece <= (int)WhiteKing)
3507 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3511 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3516 void ReadBitmap(pm, name, bits, wreq, hreq)
3519 unsigned char bits[];
3525 char msg[MSG_SIZ], fullname[MSG_SIZ];
3527 if (*appData.bitmapDirectory != NULLCHAR) {
3528 strcpy(fullname, appData.bitmapDirectory);
3529 strcat(fullname, "/");
3530 strcat(fullname, name);
3531 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3532 &w, &h, pm, &x_hot, &y_hot);
3533 fprintf(stderr, "load %s\n", name);
3534 if (errcode != BitmapSuccess) {
3536 case BitmapOpenFailed:
3537 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3539 case BitmapFileInvalid:
3540 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3542 case BitmapNoMemory:
3543 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3547 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3551 fprintf(stderr, _("%s: %s...using built-in\n"),
3553 } else if (w != wreq || h != hreq) {
3555 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3556 programName, fullname, w, h, wreq, hreq);
3562 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3571 if (lineGap == 0) return;
3573 /* [HR] Split this into 2 loops for non-square boards. */
3575 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3576 gridSegments[i].x1 = 0;
3577 gridSegments[i].x2 =
3578 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3579 gridSegments[i].y1 = gridSegments[i].y2
3580 = lineGap / 2 + (i * (squareSize + lineGap));
3583 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3584 gridSegments[j + i].y1 = 0;
3585 gridSegments[j + i].y2 =
3586 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3587 gridSegments[j + i].x1 = gridSegments[j + i].x2
3588 = lineGap / 2 + (j * (squareSize + lineGap));
3592 static void MenuBarSelect(w, addr, index)
3597 XtActionProc proc = (XtActionProc) addr;
3599 (proc)(NULL, NULL, NULL, NULL);
3602 void CreateMenuBarPopup(parent, name, mb)
3612 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3615 XtSetArg(args[j], XtNleftMargin, 20); j++;
3616 XtSetArg(args[j], XtNrightMargin, 20); j++;
3618 while (mi->string != NULL) {
3619 if (strcmp(mi->string, "----") == 0) {
3620 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3623 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3624 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3626 XtAddCallback(entry, XtNcallback,
3627 (XtCallbackProc) MenuBarSelect,
3628 (caddr_t) mi->proc);
3634 Widget CreateMenuBar(mb)
3638 Widget anchor, menuBar;
3640 char menuName[MSG_SIZ];
3643 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3644 XtSetArg(args[j], XtNvSpace, 0); j++;
3645 XtSetArg(args[j], XtNborderWidth, 0); j++;
3646 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3647 formWidget, args, j);
3649 while (mb->name != NULL) {
3650 strcpy(menuName, "menu");
3651 strcat(menuName, mb->name);
3653 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3656 shortName[0] = _(mb->name)[0];
3657 shortName[1] = NULLCHAR;
3658 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3661 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3664 XtSetArg(args[j], XtNborderWidth, 0); j++;
3665 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3667 CreateMenuBarPopup(menuBar, menuName, mb);
3673 Widget CreateButtonBar(mi)
3677 Widget button, buttonBar;
3681 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3683 XtSetArg(args[j], XtNhSpace, 0); j++;
3685 XtSetArg(args[j], XtNborderWidth, 0); j++;
3686 XtSetArg(args[j], XtNvSpace, 0); j++;
3687 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3688 formWidget, args, j);
3690 while (mi->string != NULL) {
3693 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3694 XtSetArg(args[j], XtNborderWidth, 0); j++;
3696 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3697 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3698 buttonBar, args, j);
3699 XtAddCallback(button, XtNcallback,
3700 (XtCallbackProc) MenuBarSelect,
3701 (caddr_t) mi->proc);
3708 CreatePieceMenu(name, color)
3715 ChessSquare selection;
3717 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3718 boardWidget, args, 0);
3720 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3721 String item = pieceMenuStrings[color][i];
3723 if (strcmp(item, "----") == 0) {
3724 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3727 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3728 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3730 selection = pieceMenuTranslation[color][i];
3731 XtAddCallback(entry, XtNcallback,
3732 (XtCallbackProc) PieceMenuSelect,
3733 (caddr_t) selection);
3734 if (selection == WhitePawn || selection == BlackPawn) {
3735 XtSetArg(args[0], XtNpopupOnEntry, entry);
3736 XtSetValues(menu, args, 1);
3749 ChessSquare selection;
3751 whitePieceMenu = CreatePieceMenu("menuW", 0);
3752 blackPieceMenu = CreatePieceMenu("menuB", 1);
3754 XtRegisterGrabAction(PieceMenuPopup, True,
3755 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3756 GrabModeAsync, GrabModeAsync);
3758 XtSetArg(args[0], XtNlabel, _("Drop"));
3759 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3760 boardWidget, args, 1);
3761 for (i = 0; i < DROP_MENU_SIZE; i++) {
3762 String item = dropMenuStrings[i];
3764 if (strcmp(item, "----") == 0) {
3765 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3768 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3769 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3771 selection = dropMenuTranslation[i];
3772 XtAddCallback(entry, XtNcallback,
3773 (XtCallbackProc) DropMenuSelect,
3774 (caddr_t) selection);
3779 void SetupDropMenu()
3787 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3788 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3789 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3790 dmEnables[i].piece);
3791 XtSetSensitive(entry, p != NULL || !appData.testLegality
3792 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3793 && !appData.icsActive));
3795 while (p && *p++ == dmEnables[i].piece) count++;
3796 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3798 XtSetArg(args[j], XtNlabel, label); j++;
3799 XtSetValues(entry, args, j);
3803 void PieceMenuPopup(w, event, params, num_params)
3807 Cardinal *num_params;
3809 String whichMenu; int menuNr;
3810 if (event->type == ButtonRelease)
3811 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3812 else if (event->type == ButtonPress)
3813 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3815 case 0: whichMenu = params[0]; break;
3816 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3818 case -1: if (errorUp) ErrorPopDown();
3821 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3824 static void PieceMenuSelect(w, piece, junk)
3829 if (pmFromX < 0 || pmFromY < 0) return;
3830 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3833 static void DropMenuSelect(w, piece, junk)
3838 if (pmFromX < 0 || pmFromY < 0) return;
3839 DropMenuEvent(piece, pmFromX, pmFromY);
3842 void WhiteClock(w, event, prms, nprms)
3848 if (gameMode == EditPosition || gameMode == IcsExamining) {
3849 SetWhiteToPlayEvent();
3850 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3855 void BlackClock(w, event, prms, nprms)
3861 if (gameMode == EditPosition || gameMode == IcsExamining) {
3862 SetBlackToPlayEvent();
3863 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3870 * If the user selects on a border boundary, return -1; if off the board,
3871 * return -2. Otherwise map the event coordinate to the square.
3873 int EventToSquare(x, limit)
3881 if ((x % (squareSize + lineGap)) >= squareSize)
3883 x /= (squareSize + lineGap);
3889 static void do_flash_delay(msec)
3895 static void drawHighlight(file, rank, gc)
3901 if (lineGap == 0 || appData.blindfold) return;
3904 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3905 (squareSize + lineGap);
3906 y = lineGap/2 + rank * (squareSize + lineGap);
3908 x = lineGap/2 + file * (squareSize + lineGap);
3909 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3910 (squareSize + lineGap);
3913 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3914 squareSize+lineGap, squareSize+lineGap);
3917 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3918 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3921 SetHighlights(fromX, fromY, toX, toY)
3922 int fromX, fromY, toX, toY;
3924 if (hi1X != fromX || hi1Y != fromY) {
3925 if (hi1X >= 0 && hi1Y >= 0) {
3926 drawHighlight(hi1X, hi1Y, lineGC);
3928 } // [HGM] first erase both, then draw new!
3929 if (hi2X != toX || hi2Y != toY) {
3930 if (hi2X >= 0 && hi2Y >= 0) {
3931 drawHighlight(hi2X, hi2Y, lineGC);
3934 if (hi1X != fromX || hi1Y != fromY) {
3935 if (fromX >= 0 && fromY >= 0) {
3936 drawHighlight(fromX, fromY, highlineGC);
3939 if (hi2X != toX || hi2Y != toY) {
3940 if (toX >= 0 && toY >= 0) {
3941 drawHighlight(toX, toY, highlineGC);
3953 SetHighlights(-1, -1, -1, -1);
3958 SetPremoveHighlights(fromX, fromY, toX, toY)
3959 int fromX, fromY, toX, toY;
3961 if (pm1X != fromX || pm1Y != fromY) {
3962 if (pm1X >= 0 && pm1Y >= 0) {
3963 drawHighlight(pm1X, pm1Y, lineGC);
3965 if (fromX >= 0 && fromY >= 0) {
3966 drawHighlight(fromX, fromY, prelineGC);
3969 if (pm2X != toX || pm2Y != toY) {
3970 if (pm2X >= 0 && pm2Y >= 0) {
3971 drawHighlight(pm2X, pm2Y, lineGC);
3973 if (toX >= 0 && toY >= 0) {
3974 drawHighlight(toX, toY, prelineGC);
3984 ClearPremoveHighlights()
3986 SetPremoveHighlights(-1, -1, -1, -1);
3989 static void BlankSquare(x, y, color, piece, dest)
3994 if (useImages && useImageSqs) {
3998 pm = xpmLightSquare;
4003 case 2: /* neutral */
4008 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4009 squareSize, squareSize, x, y);
4019 case 2: /* neutral */
4024 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4029 I split out the routines to draw a piece so that I could
4030 make a generic flash routine.
4032 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4034 int square_color, x, y;
4037 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4038 switch (square_color) {
4040 case 2: /* neutral */
4042 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4043 ? *pieceToOutline(piece)
4044 : *pieceToSolid(piece),
4045 dest, bwPieceGC, 0, 0,
4046 squareSize, squareSize, x, y);
4049 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4050 ? *pieceToSolid(piece)
4051 : *pieceToOutline(piece),
4052 dest, wbPieceGC, 0, 0,
4053 squareSize, squareSize, x, y);
4058 static void monoDrawPiece(piece, square_color, x, y, dest)
4060 int square_color, x, y;
4063 switch (square_color) {
4065 case 2: /* neutral */
4067 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4068 ? *pieceToOutline(piece)
4069 : *pieceToSolid(piece),
4070 dest, bwPieceGC, 0, 0,
4071 squareSize, squareSize, x, y, 1);
4074 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4075 ? *pieceToSolid(piece)
4076 : *pieceToOutline(piece),
4077 dest, wbPieceGC, 0, 0,
4078 squareSize, squareSize, x, y, 1);
4083 static void colorDrawPiece(piece, square_color, x, y, dest)
4085 int square_color, x, y;
4088 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4089 switch (square_color) {
4091 XCopyPlane(xDisplay, *pieceToSolid(piece),
4092 dest, (int) piece < (int) BlackPawn
4093 ? wlPieceGC : blPieceGC, 0, 0,
4094 squareSize, squareSize, x, y, 1);
4097 XCopyPlane(xDisplay, *pieceToSolid(piece),
4098 dest, (int) piece < (int) BlackPawn
4099 ? wdPieceGC : bdPieceGC, 0, 0,
4100 squareSize, squareSize, x, y, 1);
4102 case 2: /* neutral */
4104 XCopyPlane(xDisplay, *pieceToSolid(piece),
4105 dest, (int) piece < (int) BlackPawn
4106 ? wjPieceGC : bjPieceGC, 0, 0,
4107 squareSize, squareSize, x, y, 1);
4112 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4114 int square_color, x, y;
4119 switch (square_color) {
4121 case 2: /* neutral */
4123 if ((int)piece < (int) BlackPawn) {
4131 if ((int)piece < (int) BlackPawn) {
4139 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4140 dest, wlPieceGC, 0, 0,
4141 squareSize, squareSize, x, y);
4144 typedef void (*DrawFunc)();
4146 DrawFunc ChooseDrawFunc()
4148 if (appData.monoMode) {
4149 if (DefaultDepth(xDisplay, xScreen) == 1) {
4150 return monoDrawPiece_1bit;
4152 return monoDrawPiece;
4156 return colorDrawPieceImage;
4158 return colorDrawPiece;
4162 /* [HR] determine square color depending on chess variant. */
4163 static int SquareColor(row, column)
4168 if (gameInfo.variant == VariantXiangqi) {
4169 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4171 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4173 } else if (row <= 4) {
4179 square_color = ((column + row) % 2) == 1;
4182 /* [hgm] holdings: next line makes all holdings squares light */
4183 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4185 return square_color;
4188 void DrawSquare(row, column, piece, do_flash)
4189 int row, column, do_flash;
4192 int square_color, x, y, direction, font_ascent, font_descent;
4195 XCharStruct overall;
4199 /* Calculate delay in milliseconds (2-delays per complete flash) */
4200 flash_delay = 500 / appData.flashRate;
4203 x = lineGap + ((BOARD_WIDTH-1)-column) *
4204 (squareSize + lineGap);
4205 y = lineGap + row * (squareSize + lineGap);
4207 x = lineGap + column * (squareSize + lineGap);
4208 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4209 (squareSize + lineGap);
4212 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4214 square_color = SquareColor(row, column);
4216 if ( // [HGM] holdings: blank out area between board and holdings
4217 column == BOARD_LEFT-1 || column == BOARD_RGHT
4218 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4219 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4220 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4222 // [HGM] print piece counts next to holdings
4223 string[1] = NULLCHAR;
4224 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4225 string[0] = '0' + piece;
4226 XTextExtents(countFontStruct, string, 1, &direction,
4227 &font_ascent, &font_descent, &overall);
4228 if (appData.monoMode) {
4229 XDrawImageString(xDisplay, xBoardWindow, countGC,
4230 x + squareSize - overall.width - 2,
4231 y + font_ascent + 1, string, 1);
4233 XDrawString(xDisplay, xBoardWindow, countGC,
4234 x + squareSize - overall.width - 2,
4235 y + font_ascent + 1, string, 1);
4238 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4239 string[0] = '0' + piece;
4240 XTextExtents(countFontStruct, string, 1, &direction,
4241 &font_ascent, &font_descent, &overall);
4242 if (appData.monoMode) {
4243 XDrawImageString(xDisplay, xBoardWindow, countGC,
4244 x + 2, y + font_ascent + 1, string, 1);
4246 XDrawString(xDisplay, xBoardWindow, countGC,
4247 x + 2, y + font_ascent + 1, string, 1);
4251 if (piece == EmptySquare || appData.blindfold) {
4252 BlankSquare(x, y, square_color, piece, xBoardWindow);
4254 drawfunc = ChooseDrawFunc();
4255 if (do_flash && appData.flashCount > 0) {
4256 for (i=0; i<appData.flashCount; ++i) {
4258 drawfunc(piece, square_color, x, y, xBoardWindow);
4259 XSync(xDisplay, False);
4260 do_flash_delay(flash_delay);
4262 BlankSquare(x, y, square_color, piece, xBoardWindow);
4263 XSync(xDisplay, False);
4264 do_flash_delay(flash_delay);
4267 drawfunc(piece, square_color, x, y, xBoardWindow);
4271 string[1] = NULLCHAR;
4272 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4273 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4274 string[0] = 'a' + column - BOARD_LEFT;
4275 XTextExtents(coordFontStruct, string, 1, &direction,
4276 &font_ascent, &font_descent, &overall);
4277 if (appData.monoMode) {
4278 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4279 x + squareSize - overall.width - 2,
4280 y + squareSize - font_descent - 1, string, 1);
4282 XDrawString(xDisplay, xBoardWindow, coordGC,
4283 x + squareSize - overall.width - 2,
4284 y + squareSize - font_descent - 1, string, 1);
4287 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4288 string[0] = ONE + row;
4289 XTextExtents(coordFontStruct, string, 1, &direction,
4290 &font_ascent, &font_descent, &overall);
4291 if (appData.monoMode) {
4292 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4293 x + 2, y + font_ascent + 1, string, 1);
4295 XDrawString(xDisplay, xBoardWindow, coordGC,
4296 x + 2, y + font_ascent + 1, string, 1);
4299 if(!partnerUp && marker[row][column]) {
4300 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4301 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4306 /* Why is this needed on some versions of X? */
4307 void EventProc(widget, unused, event)
4312 if (!XtIsRealized(widget))
4315 switch (event->type) {
4317 if (event->xexpose.count > 0) return; /* no clipping is done */
4318 XDrawPosition(widget, True, NULL);
4319 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4320 flipView = !flipView; partnerUp = !partnerUp;
4321 XDrawPosition(widget, True, NULL);
4322 flipView = !flipView; partnerUp = !partnerUp;
4326 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4333 void DrawPosition(fullRedraw, board)
4334 /*Boolean*/int fullRedraw;
4337 XDrawPosition(boardWidget, fullRedraw, board);
4340 /* Returns 1 if there are "too many" differences between b1 and b2
4341 (i.e. more than 1 move was made) */
4342 static int too_many_diffs(b1, b2)
4348 for (i=0; i<BOARD_HEIGHT; ++i) {
4349 for (j=0; j<BOARD_WIDTH; ++j) {
4350 if (b1[i][j] != b2[i][j]) {
4351 if (++c > 4) /* Castling causes 4 diffs */
4360 /* Matrix describing castling maneuvers */
4361 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4362 static int castling_matrix[4][5] = {
4363 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4364 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4365 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4366 { 7, 7, 4, 5, 6 } /* 0-0, black */
4369 /* Checks whether castling occurred. If it did, *rrow and *rcol
4370 are set to the destination (row,col) of the rook that moved.
4372 Returns 1 if castling occurred, 0 if not.
4374 Note: Only handles a max of 1 castling move, so be sure
4375 to call too_many_diffs() first.
4377 static int check_castle_draw(newb, oldb, rrow, rcol)
4384 /* For each type of castling... */
4385 for (i=0; i<4; ++i) {
4386 r = castling_matrix[i];
4388 /* Check the 4 squares involved in the castling move */
4390 for (j=1; j<=4; ++j) {
4391 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4398 /* All 4 changed, so it must be a castling move */
4407 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4408 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4410 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4413 void DrawSeekBackground( int left, int top, int right, int bottom )
4415 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4418 void DrawSeekText(char *buf, int x, int y)
4420 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4423 void DrawSeekDot(int x, int y, int colorNr)
4425 int square = colorNr & 0x80;
4428 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4430 XFillRectangle(xDisplay, xBoardWindow, color,
4431 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4433 XFillArc(xDisplay, xBoardWindow, color,
4434 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4437 static int damage[2][BOARD_RANKS][BOARD_FILES];
4440 * event handler for redrawing the board
4442 void XDrawPosition(w, repaint, board)
4444 /*Boolean*/int repaint;
4448 static int lastFlipView = 0;
4449 static int lastBoardValid[2] = {0, 0};
4450 static Board lastBoard[2];
4453 int nr = twoBoards*partnerUp;
4455 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4457 if (board == NULL) {
4458 if (!lastBoardValid) return;
4459 board = lastBoard[nr];
4461 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4462 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4463 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4468 * It would be simpler to clear the window with XClearWindow()
4469 * but this causes a very distracting flicker.
4472 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4474 /* If too much changes (begin observing new game, etc.), don't
4476 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4478 /* Special check for castling so we don't flash both the king
4479 and the rook (just flash the king). */
4481 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4482 /* Draw rook with NO flashing. King will be drawn flashing later */
4483 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4484 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4488 /* First pass -- Draw (newly) empty squares and repair damage.
4489 This prevents you from having a piece show up twice while it
4490 is flashing on its new square */
4491 for (i = 0; i < BOARD_HEIGHT; i++)
4492 for (j = 0; j < BOARD_WIDTH; j++)
4493 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4494 || damage[nr][i][j]) {
4495 DrawSquare(i, j, board[i][j], 0);
4496 damage[nr][i][j] = False;
4499 /* Second pass -- Draw piece(s) in new position and flash them */
4500 for (i = 0; i < BOARD_HEIGHT; i++)
4501 for (j = 0; j < BOARD_WIDTH; j++)
4502 if (board[i][j] != lastBoard[nr][i][j]) {
4503 DrawSquare(i, j, board[i][j], do_flash);
4507 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4508 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4509 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4511 for (i = 0; i < BOARD_HEIGHT; i++)
4512 for (j = 0; j < BOARD_WIDTH; j++) {
4513 DrawSquare(i, j, board[i][j], 0);
4514 damage[nr][i][j] = False;
4518 CopyBoard(lastBoard[nr], board);
4519 lastBoardValid[nr] = 1;
4520 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4521 lastFlipView = flipView;
4523 /* Draw highlights */
4524 if (pm1X >= 0 && pm1Y >= 0) {
4525 drawHighlight(pm1X, pm1Y, prelineGC);
4527 if (pm2X >= 0 && pm2Y >= 0) {
4528 drawHighlight(pm2X, pm2Y, prelineGC);
4530 if (hi1X >= 0 && hi1Y >= 0) {
4531 drawHighlight(hi1X, hi1Y, highlineGC);
4533 if (hi2X >= 0 && hi2Y >= 0) {
4534 drawHighlight(hi2X, hi2Y, highlineGC);
4537 /* If piece being dragged around board, must redraw that too */
4540 XSync(xDisplay, False);
4545 * event handler for redrawing the board
4547 void DrawPositionProc(w, event, prms, nprms)
4553 XDrawPosition(w, True, NULL);
4558 * event handler for parsing user moves
4560 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4561 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4562 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4563 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4564 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4565 // and at the end FinishMove() to perform the move after optional promotion popups.
4566 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4567 void HandleUserMove(w, event, prms, nprms)
4573 if (w != boardWidget || errorExitStatus != -1) return;
4576 if (event->type == ButtonPress) {
4577 XtPopdown(promotionShell);
4578 XtDestroyWidget(promotionShell);
4579 promotionUp = False;
4587 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4588 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4589 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4592 void AnimateUserMove (Widget w, XEvent * event,
4593 String * params, Cardinal * nParams)
4595 DragPieceMove(event->xmotion.x, event->xmotion.y);
4598 void HandlePV (Widget w, XEvent * event,
4599 String * params, Cardinal * nParams)
4600 { // [HGM] pv: walk PV
4601 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4604 Widget CommentCreate(name, text, mutable, callback, lines)
4606 int /*Boolean*/ mutable;
4607 XtCallbackProc callback;
4611 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4616 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4617 XtGetValues(boardWidget, args, j);
4620 XtSetArg(args[j], XtNresizable, True); j++;
4623 XtCreatePopupShell(name, topLevelShellWidgetClass,
4624 shellWidget, args, j);
4627 XtCreatePopupShell(name, transientShellWidgetClass,
4628 shellWidget, args, j);
4631 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4632 layoutArgs, XtNumber(layoutArgs));
4634 XtCreateManagedWidget("form", formWidgetClass, layout,
4635 formArgs, XtNumber(formArgs));
4639 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4640 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4642 XtSetArg(args[j], XtNstring, text); j++;
4643 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4644 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4645 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4646 XtSetArg(args[j], XtNright, XtChainRight); j++;
4647 XtSetArg(args[j], XtNresizable, True); j++;
4648 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4649 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4650 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4651 XtSetArg(args[j], XtNautoFill, True); j++;
4652 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4654 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4655 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4659 XtSetArg(args[j], XtNfromVert, edit); j++;
4660 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4661 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4662 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4663 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4665 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4666 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4669 XtSetArg(args[j], XtNfromVert, edit); j++;
4670 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4671 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4672 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4673 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4674 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4676 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4677 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4680 XtSetArg(args[j], XtNfromVert, edit); j++;
4681 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4682 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4683 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4684 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4685 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4687 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4688 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4691 XtSetArg(args[j], XtNfromVert, edit); j++;
4692 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4693 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4694 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4695 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4697 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4698 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4701 XtSetArg(args[j], XtNfromVert, edit); j++;
4702 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4703 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4704 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4705 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4706 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4708 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4709 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4712 XtRealizeWidget(shell);
4714 if (commentX == -1) {
4717 Dimension pw_height;
4718 Dimension ew_height;
4721 XtSetArg(args[j], XtNheight, &ew_height); j++;
4722 XtGetValues(edit, args, j);
4725 XtSetArg(args[j], XtNheight, &pw_height); j++;
4726 XtGetValues(shell, args, j);
4727 commentH = pw_height + (lines - 1) * ew_height;
4728 commentW = bw_width - 16;
4730 XSync(xDisplay, False);
4732 /* This code seems to tickle an X bug if it is executed too soon
4733 after xboard starts up. The coordinates get transformed as if
4734 the main window was positioned at (0, 0).
4736 XtTranslateCoords(shellWidget,
4737 (bw_width - commentW) / 2, 0 - commentH / 2,
4738 &commentX, &commentY);
4740 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4741 RootWindowOfScreen(XtScreen(shellWidget)),
4742 (bw_width - commentW) / 2, 0 - commentH / 2,
4747 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4750 if(wpComment.width > 0) {
4751 commentX = wpComment.x;
4752 commentY = wpComment.y;
4753 commentW = wpComment.width;
4754 commentH = wpComment.height;
4758 XtSetArg(args[j], XtNheight, commentH); j++;
4759 XtSetArg(args[j], XtNwidth, commentW); j++;
4760 XtSetArg(args[j], XtNx, commentX); j++;
4761 XtSetArg(args[j], XtNy, commentY); j++;
4762 XtSetValues(shell, args, j);
4763 XtSetKeyboardFocus(shell, edit);
4768 /* Used for analysis window and ICS input window */
4769 Widget MiscCreate(name, text, mutable, callback, lines)
4771 int /*Boolean*/ mutable;
4772 XtCallbackProc callback;
4776 Widget shell, layout, form, edit;
4778 Dimension bw_width, pw_height, ew_height, w, h;
4784 XtSetArg(args[j], XtNresizable, True); j++;
4787 XtCreatePopupShell(name, topLevelShellWidgetClass,
4788 shellWidget, args, j);
4791 XtCreatePopupShell(name, transientShellWidgetClass,
4792 shellWidget, args, j);
4795 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4796 layoutArgs, XtNumber(layoutArgs));
4798 XtCreateManagedWidget("form", formWidgetClass, layout,
4799 formArgs, XtNumber(formArgs));
4803 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4804 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4806 XtSetArg(args[j], XtNstring, text); j++;
4807 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4808 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4809 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4810 XtSetArg(args[j], XtNright, XtChainRight); j++;
4811 XtSetArg(args[j], XtNresizable, True); j++;
4812 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4813 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4814 XtSetArg(args[j], XtNautoFill, True); j++;
4815 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4817 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4819 XtRealizeWidget(shell);
4822 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4823 XtGetValues(boardWidget, args, j);
4826 XtSetArg(args[j], XtNheight, &ew_height); j++;
4827 XtGetValues(edit, args, j);
4830 XtSetArg(args[j], XtNheight, &pw_height); j++;
4831 XtGetValues(shell, args, j);
4832 h = pw_height + (lines - 1) * ew_height;
4835 XSync(xDisplay, False);
4837 /* This code seems to tickle an X bug if it is executed too soon
4838 after xboard starts up. The coordinates get transformed as if
4839 the main window was positioned at (0, 0).
4841 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4843 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4844 RootWindowOfScreen(XtScreen(shellWidget)),
4845 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4849 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4852 XtSetArg(args[j], XtNheight, h); j++;
4853 XtSetArg(args[j], XtNwidth, w); j++;
4854 XtSetArg(args[j], XtNx, x); j++;
4855 XtSetArg(args[j], XtNy, y); j++;
4856 XtSetValues(shell, args, j);
4862 static int savedIndex; /* gross that this is global */
4864 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4867 XawTextPosition index, dummy;
4870 XawTextGetSelectionPos(w, &index, &dummy);
4871 XtSetArg(arg, XtNstring, &val);
4872 XtGetValues(w, &arg, 1);
4873 ReplaceComment(savedIndex, val);
4874 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4875 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4878 void EditCommentPopUp(index, title, text)
4887 if (text == NULL) text = "";
4889 if (editShell == NULL) {
4891 CommentCreate(title, text, True, EditCommentCallback, 4);
4892 XtRealizeWidget(editShell);
4893 CatchDeleteWindow(editShell, "EditCommentPopDown");
4895 edit = XtNameToWidget(editShell, "*form.text");
4897 XtSetArg(args[j], XtNstring, text); j++;
4898 XtSetValues(edit, args, j);
4900 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4901 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4902 XtSetValues(editShell, args, j);
4905 XtPopup(editShell, XtGrabNone);
4909 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4910 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4914 void EditCommentCallback(w, client_data, call_data)
4916 XtPointer client_data, call_data;
4924 XtSetArg(args[j], XtNlabel, &name); j++;
4925 XtGetValues(w, args, j);
4927 if (strcmp(name, _("ok")) == 0) {
4928 edit = XtNameToWidget(editShell, "*form.text");
4930 XtSetArg(args[j], XtNstring, &val); j++;
4931 XtGetValues(edit, args, j);
4932 ReplaceComment(savedIndex, val);
4933 EditCommentPopDown();
4934 } else if (strcmp(name, _("cancel")) == 0) {
4935 EditCommentPopDown();
4936 } else if (strcmp(name, _("clear")) == 0) {
4937 edit = XtNameToWidget(editShell, "*form.text");
4938 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4939 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4943 void EditCommentPopDown()
4948 if (!editUp) return;
4950 XtSetArg(args[j], XtNx, &commentX); j++;
4951 XtSetArg(args[j], XtNy, &commentY); j++;
4952 XtSetArg(args[j], XtNheight, &commentH); j++;
4953 XtSetArg(args[j], XtNwidth, &commentW); j++;
4954 XtGetValues(editShell, args, j);
4955 XtPopdown(editShell);
4958 XtSetArg(args[j], XtNleftBitmap, None); j++;
4959 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4963 void ICSInputBoxPopUp()
4968 char *title = _("ICS Input");
4971 if (ICSInputShell == NULL) {
4972 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4973 tr = XtParseTranslationTable(ICSInputTranslations);
4974 edit = XtNameToWidget(ICSInputShell, "*form.text");
4975 XtOverrideTranslations(edit, tr);
4976 XtRealizeWidget(ICSInputShell);
4977 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4980 edit = XtNameToWidget(ICSInputShell, "*form.text");
4982 XtSetArg(args[j], XtNstring, ""); j++;
4983 XtSetValues(edit, args, j);
4985 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4986 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4987 XtSetValues(ICSInputShell, args, j);
4990 XtPopup(ICSInputShell, XtGrabNone);
4991 XtSetKeyboardFocus(ICSInputShell, edit);
4993 ICSInputBoxUp = True;
4995 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4996 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5000 void ICSInputSendText()
5007 edit = XtNameToWidget(ICSInputShell, "*form.text");
5009 XtSetArg(args[j], XtNstring, &val); j++;
5010 XtGetValues(edit, args, j);
5012 SendMultiLineToICS(val);
5013 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5014 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5017 void ICSInputBoxPopDown()
5022 if (!ICSInputBoxUp) return;
5024 XtPopdown(ICSInputShell);
5025 ICSInputBoxUp = False;
5027 XtSetArg(args[j], XtNleftBitmap, None); j++;
5028 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5032 void CommentPopUp(title, text)
5039 savedIndex = currentMove; // [HGM] vari
5040 if (commentShell == NULL) {
5042 CommentCreate(title, text, False, CommentCallback, 4);
5043 XtRealizeWidget(commentShell);
5044 CatchDeleteWindow(commentShell, "CommentPopDown");
5046 edit = XtNameToWidget(commentShell, "*form.text");
5048 XtSetArg(args[j], XtNstring, text); j++;
5049 XtSetValues(edit, args, j);
5051 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5052 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5053 XtSetValues(commentShell, args, j);
5056 XtPopup(commentShell, XtGrabNone);
5057 XSync(xDisplay, False);
5062 void CommentCallback(w, client_data, call_data)
5064 XtPointer client_data, call_data;
5071 XtSetArg(args[j], XtNlabel, &name); j++;
5072 XtGetValues(w, args, j);
5074 if (strcmp(name, _("close")) == 0) {
5076 } else if (strcmp(name, _("edit")) == 0) {
5083 void CommentPopDown()
5088 if (!commentUp) return;
5090 XtSetArg(args[j], XtNx, &commentX); j++;
5091 XtSetArg(args[j], XtNy, &commentY); j++;
5092 XtSetArg(args[j], XtNwidth, &commentW); j++;
5093 XtSetArg(args[j], XtNheight, &commentH); j++;
5094 XtGetValues(commentShell, args, j);
5095 XtPopdown(commentShell);
5096 XSync(xDisplay, False);
5100 void FileNamePopUp(label, def, proc, openMode)
5107 Widget popup, layout, dialog, edit;
5113 fileProc = proc; /* I can't see a way not */
5114 fileOpenMode = openMode; /* to use globals here */
5115 { // [HGM] use file-selector dialog stolen from Ghostview
5117 int index; // this is not supported yet
5119 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5120 NULL, openMode, NULL, &name))
5121 (void) (*fileProc)(f, index=0, name);
5125 void FileNamePopDown()
5127 if (!filenameUp) return;
5128 XtPopdown(fileNameShell);
5129 XtDestroyWidget(fileNameShell);
5134 void FileNameCallback(w, client_data, call_data)
5136 XtPointer client_data, call_data;
5141 XtSetArg(args[0], XtNlabel, &name);
5142 XtGetValues(w, args, 1);
5144 if (strcmp(name, _("cancel")) == 0) {
5149 FileNameAction(w, NULL, NULL, NULL);
5152 void FileNameAction(w, event, prms, nprms)
5164 name = XawDialogGetValueString(w = XtParent(w));
5166 if ((name != NULL) && (*name != NULLCHAR)) {
5168 XtPopdown(w = XtParent(XtParent(w)));
5172 p = strrchr(buf, ' ');
5179 fullname = ExpandPathName(buf);
5181 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5184 f = fopen(fullname, fileOpenMode);
5186 DisplayError(_("Failed to open file"), errno);
5188 (void) (*fileProc)(f, index, buf);
5195 XtPopdown(w = XtParent(XtParent(w)));
5201 void PromotionPopUp()
5204 Widget dialog, layout;
5206 Dimension bw_width, pw_width;
5210 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5211 XtGetValues(boardWidget, args, j);
5214 XtSetArg(args[j], XtNresizable, True); j++;
5215 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5217 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5218 shellWidget, args, j);
5220 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5221 layoutArgs, XtNumber(layoutArgs));
5224 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5225 XtSetArg(args[j], XtNborderWidth, 0); j++;
5226 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5229 if(gameInfo.variant != VariantShogi) {
5230 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5231 (XtPointer) dialog);
5232 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5233 (XtPointer) dialog);
5234 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5235 (XtPointer) dialog);
5236 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5237 (XtPointer) dialog);
5238 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5239 gameInfo.variant == VariantGiveaway) {
5240 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5241 (XtPointer) dialog);
5243 if(gameInfo.variant == VariantCapablanca ||
5244 gameInfo.variant == VariantGothic ||
5245 gameInfo.variant == VariantCapaRandom) {
5246 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5247 (XtPointer) dialog);
5248 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5249 (XtPointer) dialog);
5251 } else // [HGM] shogi
5253 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5254 (XtPointer) dialog);
5255 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5256 (XtPointer) dialog);
5258 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5259 (XtPointer) dialog);
5261 XtRealizeWidget(promotionShell);
5262 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5265 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5266 XtGetValues(promotionShell, args, j);
5268 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5269 lineGap + squareSize/3 +
5270 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5271 0 : 6*(squareSize + lineGap)), &x, &y);
5274 XtSetArg(args[j], XtNx, x); j++;
5275 XtSetArg(args[j], XtNy, y); j++;
5276 XtSetValues(promotionShell, args, j);
5278 XtPopup(promotionShell, XtGrabNone);
5283 void PromotionPopDown()
5285 if (!promotionUp) return;
5286 XtPopdown(promotionShell);
5287 XtDestroyWidget(promotionShell);
5288 promotionUp = False;
5291 void PromotionCallback(w, client_data, call_data)
5293 XtPointer client_data, call_data;
5299 XtSetArg(args[0], XtNlabel, &name);
5300 XtGetValues(w, args, 1);
5304 if (fromX == -1) return;
5306 if (strcmp(name, _("cancel")) == 0) {
5310 } else if (strcmp(name, _("Knight")) == 0) {
5312 } else if (strcmp(name, _("Promote")) == 0) {
5314 } else if (strcmp(name, _("Defer")) == 0) {
5317 promoChar = ToLower(name[0]);
5320 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5322 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5323 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5328 void ErrorCallback(w, client_data, call_data)
5330 XtPointer client_data, call_data;
5333 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5335 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5341 if (!errorUp) return;
5343 XtPopdown(errorShell);
5344 XtDestroyWidget(errorShell);
5345 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5348 void ErrorPopUp(title, label, modal)
5349 char *title, *label;
5353 Widget dialog, layout;
5357 Dimension bw_width, pw_width;
5358 Dimension pw_height;
5362 XtSetArg(args[i], XtNresizable, True); i++;
5363 XtSetArg(args[i], XtNtitle, title); i++;
5365 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5366 shellWidget, args, i);
5368 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5369 layoutArgs, XtNumber(layoutArgs));
5372 XtSetArg(args[i], XtNlabel, label); i++;
5373 XtSetArg(args[i], XtNborderWidth, 0); i++;
5374 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5377 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5379 XtRealizeWidget(errorShell);
5380 CatchDeleteWindow(errorShell, "ErrorPopDown");
5383 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5384 XtGetValues(boardWidget, args, i);
5386 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5387 XtSetArg(args[i], XtNheight, &pw_height); i++;
5388 XtGetValues(errorShell, args, i);
5391 /* This code seems to tickle an X bug if it is executed too soon
5392 after xboard starts up. The coordinates get transformed as if
5393 the main window was positioned at (0, 0).
5395 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5396 0 - pw_height + squareSize / 3, &x, &y);
5398 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5399 RootWindowOfScreen(XtScreen(boardWidget)),
5400 (bw_width - pw_width) / 2,
5401 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5405 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5408 XtSetArg(args[i], XtNx, x); i++;
5409 XtSetArg(args[i], XtNy, y); i++;
5410 XtSetValues(errorShell, args, i);
5413 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5416 /* Disable all user input other than deleting the window */
5417 static int frozen = 0;
5421 /* Grab by a widget that doesn't accept input */
5422 XtAddGrab(messageWidget, TRUE, FALSE);
5426 /* Undo a FreezeUI */
5429 if (!frozen) return;
5430 XtRemoveGrab(messageWidget);
5434 char *ModeToWidgetName(mode)
5438 case BeginningOfGame:
5439 if (appData.icsActive)
5440 return "menuMode.ICS Client";
5441 else if (appData.noChessProgram ||
5442 *appData.cmailGameName != NULLCHAR)
5443 return "menuMode.Edit Game";
5445 return "menuMode.Machine Black";
5446 case MachinePlaysBlack:
5447 return "menuMode.Machine Black";
5448 case MachinePlaysWhite:
5449 return "menuMode.Machine White";
5451 return "menuMode.Analysis Mode";
5453 return "menuMode.Analyze File";
5454 case TwoMachinesPlay:
5455 return "menuMode.Two Machines";
5457 return "menuMode.Edit Game";
5458 case PlayFromGameFile:
5459 return "menuFile.Load Game";
5461 return "menuMode.Edit Position";
5463 return "menuMode.Training";
5464 case IcsPlayingWhite:
5465 case IcsPlayingBlack:
5469 return "menuMode.ICS Client";
5476 void ModeHighlight()
5479 static int oldPausing = FALSE;
5480 static GameMode oldmode = (GameMode) -1;
5483 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5485 if (pausing != oldPausing) {
5486 oldPausing = pausing;
5488 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5490 XtSetArg(args[0], XtNleftBitmap, None);
5492 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5495 if (appData.showButtonBar) {
5496 /* Always toggle, don't set. Previous code messes up when
5497 invoked while the button is pressed, as releasing it
5498 toggles the state again. */
5501 XtSetArg(args[0], XtNbackground, &oldbg);
5502 XtSetArg(args[1], XtNforeground, &oldfg);
5503 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5505 XtSetArg(args[0], XtNbackground, oldfg);
5506 XtSetArg(args[1], XtNforeground, oldbg);
5508 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5512 wname = ModeToWidgetName(oldmode);
5513 if (wname != NULL) {
5514 XtSetArg(args[0], XtNleftBitmap, None);
5515 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5517 wname = ModeToWidgetName(gameMode);
5518 if (wname != NULL) {
5519 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5520 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5524 /* Maybe all the enables should be handled here, not just this one */
5525 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5526 gameMode == Training || gameMode == PlayFromGameFile);
5531 * Button/menu procedures
5533 void ResetProc(w, event, prms, nprms)
5542 int LoadGamePopUp(f, gameNumber, title)
5547 cmailMsgLoaded = FALSE;
5548 if (gameNumber == 0) {
5549 int error = GameListBuild(f);
5551 DisplayError(_("Cannot build game list"), error);
5552 } else if (!ListEmpty(&gameList) &&
5553 ((ListGame *) gameList.tailPred)->number > 1) {
5554 GameListPopUp(f, title);
5560 return LoadGame(f, gameNumber, title, FALSE);
5563 void LoadGameProc(w, event, prms, nprms)
5569 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5572 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5575 void LoadNextGameProc(w, event, prms, nprms)
5584 void LoadPrevGameProc(w, event, prms, nprms)
5593 void ReloadGameProc(w, event, prms, nprms)
5602 void LoadNextPositionProc(w, event, prms, nprms)
5611 void LoadPrevPositionProc(w, event, prms, nprms)
5620 void ReloadPositionProc(w, event, prms, nprms)
5629 void LoadPositionProc(w, event, prms, nprms)
5635 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5638 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5641 void SaveGameProc(w, event, prms, nprms)
5647 FileNamePopUp(_("Save game file name?"),
5648 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5652 void SavePositionProc(w, event, prms, nprms)
5658 FileNamePopUp(_("Save position file name?"),
5659 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5663 void ReloadCmailMsgProc(w, event, prms, nprms)
5669 ReloadCmailMsgEvent(FALSE);
5672 void MailMoveProc(w, event, prms, nprms)
5681 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5682 char *selected_fen_position=NULL;
5685 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5686 Atom *type_return, XtPointer *value_return,
5687 unsigned long *length_return, int *format_return)
5689 char *selection_tmp;
5691 if (!selected_fen_position) return False; /* should never happen */
5692 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5693 /* note: since no XtSelectionDoneProc was registered, Xt will
5694 * automatically call XtFree on the value returned. So have to
5695 * make a copy of it allocated with XtMalloc */
5696 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5697 strcpy(selection_tmp, selected_fen_position);
5699 *value_return=selection_tmp;
5700 *length_return=strlen(selection_tmp);
5701 *type_return=*target;
5702 *format_return = 8; /* bits per byte */
5704 } else if (*target == XA_TARGETS(xDisplay)) {
5705 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5706 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5707 targets_tmp[1] = XA_STRING;
5708 *value_return = targets_tmp;
5709 *type_return = XA_ATOM;
5711 *format_return = 8 * sizeof(Atom);
5712 if (*format_return > 32) {
5713 *length_return *= *format_return / 32;
5714 *format_return = 32;
5722 /* note: when called from menu all parameters are NULL, so no clue what the
5723 * Widget which was clicked on was, or what the click event was
5725 void CopyPositionProc(w, event, prms, nprms)
5732 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5733 * have a notion of a position that is selected but not copied.
5734 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5736 if(gameMode == EditPosition) EditPositionDone(TRUE);
5737 if (selected_fen_position) free(selected_fen_position);
5738 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5739 if (!selected_fen_position) return;
5740 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5742 SendPositionSelection,
5743 NULL/* lose_ownership_proc */ ,
5744 NULL/* transfer_done_proc */);
5745 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5747 SendPositionSelection,
5748 NULL/* lose_ownership_proc */ ,
5749 NULL/* transfer_done_proc */);
5752 /* function called when the data to Paste is ready */
5754 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5755 Atom *type, XtPointer value, unsigned long *len, int *format)
5758 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5759 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5760 EditPositionPasteFEN(fenstr);
5764 /* called when Paste Position button is pressed,
5765 * all parameters will be NULL */
5766 void PastePositionProc(w, event, prms, nprms)
5772 XtGetSelectionValue(menuBarWidget,
5773 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5774 /* (XtSelectionCallbackProc) */ PastePositionCB,
5775 NULL, /* client_data passed to PastePositionCB */
5777 /* better to use the time field from the event that triggered the
5778 * call to this function, but that isn't trivial to get
5786 SendGameSelection(Widget w, Atom *selection, Atom *target,
5787 Atom *type_return, XtPointer *value_return,
5788 unsigned long *length_return, int *format_return)
5790 char *selection_tmp;
5792 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5793 FILE* f = fopen(gameCopyFilename, "r");
5796 if (f == NULL) return False;
5800 selection_tmp = XtMalloc(len + 1);
5801 count = fread(selection_tmp, 1, len, f);
5803 XtFree(selection_tmp);
5806 selection_tmp[len] = NULLCHAR;
5807 *value_return = selection_tmp;
5808 *length_return = len;
5809 *type_return = *target;
5810 *format_return = 8; /* bits per byte */
5812 } else if (*target == XA_TARGETS(xDisplay)) {
5813 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5814 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5815 targets_tmp[1] = XA_STRING;
5816 *value_return = targets_tmp;
5817 *type_return = XA_ATOM;
5819 *format_return = 8 * sizeof(Atom);
5820 if (*format_return > 32) {
5821 *length_return *= *format_return / 32;
5822 *format_return = 32;
5830 /* note: when called from menu all parameters are NULL, so no clue what the
5831 * Widget which was clicked on was, or what the click event was
5833 void CopyGameProc(w, event, prms, nprms)
5841 ret = SaveGameToFile(gameCopyFilename, FALSE);
5845 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5846 * have a notion of a game that is selected but not copied.
5847 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5849 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5852 NULL/* lose_ownership_proc */ ,
5853 NULL/* transfer_done_proc */);
5854 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5857 NULL/* lose_ownership_proc */ ,
5858 NULL/* transfer_done_proc */);
5861 /* function called when the data to Paste is ready */
5863 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5864 Atom *type, XtPointer value, unsigned long *len, int *format)
5867 if (value == NULL || *len == 0) {
5868 return; /* nothing had been selected to copy */
5870 f = fopen(gamePasteFilename, "w");
5872 DisplayError(_("Can't open temp file"), errno);
5875 fwrite(value, 1, *len, f);
5878 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5881 /* called when Paste Game button is pressed,
5882 * all parameters will be NULL */
5883 void PasteGameProc(w, event, prms, nprms)
5889 XtGetSelectionValue(menuBarWidget,
5890 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5891 /* (XtSelectionCallbackProc) */ PasteGameCB,
5892 NULL, /* client_data passed to PasteGameCB */
5894 /* better to use the time field from the event that triggered the
5895 * call to this function, but that isn't trivial to get
5905 SaveGameProc(NULL, NULL, NULL, NULL);
5909 void QuitProc(w, event, prms, nprms)
5918 void PauseProc(w, event, prms, nprms)
5928 void MachineBlackProc(w, event, prms, nprms)
5934 MachineBlackEvent();
5937 void MachineWhiteProc(w, event, prms, nprms)
5943 MachineWhiteEvent();
5946 void AnalyzeModeProc(w, event, prms, nprms)
5954 if (!first.analysisSupport) {
5955 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5956 DisplayError(buf, 0);
5959 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5960 if (appData.icsActive) {
5961 if (gameMode != IcsObserving) {
5962 sprintf(buf,_("You are not observing a game"));
5963 DisplayError(buf, 0);
5965 if (appData.icsEngineAnalyze) {
5966 if (appData.debugMode)
5967 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5973 /* if enable, use want disable icsEngineAnalyze */
5974 if (appData.icsEngineAnalyze) {
5979 appData.icsEngineAnalyze = TRUE;
5980 if (appData.debugMode)
5981 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5983 if (!appData.showThinking)
5984 ShowThinkingProc(w,event,prms,nprms);
5989 void AnalyzeFileProc(w, event, prms, nprms)
5995 if (!first.analysisSupport) {
5997 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5998 DisplayError(buf, 0);
6003 if (!appData.showThinking)
6004 ShowThinkingProc(w,event,prms,nprms);
6007 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6008 AnalysisPeriodicEvent(1);
6011 void TwoMachinesProc(w, event, prms, nprms)
6020 void IcsClientProc(w, event, prms, nprms)
6029 void EditGameProc(w, event, prms, nprms)
6038 void EditPositionProc(w, event, prms, nprms)
6044 EditPositionEvent();
6047 void TrainingProc(w, event, prms, nprms)
6056 void EditCommentProc(w, event, prms, nprms)
6063 EditCommentPopDown();
6069 void IcsInputBoxProc(w, event, prms, nprms)
6075 if (ICSInputBoxUp) {
6076 ICSInputBoxPopDown();
6082 void AcceptProc(w, event, prms, nprms)
6091 void DeclineProc(w, event, prms, nprms)
6100 void RematchProc(w, event, prms, nprms)
6109 void CallFlagProc(w, event, prms, nprms)
6118 void DrawProc(w, event, prms, nprms)
6127 void AbortProc(w, event, prms, nprms)
6136 void AdjournProc(w, event, prms, nprms)
6145 void ResignProc(w, event, prms, nprms)
6154 void AdjuWhiteProc(w, event, prms, nprms)
6160 UserAdjudicationEvent(+1);
6163 void AdjuBlackProc(w, event, prms, nprms)
6169 UserAdjudicationEvent(-1);
6172 void AdjuDrawProc(w, event, prms, nprms)
6178 UserAdjudicationEvent(0);
6181 void EnterKeyProc(w, event, prms, nprms)
6187 if (ICSInputBoxUp == True)
6191 void UpKeyProc(w, event, prms, nprms)
6196 { // [HGM] input: let up-arrow recall previous line from history
6203 if (!ICSInputBoxUp) return;
6204 edit = XtNameToWidget(ICSInputShell, "*form.text");
6206 XtSetArg(args[j], XtNstring, &val); j++;
6207 XtGetValues(edit, args, j);
6208 val = PrevInHistory(val);
6209 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6210 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6212 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6213 XawTextReplace(edit, 0, 0, &t);
6214 XawTextSetInsertionPoint(edit, 9999);
6218 void DownKeyProc(w, event, prms, nprms)
6223 { // [HGM] input: let down-arrow recall next line from history
6228 if (!ICSInputBoxUp) return;
6229 edit = XtNameToWidget(ICSInputShell, "*form.text");
6230 val = NextInHistory();
6231 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6232 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6234 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6235 XawTextReplace(edit, 0, 0, &t);
6236 XawTextSetInsertionPoint(edit, 9999);
6240 void StopObservingProc(w, event, prms, nprms)
6246 StopObservingEvent();
6249 void StopExaminingProc(w, event, prms, nprms)
6255 StopExaminingEvent();
6258 void UploadProc(w, event, prms, nprms)
6268 void ForwardProc(w, event, prms, nprms)
6278 void BackwardProc(w, event, prms, nprms)
6287 void ToStartProc(w, event, prms, nprms)
6296 void ToEndProc(w, event, prms, nprms)
6305 void RevertProc(w, event, prms, nprms)
6314 void AnnotateProc(w, event, prms, nprms)
6323 void TruncateGameProc(w, event, prms, nprms)
6329 TruncateGameEvent();
6331 void RetractMoveProc(w, event, prms, nprms)
6340 void MoveNowProc(w, event, prms, nprms)
6350 void AlwaysQueenProc(w, event, prms, nprms)
6358 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6360 if (appData.alwaysPromoteToQueen) {
6361 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6363 XtSetArg(args[0], XtNleftBitmap, None);
6365 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6369 void AnimateDraggingProc(w, event, prms, nprms)
6377 appData.animateDragging = !appData.animateDragging;
6379 if (appData.animateDragging) {
6380 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6383 XtSetArg(args[0], XtNleftBitmap, None);
6385 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6389 void AnimateMovingProc(w, event, prms, nprms)
6397 appData.animate = !appData.animate;
6399 if (appData.animate) {
6400 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6403 XtSetArg(args[0], XtNleftBitmap, None);
6405 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6409 void AutocommProc(w, event, prms, nprms)
6417 appData.autoComment = !appData.autoComment;
6419 if (appData.autoComment) {
6420 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6422 XtSetArg(args[0], XtNleftBitmap, None);
6424 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6429 void AutoflagProc(w, event, prms, nprms)
6437 appData.autoCallFlag = !appData.autoCallFlag;
6439 if (appData.autoCallFlag) {
6440 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6442 XtSetArg(args[0], XtNleftBitmap, None);
6444 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6448 void AutoflipProc(w, event, prms, nprms)
6456 appData.autoFlipView = !appData.autoFlipView;
6458 if (appData.autoFlipView) {
6459 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6461 XtSetArg(args[0], XtNleftBitmap, None);
6463 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6467 void AutobsProc(w, event, prms, nprms)
6475 appData.autoObserve = !appData.autoObserve;
6477 if (appData.autoObserve) {
6478 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6480 XtSetArg(args[0], XtNleftBitmap, None);
6482 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6486 void AutoraiseProc(w, event, prms, nprms)
6494 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6496 if (appData.autoRaiseBoard) {
6497 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6499 XtSetArg(args[0], XtNleftBitmap, None);
6501 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6505 void AutosaveProc(w, event, prms, nprms)
6513 appData.autoSaveGames = !appData.autoSaveGames;
6515 if (appData.autoSaveGames) {
6516 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6518 XtSetArg(args[0], XtNleftBitmap, None);
6520 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6524 void BlindfoldProc(w, event, prms, nprms)
6532 appData.blindfold = !appData.blindfold;
6534 if (appData.blindfold) {
6535 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6537 XtSetArg(args[0], XtNleftBitmap, None);
6539 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6542 DrawPosition(True, NULL);
6545 void TestLegalityProc(w, event, prms, nprms)
6553 appData.testLegality = !appData.testLegality;
6555 if (appData.testLegality) {
6556 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6558 XtSetArg(args[0], XtNleftBitmap, None);
6560 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6565 void FlashMovesProc(w, event, prms, nprms)
6573 if (appData.flashCount == 0) {
6574 appData.flashCount = 3;
6576 appData.flashCount = -appData.flashCount;
6579 if (appData.flashCount > 0) {
6580 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6582 XtSetArg(args[0], XtNleftBitmap, None);
6584 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6588 void FlipViewProc(w, event, prms, nprms)
6594 flipView = !flipView;
6595 DrawPosition(True, NULL);
6598 void GetMoveListProc(w, event, prms, nprms)
6606 appData.getMoveList = !appData.getMoveList;
6608 if (appData.getMoveList) {
6609 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6612 XtSetArg(args[0], XtNleftBitmap, None);
6614 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6619 void HighlightDraggingProc(w, event, prms, nprms)
6627 appData.highlightDragging = !appData.highlightDragging;
6629 if (appData.highlightDragging) {
6630 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6632 XtSetArg(args[0], XtNleftBitmap, None);
6634 XtSetValues(XtNameToWidget(menuBarWidget,
6635 "menuOptions.Highlight Dragging"), args, 1);
6639 void HighlightLastMoveProc(w, event, prms, nprms)
6647 appData.highlightLastMove = !appData.highlightLastMove;
6649 if (appData.highlightLastMove) {
6650 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6652 XtSetArg(args[0], XtNleftBitmap, None);
6654 XtSetValues(XtNameToWidget(menuBarWidget,
6655 "menuOptions.Highlight Last Move"), args, 1);
6658 void IcsAlarmProc(w, event, prms, nprms)
6666 appData.icsAlarm = !appData.icsAlarm;
6668 if (appData.icsAlarm) {
6669 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6671 XtSetArg(args[0], XtNleftBitmap, None);
6673 XtSetValues(XtNameToWidget(menuBarWidget,
6674 "menuOptions.ICS Alarm"), args, 1);
6677 void MoveSoundProc(w, event, prms, nprms)
6685 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6687 if (appData.ringBellAfterMoves) {
6688 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6690 XtSetArg(args[0], XtNleftBitmap, None);
6692 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6697 void OldSaveStyleProc(w, event, prms, nprms)
6705 appData.oldSaveStyle = !appData.oldSaveStyle;
6707 if (appData.oldSaveStyle) {
6708 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6710 XtSetArg(args[0], XtNleftBitmap, None);
6712 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6716 void PeriodicUpdatesProc(w, event, prms, nprms)
6724 PeriodicUpdatesEvent(!appData.periodicUpdates);
6726 if (appData.periodicUpdates) {
6727 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6729 XtSetArg(args[0], XtNleftBitmap, None);
6731 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6735 void PonderNextMoveProc(w, event, prms, nprms)
6743 PonderNextMoveEvent(!appData.ponderNextMove);
6745 if (appData.ponderNextMove) {
6746 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6748 XtSetArg(args[0], XtNleftBitmap, None);
6750 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6754 void PopupExitMessageProc(w, event, prms, nprms)
6762 appData.popupExitMessage = !appData.popupExitMessage;
6764 if (appData.popupExitMessage) {
6765 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6767 XtSetArg(args[0], XtNleftBitmap, None);
6769 XtSetValues(XtNameToWidget(menuBarWidget,
6770 "menuOptions.Popup Exit Message"), args, 1);
6773 void PopupMoveErrorsProc(w, event, prms, nprms)
6781 appData.popupMoveErrors = !appData.popupMoveErrors;
6783 if (appData.popupMoveErrors) {
6784 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6786 XtSetArg(args[0], XtNleftBitmap, None);
6788 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6792 void PremoveProc(w, event, prms, nprms)
6800 appData.premove = !appData.premove;
6802 if (appData.premove) {
6803 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6805 XtSetArg(args[0], XtNleftBitmap, None);
6807 XtSetValues(XtNameToWidget(menuBarWidget,
6808 "menuOptions.Premove"), args, 1);
6811 void QuietPlayProc(w, event, prms, nprms)
6819 appData.quietPlay = !appData.quietPlay;
6821 if (appData.quietPlay) {
6822 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6824 XtSetArg(args[0], XtNleftBitmap, None);
6826 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6830 void ShowCoordsProc(w, event, prms, nprms)
6838 appData.showCoords = !appData.showCoords;
6840 if (appData.showCoords) {
6841 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6843 XtSetArg(args[0], XtNleftBitmap, None);
6845 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6848 DrawPosition(True, NULL);
6851 void ShowThinkingProc(w, event, prms, nprms)
6857 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6858 ShowThinkingEvent();
6861 void HideThinkingProc(w, event, prms, nprms)
6869 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6870 ShowThinkingEvent();
6872 if (appData.hideThinkingFromHuman) {
6873 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6875 XtSetArg(args[0], XtNleftBitmap, None);
6877 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6881 void SaveOnExitProc(w, event, prms, nprms)
6889 saveSettingsOnExit = !saveSettingsOnExit;
6891 if (saveSettingsOnExit) {
6892 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6894 XtSetArg(args[0], XtNleftBitmap, None);
6896 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6900 void SaveSettingsProc(w, event, prms, nprms)
6906 SaveSettings(settingsFileName);
6909 void InfoProc(w, event, prms, nprms)
6916 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6921 void ManProc(w, event, prms, nprms)
6929 if (nprms && *nprms > 0)
6933 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6937 void HintProc(w, event, prms, nprms)
6946 void BookProc(w, event, prms, nprms)
6955 void AboutProc(w, event, prms, nprms)
6963 char *zippy = " (with Zippy code)";
6967 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6968 programVersion, zippy,
6969 "Copyright 1991 Digital Equipment Corporation",
6970 "Enhancements Copyright 1992-2009 Free Software Foundation",
6971 "Enhancements Copyright 2005 Alessandro Scotti",
6972 PACKAGE, " is free software and carries NO WARRANTY;",
6973 "see the file COPYING for more information.");
6974 ErrorPopUp(_("About XBoard"), buf, FALSE);
6977 void DebugProc(w, event, prms, nprms)
6983 appData.debugMode = !appData.debugMode;
6986 void AboutGameProc(w, event, prms, nprms)
6995 void NothingProc(w, event, prms, nprms)
7004 void Iconify(w, event, prms, nprms)
7013 XtSetArg(args[0], XtNiconic, True);
7014 XtSetValues(shellWidget, args, 1);
7017 void DisplayMessage(message, extMessage)
7018 char *message, *extMessage;
7020 /* display a message in the message widget */
7029 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7034 message = extMessage;
7038 /* need to test if messageWidget already exists, since this function
7039 can also be called during the startup, if for example a Xresource
7040 is not set up correctly */
7043 XtSetArg(arg, XtNlabel, message);
7044 XtSetValues(messageWidget, &arg, 1);
7050 void DisplayTitle(text)
7055 char title[MSG_SIZ];
7058 if (text == NULL) text = "";
7060 if (appData.titleInWindow) {
7062 XtSetArg(args[i], XtNlabel, text); i++;
7063 XtSetValues(titleWidget, args, i);
7066 if (*text != NULLCHAR) {
7068 strcpy(title, text);
7069 } else if (appData.icsActive) {
7070 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7071 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7072 } else if (appData.cmailGameName[0] != NULLCHAR) {
7073 snprintf(icon, sizeof(icon), "%s", "CMail");
7074 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7076 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7077 } else if (gameInfo.variant == VariantGothic) {
7078 strcpy(icon, programName);
7079 strcpy(title, GOTHIC);
7082 } else if (gameInfo.variant == VariantFalcon) {
7083 strcpy(icon, programName);
7084 strcpy(title, FALCON);
7086 } else if (appData.noChessProgram) {
7087 strcpy(icon, programName);
7088 strcpy(title, programName);
7090 strcpy(icon, first.tidy);
7091 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7094 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7095 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7096 XtSetValues(shellWidget, args, i);
7100 void DisplayError(message, error)
7107 if (appData.debugMode || appData.matchMode) {
7108 fprintf(stderr, "%s: %s\n", programName, message);
7111 if (appData.debugMode || appData.matchMode) {
7112 fprintf(stderr, "%s: %s: %s\n",
7113 programName, message, strerror(error));
7115 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7118 ErrorPopUp(_("Error"), message, FALSE);
7122 void DisplayMoveError(message)
7127 DrawPosition(FALSE, NULL);
7128 if (appData.debugMode || appData.matchMode) {
7129 fprintf(stderr, "%s: %s\n", programName, message);
7131 if (appData.popupMoveErrors) {
7132 ErrorPopUp(_("Error"), message, FALSE);
7134 DisplayMessage(message, "");
7139 void DisplayFatalError(message, error, status)
7145 errorExitStatus = status;
7147 fprintf(stderr, "%s: %s\n", programName, message);
7149 fprintf(stderr, "%s: %s: %s\n",
7150 programName, message, strerror(error));
7151 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7154 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7155 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7161 void DisplayInformation(message)
7165 ErrorPopUp(_("Information"), message, TRUE);
7168 void DisplayNote(message)
7172 ErrorPopUp(_("Note"), message, FALSE);
7176 NullXErrorCheck(dpy, error_event)
7178 XErrorEvent *error_event;
7183 void DisplayIcsInteractionTitle(message)
7186 if (oldICSInteractionTitle == NULL) {
7187 /* Magic to find the old window title, adapted from vim */
7188 char *wina = getenv("WINDOWID");
7190 Window win = (Window) atoi(wina);
7191 Window root, parent, *children;
7192 unsigned int nchildren;
7193 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7195 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7196 if (!XQueryTree(xDisplay, win, &root, &parent,
7197 &children, &nchildren)) break;
7198 if (children) XFree((void *)children);
7199 if (parent == root || parent == 0) break;
7202 XSetErrorHandler(oldHandler);
7204 if (oldICSInteractionTitle == NULL) {
7205 oldICSInteractionTitle = "xterm";
7208 printf("\033]0;%s\007", message);
7212 char pendingReplyPrefix[MSG_SIZ];
7213 ProcRef pendingReplyPR;
7215 void AskQuestionProc(w, event, prms, nprms)
7222 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7226 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7229 void AskQuestionPopDown()
7231 if (!askQuestionUp) return;
7232 XtPopdown(askQuestionShell);
7233 XtDestroyWidget(askQuestionShell);
7234 askQuestionUp = False;
7237 void AskQuestionReplyAction(w, event, prms, nprms)
7247 reply = XawDialogGetValueString(w = XtParent(w));
7248 strcpy(buf, pendingReplyPrefix);
7249 if (*buf) strcat(buf, " ");
7252 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7253 AskQuestionPopDown();
7255 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7258 void AskQuestionCallback(w, client_data, call_data)
7260 XtPointer client_data, call_data;
7265 XtSetArg(args[0], XtNlabel, &name);
7266 XtGetValues(w, args, 1);
7268 if (strcmp(name, _("cancel")) == 0) {
7269 AskQuestionPopDown();
7271 AskQuestionReplyAction(w, NULL, NULL, NULL);
7275 void AskQuestion(title, question, replyPrefix, pr)
7276 char *title, *question, *replyPrefix;
7280 Widget popup, layout, dialog, edit;
7286 strcpy(pendingReplyPrefix, replyPrefix);
7287 pendingReplyPR = pr;
7290 XtSetArg(args[i], XtNresizable, True); i++;
7291 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7292 askQuestionShell = popup =
7293 XtCreatePopupShell(title, transientShellWidgetClass,
7294 shellWidget, args, i);
7297 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7298 layoutArgs, XtNumber(layoutArgs));
7301 XtSetArg(args[i], XtNlabel, question); i++;
7302 XtSetArg(args[i], XtNvalue, ""); i++;
7303 XtSetArg(args[i], XtNborderWidth, 0); i++;
7304 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7307 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7308 (XtPointer) dialog);
7309 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7310 (XtPointer) dialog);
7312 XtRealizeWidget(popup);
7313 CatchDeleteWindow(popup, "AskQuestionPopDown");
7315 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7316 &x, &y, &win_x, &win_y, &mask);
7318 XtSetArg(args[0], XtNx, x - 10);
7319 XtSetArg(args[1], XtNy, y - 30);
7320 XtSetValues(popup, args, 2);
7322 XtPopup(popup, XtGrabExclusive);
7323 askQuestionUp = True;
7325 edit = XtNameToWidget(dialog, "*value");
7326 XtSetKeyboardFocus(popup, edit);
7334 if (*name == NULLCHAR) {
7336 } else if (strcmp(name, "$") == 0) {
7337 putc(BELLCHAR, stderr);
7340 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7348 PlaySound(appData.soundMove);
7354 PlaySound(appData.soundIcsWin);
7360 PlaySound(appData.soundIcsLoss);
7366 PlaySound(appData.soundIcsDraw);
7370 PlayIcsUnfinishedSound()
7372 PlaySound(appData.soundIcsUnfinished);
7378 PlaySound(appData.soundIcsAlarm);
7384 system("stty echo");
7390 system("stty -echo");
7394 Colorize(cc, continuation)
7399 int count, outCount, error;
7401 if (textColors[(int)cc].bg > 0) {
7402 if (textColors[(int)cc].fg > 0) {
7403 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7404 textColors[(int)cc].fg, textColors[(int)cc].bg);
7406 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7407 textColors[(int)cc].bg);
7410 if (textColors[(int)cc].fg > 0) {
7411 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7412 textColors[(int)cc].fg);
7414 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7417 count = strlen(buf);
7418 outCount = OutputToProcess(NoProc, buf, count, &error);
7419 if (outCount < count) {
7420 DisplayFatalError(_("Error writing to display"), error, 1);
7423 if (continuation) return;
7426 PlaySound(appData.soundShout);
7429 PlaySound(appData.soundSShout);
7432 PlaySound(appData.soundChannel1);
7435 PlaySound(appData.soundChannel);
7438 PlaySound(appData.soundKibitz);
7441 PlaySound(appData.soundTell);
7443 case ColorChallenge:
7444 PlaySound(appData.soundChallenge);
7447 PlaySound(appData.soundRequest);
7450 PlaySound(appData.soundSeek);
7461 return getpwuid(getuid())->pw_name;
7464 static char *ExpandPathName(path)
7467 static char static_buf[2000];
7468 char *d, *s, buf[2000];
7474 while (*s && isspace(*s))
7483 if (*(s+1) == '/') {
7484 strcpy(d, getpwuid(getuid())->pw_dir);
7489 *strchr(buf, '/') = 0;
7490 pwd = getpwnam(buf);
7493 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7497 strcpy(d, pwd->pw_dir);
7498 strcat(d, strchr(s+1, '/'));
7509 static char host_name[MSG_SIZ];
7511 #if HAVE_GETHOSTNAME
7512 gethostname(host_name, MSG_SIZ);
7514 #else /* not HAVE_GETHOSTNAME */
7515 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7516 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7518 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7520 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7521 #endif /* not HAVE_GETHOSTNAME */
7524 XtIntervalId delayedEventTimerXID = 0;
7525 DelayedEventCallback delayedEventCallback = 0;
7530 delayedEventTimerXID = 0;
7531 delayedEventCallback();
7535 ScheduleDelayedEvent(cb, millisec)
7536 DelayedEventCallback cb; long millisec;
7538 if(delayedEventTimerXID && delayedEventCallback == cb)
7539 // [HGM] alive: replace, rather than add or flush identical event
7540 XtRemoveTimeOut(delayedEventTimerXID);
7541 delayedEventCallback = cb;
7542 delayedEventTimerXID =
7543 XtAppAddTimeOut(appContext, millisec,
7544 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7547 DelayedEventCallback
7550 if (delayedEventTimerXID) {
7551 return delayedEventCallback;
7558 CancelDelayedEvent()
7560 if (delayedEventTimerXID) {
7561 XtRemoveTimeOut(delayedEventTimerXID);
7562 delayedEventTimerXID = 0;
7566 XtIntervalId loadGameTimerXID = 0;
7568 int LoadGameTimerRunning()
7570 return loadGameTimerXID != 0;
7573 int StopLoadGameTimer()
7575 if (loadGameTimerXID != 0) {
7576 XtRemoveTimeOut(loadGameTimerXID);
7577 loadGameTimerXID = 0;
7585 LoadGameTimerCallback(arg, id)
7589 loadGameTimerXID = 0;
7594 StartLoadGameTimer(millisec)
7598 XtAppAddTimeOut(appContext, millisec,
7599 (XtTimerCallbackProc) LoadGameTimerCallback,
7603 XtIntervalId analysisClockXID = 0;
7606 AnalysisClockCallback(arg, id)
7610 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7611 || appData.icsEngineAnalyze) { // [DM]
7612 AnalysisPeriodicEvent(0);
7613 StartAnalysisClock();
7618 StartAnalysisClock()
7621 XtAppAddTimeOut(appContext, 2000,
7622 (XtTimerCallbackProc) AnalysisClockCallback,
7626 XtIntervalId clockTimerXID = 0;
7628 int ClockTimerRunning()
7630 return clockTimerXID != 0;
7633 int StopClockTimer()
7635 if (clockTimerXID != 0) {
7636 XtRemoveTimeOut(clockTimerXID);
7645 ClockTimerCallback(arg, id)
7654 StartClockTimer(millisec)
7658 XtAppAddTimeOut(appContext, millisec,
7659 (XtTimerCallbackProc) ClockTimerCallback,
7664 DisplayTimerLabel(w, color, timer, highlight)
7673 /* check for low time warning */
7674 Pixel foregroundOrWarningColor = timerForegroundPixel;
7677 appData.lowTimeWarning &&
7678 (timer / 1000) < appData.icsAlarmTime)
7679 foregroundOrWarningColor = lowTimeWarningColor;
7681 if (appData.clockMode) {
7682 sprintf(buf, "%s: %s", color, TimeString(timer));
7683 XtSetArg(args[0], XtNlabel, buf);
7685 sprintf(buf, "%s ", color);
7686 XtSetArg(args[0], XtNlabel, buf);
7691 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7692 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7694 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7695 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7698 XtSetValues(w, args, 3);
7702 DisplayWhiteClock(timeRemaining, highlight)
7708 if(appData.noGUI) return;
7709 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7710 if (highlight && iconPixmap == bIconPixmap) {
7711 iconPixmap = wIconPixmap;
7712 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7713 XtSetValues(shellWidget, args, 1);
7718 DisplayBlackClock(timeRemaining, highlight)
7724 if(appData.noGUI) return;
7725 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7726 if (highlight && iconPixmap == wIconPixmap) {
7727 iconPixmap = bIconPixmap;
7728 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7729 XtSetValues(shellWidget, args, 1);
7747 int StartChildProcess(cmdLine, dir, pr)
7754 int to_prog[2], from_prog[2];
7758 if (appData.debugMode) {
7759 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7762 /* We do NOT feed the cmdLine to the shell; we just
7763 parse it into blank-separated arguments in the
7764 most simple-minded way possible.
7767 strcpy(buf, cmdLine);
7770 while(*p == ' ') p++;
7772 if(*p == '"' || *p == '\'')
7773 p = strchr(++argv[i-1], *p);
7774 else p = strchr(p, ' ');
7775 if (p == NULL) break;
7780 SetUpChildIO(to_prog, from_prog);
7782 if ((pid = fork()) == 0) {
7784 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7785 close(to_prog[1]); // first close the unused pipe ends
7786 close(from_prog[0]);
7787 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7788 dup2(from_prog[1], 1);
7789 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7790 close(from_prog[1]); // and closing again loses one of the pipes!
7791 if(fileno(stderr) >= 2) // better safe than sorry...
7792 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7794 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7799 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7801 execvp(argv[0], argv);
7803 /* If we get here, exec failed */
7808 /* Parent process */
7810 close(from_prog[1]);
7812 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7815 cp->fdFrom = from_prog[0];
7816 cp->fdTo = to_prog[1];
7821 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7822 static RETSIGTYPE AlarmCallBack(int n)
7828 DestroyChildProcess(pr, signalType)
7832 ChildProc *cp = (ChildProc *) pr;
7834 if (cp->kind != CPReal) return;
7836 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7837 signal(SIGALRM, AlarmCallBack);
7839 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7840 kill(cp->pid, SIGKILL); // kill it forcefully
7841 wait((int *) 0); // and wait again
7845 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7847 /* Process is exiting either because of the kill or because of
7848 a quit command sent by the backend; either way, wait for it to die.
7857 InterruptChildProcess(pr)
7860 ChildProc *cp = (ChildProc *) pr;
7862 if (cp->kind != CPReal) return;
7863 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7866 int OpenTelnet(host, port, pr)
7871 char cmdLine[MSG_SIZ];
7873 if (port[0] == NULLCHAR) {
7874 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7876 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7878 return StartChildProcess(cmdLine, "", pr);
7881 int OpenTCP(host, port, pr)
7887 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7888 #else /* !OMIT_SOCKETS */
7890 struct sockaddr_in sa;
7892 unsigned short uport;
7895 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7899 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7900 sa.sin_family = AF_INET;
7901 sa.sin_addr.s_addr = INADDR_ANY;
7902 uport = (unsigned short) 0;
7903 sa.sin_port = htons(uport);
7904 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7908 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7909 if (!(hp = gethostbyname(host))) {
7911 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7912 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7913 hp->h_addrtype = AF_INET;
7915 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7916 hp->h_addr_list[0] = (char *) malloc(4);
7917 hp->h_addr_list[0][0] = b0;
7918 hp->h_addr_list[0][1] = b1;
7919 hp->h_addr_list[0][2] = b2;
7920 hp->h_addr_list[0][3] = b3;
7925 sa.sin_family = hp->h_addrtype;
7926 uport = (unsigned short) atoi(port);
7927 sa.sin_port = htons(uport);
7928 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7930 if (connect(s, (struct sockaddr *) &sa,
7931 sizeof(struct sockaddr_in)) < 0) {
7935 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7942 #endif /* !OMIT_SOCKETS */
7947 int OpenCommPort(name, pr)
7954 fd = open(name, 2, 0);
7955 if (fd < 0) return errno;
7957 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7967 int OpenLoopback(pr)
7973 SetUpChildIO(to, from);
7975 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7978 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7985 int OpenRcmd(host, user, cmd, pr)
7986 char *host, *user, *cmd;
7989 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7993 #define INPUT_SOURCE_BUF_SIZE 8192
8002 char buf[INPUT_SOURCE_BUF_SIZE];
8007 DoInputCallback(closure, source, xid)
8012 InputSource *is = (InputSource *) closure;
8017 if (is->lineByLine) {
8018 count = read(is->fd, is->unused,
8019 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8021 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8024 is->unused += count;
8026 while (p < is->unused) {
8027 q = memchr(p, '\n', is->unused - p);
8028 if (q == NULL) break;
8030 (is->func)(is, is->closure, p, q - p, 0);
8034 while (p < is->unused) {
8039 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8044 (is->func)(is, is->closure, is->buf, count, error);
8048 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8055 ChildProc *cp = (ChildProc *) pr;
8057 is = (InputSource *) calloc(1, sizeof(InputSource));
8058 is->lineByLine = lineByLine;
8062 is->fd = fileno(stdin);
8064 is->kind = cp->kind;
8065 is->fd = cp->fdFrom;
8068 is->unused = is->buf;
8071 is->xid = XtAppAddInput(appContext, is->fd,
8072 (XtPointer) (XtInputReadMask),
8073 (XtInputCallbackProc) DoInputCallback,
8075 is->closure = closure;
8076 return (InputSourceRef) is;
8080 RemoveInputSource(isr)
8083 InputSource *is = (InputSource *) isr;
8085 if (is->xid == 0) return;
8086 XtRemoveInput(is->xid);
8090 int OutputToProcess(pr, message, count, outError)
8096 static int line = 0;
8097 ChildProc *cp = (ChildProc *) pr;
8102 if (appData.noJoin || !appData.useInternalWrap)
8103 outCount = fwrite(message, 1, count, stdout);
8106 int width = get_term_width();
8107 int len = wrap(NULL, message, count, width, &line);
8108 char *msg = malloc(len);
8112 outCount = fwrite(message, 1, count, stdout);
8115 dbgchk = wrap(msg, message, count, width, &line);
8116 if (dbgchk != len && appData.debugMode)
8117 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8118 outCount = fwrite(msg, 1, dbgchk, stdout);
8124 outCount = write(cp->fdTo, message, count);
8134 /* Output message to process, with "ms" milliseconds of delay
8135 between each character. This is needed when sending the logon
8136 script to ICC, which for some reason doesn't like the
8137 instantaneous send. */
8138 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8145 ChildProc *cp = (ChildProc *) pr;
8150 r = write(cp->fdTo, message++, 1);
8163 /**** Animation code by Hugh Fisher, DCS, ANU.
8165 Known problem: if a window overlapping the board is
8166 moved away while a piece is being animated underneath,
8167 the newly exposed area won't be updated properly.
8168 I can live with this.
8170 Known problem: if you look carefully at the animation
8171 of pieces in mono mode, they are being drawn as solid
8172 shapes without interior detail while moving. Fixing
8173 this would be a major complication for minimal return.
8176 /* Masks for XPM pieces. Black and white pieces can have
8177 different shapes, but in the interest of retaining my
8178 sanity pieces must have the same outline on both light
8179 and dark squares, and all pieces must use the same
8180 background square colors/images. */
8182 static int xpmDone = 0;
8185 CreateAnimMasks (pieceDepth)
8192 unsigned long plane;
8195 /* Need a bitmap just to get a GC with right depth */
8196 buf = XCreatePixmap(xDisplay, xBoardWindow,
8198 values.foreground = 1;
8199 values.background = 0;
8200 /* Don't use XtGetGC, not read only */
8201 maskGC = XCreateGC(xDisplay, buf,
8202 GCForeground | GCBackground, &values);
8203 XFreePixmap(xDisplay, buf);
8205 buf = XCreatePixmap(xDisplay, xBoardWindow,
8206 squareSize, squareSize, pieceDepth);
8207 values.foreground = XBlackPixel(xDisplay, xScreen);
8208 values.background = XWhitePixel(xDisplay, xScreen);
8209 bufGC = XCreateGC(xDisplay, buf,
8210 GCForeground | GCBackground, &values);
8212 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8213 /* Begin with empty mask */
8214 if(!xpmDone) // [HGM] pieces: keep using existing
8215 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8216 squareSize, squareSize, 1);
8217 XSetFunction(xDisplay, maskGC, GXclear);
8218 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8219 0, 0, squareSize, squareSize);
8221 /* Take a copy of the piece */
8226 XSetFunction(xDisplay, bufGC, GXcopy);
8227 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8229 0, 0, squareSize, squareSize, 0, 0);
8231 /* XOR the background (light) over the piece */
8232 XSetFunction(xDisplay, bufGC, GXxor);
8234 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8235 0, 0, squareSize, squareSize, 0, 0);
8237 XSetForeground(xDisplay, bufGC, lightSquareColor);
8238 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8241 /* We now have an inverted piece image with the background
8242 erased. Construct mask by just selecting all the non-zero
8243 pixels - no need to reconstruct the original image. */
8244 XSetFunction(xDisplay, maskGC, GXor);
8246 /* Might be quicker to download an XImage and create bitmap
8247 data from it rather than this N copies per piece, but it
8248 only takes a fraction of a second and there is a much
8249 longer delay for loading the pieces. */
8250 for (n = 0; n < pieceDepth; n ++) {
8251 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8252 0, 0, squareSize, squareSize,
8258 XFreePixmap(xDisplay, buf);
8259 XFreeGC(xDisplay, bufGC);
8260 XFreeGC(xDisplay, maskGC);
8264 InitAnimState (anim, info)
8266 XWindowAttributes * info;
8271 /* Each buffer is square size, same depth as window */
8272 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8273 squareSize, squareSize, info->depth);
8274 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8275 squareSize, squareSize, info->depth);
8277 /* Create a plain GC for blitting */
8278 mask = GCForeground | GCBackground | GCFunction |
8279 GCPlaneMask | GCGraphicsExposures;
8280 values.foreground = XBlackPixel(xDisplay, xScreen);
8281 values.background = XWhitePixel(xDisplay, xScreen);
8282 values.function = GXcopy;
8283 values.plane_mask = AllPlanes;
8284 values.graphics_exposures = False;
8285 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8287 /* Piece will be copied from an existing context at
8288 the start of each new animation/drag. */
8289 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8291 /* Outline will be a read-only copy of an existing */
8292 anim->outlineGC = None;
8298 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8299 XWindowAttributes info;
8301 if (xpmDone && gameInfo.variant == old) return;
8302 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8303 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8305 InitAnimState(&game, &info);
8306 InitAnimState(&player, &info);
8308 /* For XPM pieces, we need bitmaps to use as masks. */
8310 CreateAnimMasks(info.depth);
8316 static Boolean frameWaiting;
8318 static RETSIGTYPE FrameAlarm (sig)
8321 frameWaiting = False;
8322 /* In case System-V style signals. Needed?? */
8323 signal(SIGALRM, FrameAlarm);
8330 struct itimerval delay;
8332 XSync(xDisplay, False);
8335 frameWaiting = True;
8336 signal(SIGALRM, FrameAlarm);
8337 delay.it_interval.tv_sec =
8338 delay.it_value.tv_sec = time / 1000;
8339 delay.it_interval.tv_usec =
8340 delay.it_value.tv_usec = (time % 1000) * 1000;
8341 setitimer(ITIMER_REAL, &delay, NULL);
8342 while (frameWaiting) pause();
8343 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8344 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8345 setitimer(ITIMER_REAL, &delay, NULL);
8355 XSync(xDisplay, False);
8357 usleep(time * 1000);
8362 /* Convert board position to corner of screen rect and color */
8365 ScreenSquare(column, row, pt, color)
8366 int column; int row; XPoint * pt; int * color;
8369 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8370 pt->y = lineGap + row * (squareSize + lineGap);
8372 pt->x = lineGap + column * (squareSize + lineGap);
8373 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8375 *color = SquareColor(row, column);
8378 /* Convert window coords to square */
8381 BoardSquare(x, y, column, row)
8382 int x; int y; int * column; int * row;
8384 *column = EventToSquare(x, BOARD_WIDTH);
8385 if (flipView && *column >= 0)
8386 *column = BOARD_WIDTH - 1 - *column;
8387 *row = EventToSquare(y, BOARD_HEIGHT);
8388 if (!flipView && *row >= 0)
8389 *row = BOARD_HEIGHT - 1 - *row;
8394 #undef Max /* just in case */
8396 #define Max(a, b) ((a) > (b) ? (a) : (b))
8397 #define Min(a, b) ((a) < (b) ? (a) : (b))
8400 SetRect(rect, x, y, width, height)
8401 XRectangle * rect; int x; int y; int width; int height;
8405 rect->width = width;
8406 rect->height = height;
8409 /* Test if two frames overlap. If they do, return
8410 intersection rect within old and location of
8411 that rect within new. */
8414 Intersect(old, new, size, area, pt)
8415 XPoint * old; XPoint * new;
8416 int size; XRectangle * area; XPoint * pt;
8418 if (old->x > new->x + size || new->x > old->x + size ||
8419 old->y > new->y + size || new->y > old->y + size) {
8422 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8423 size - abs(old->x - new->x), size - abs(old->y - new->y));
8424 pt->x = Max(old->x - new->x, 0);
8425 pt->y = Max(old->y - new->y, 0);
8430 /* For two overlapping frames, return the rect(s)
8431 in the old that do not intersect with the new. */
8434 CalcUpdateRects(old, new, size, update, nUpdates)
8435 XPoint * old; XPoint * new; int size;
8436 XRectangle update[]; int * nUpdates;
8440 /* If old = new (shouldn't happen) then nothing to draw */
8441 if (old->x == new->x && old->y == new->y) {
8445 /* Work out what bits overlap. Since we know the rects
8446 are the same size we don't need a full intersect calc. */
8448 /* Top or bottom edge? */
8449 if (new->y > old->y) {
8450 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8452 } else if (old->y > new->y) {
8453 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8454 size, old->y - new->y);
8457 /* Left or right edge - don't overlap any update calculated above. */
8458 if (new->x > old->x) {
8459 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8460 new->x - old->x, size - abs(new->y - old->y));
8462 } else if (old->x > new->x) {
8463 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8464 old->x - new->x, size - abs(new->y - old->y));
8471 /* Generate a series of frame coords from start->mid->finish.
8472 The movement rate doubles until the half way point is
8473 reached, then halves back down to the final destination,
8474 which gives a nice slow in/out effect. The algorithmn
8475 may seem to generate too many intermediates for short
8476 moves, but remember that the purpose is to attract the
8477 viewers attention to the piece about to be moved and
8478 then to where it ends up. Too few frames would be less
8482 Tween(start, mid, finish, factor, frames, nFrames)
8483 XPoint * start; XPoint * mid;
8484 XPoint * finish; int factor;
8485 XPoint frames[]; int * nFrames;
8487 int fraction, n, count;
8491 /* Slow in, stepping 1/16th, then 1/8th, ... */
8493 for (n = 0; n < factor; n++)
8495 for (n = 0; n < factor; n++) {
8496 frames[count].x = start->x + (mid->x - start->x) / fraction;
8497 frames[count].y = start->y + (mid->y - start->y) / fraction;
8499 fraction = fraction / 2;
8503 frames[count] = *mid;
8506 /* Slow out, stepping 1/2, then 1/4, ... */
8508 for (n = 0; n < factor; n++) {
8509 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8510 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8512 fraction = fraction * 2;
8517 /* Draw a piece on the screen without disturbing what's there */
8520 SelectGCMask(piece, clip, outline, mask)
8521 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8525 /* Bitmap for piece being moved. */
8526 if (appData.monoMode) {
8527 *mask = *pieceToSolid(piece);
8528 } else if (useImages) {
8530 *mask = xpmMask[piece];
8532 *mask = ximMaskPm[piece];
8535 *mask = *pieceToSolid(piece);
8538 /* GC for piece being moved. Square color doesn't matter, but
8539 since it gets modified we make a copy of the original. */
8541 if (appData.monoMode)
8546 if (appData.monoMode)
8551 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8553 /* Outline only used in mono mode and is not modified */
8555 *outline = bwPieceGC;
8557 *outline = wbPieceGC;
8561 OverlayPiece(piece, clip, outline, dest)
8562 ChessSquare piece; GC clip; GC outline; Drawable dest;
8567 /* Draw solid rectangle which will be clipped to shape of piece */
8568 XFillRectangle(xDisplay, dest, clip,
8569 0, 0, squareSize, squareSize);
8570 if (appData.monoMode)
8571 /* Also draw outline in contrasting color for black
8572 on black / white on white cases */
8573 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8574 0, 0, squareSize, squareSize, 0, 0, 1);
8576 /* Copy the piece */
8581 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8583 0, 0, squareSize, squareSize,
8588 /* Animate the movement of a single piece */
8591 BeginAnimation(anim, piece, startColor, start)
8599 /* The old buffer is initialised with the start square (empty) */
8600 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8601 anim->prevFrame = *start;
8603 /* The piece will be drawn using its own bitmap as a matte */
8604 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8605 XSetClipMask(xDisplay, anim->pieceGC, mask);
8609 AnimationFrame(anim, frame, piece)
8614 XRectangle updates[4];
8619 /* Save what we are about to draw into the new buffer */
8620 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8621 frame->x, frame->y, squareSize, squareSize,
8624 /* Erase bits of the previous frame */
8625 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8626 /* Where the new frame overlapped the previous,
8627 the contents in newBuf are wrong. */
8628 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8629 overlap.x, overlap.y,
8630 overlap.width, overlap.height,
8632 /* Repaint the areas in the old that don't overlap new */
8633 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8634 for (i = 0; i < count; i++)
8635 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8636 updates[i].x - anim->prevFrame.x,
8637 updates[i].y - anim->prevFrame.y,
8638 updates[i].width, updates[i].height,
8639 updates[i].x, updates[i].y);
8641 /* Easy when no overlap */
8642 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8643 0, 0, squareSize, squareSize,
8644 anim->prevFrame.x, anim->prevFrame.y);
8647 /* Save this frame for next time round */
8648 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8649 0, 0, squareSize, squareSize,
8651 anim->prevFrame = *frame;
8653 /* Draw piece over original screen contents, not current,
8654 and copy entire rect. Wipes out overlapping piece images. */
8655 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8656 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8657 0, 0, squareSize, squareSize,
8658 frame->x, frame->y);
8662 EndAnimation (anim, finish)
8666 XRectangle updates[4];
8671 /* The main code will redraw the final square, so we
8672 only need to erase the bits that don't overlap. */
8673 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8674 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8675 for (i = 0; i < count; i++)
8676 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8677 updates[i].x - anim->prevFrame.x,
8678 updates[i].y - anim->prevFrame.y,
8679 updates[i].width, updates[i].height,
8680 updates[i].x, updates[i].y);
8682 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8683 0, 0, squareSize, squareSize,
8684 anim->prevFrame.x, anim->prevFrame.y);
8689 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8691 ChessSquare piece; int startColor;
8692 XPoint * start; XPoint * finish;
8693 XPoint frames[]; int nFrames;
8697 BeginAnimation(anim, piece, startColor, start);
8698 for (n = 0; n < nFrames; n++) {
8699 AnimationFrame(anim, &(frames[n]), piece);
8700 FrameDelay(appData.animSpeed);
8702 EndAnimation(anim, finish);
8705 /* Main control logic for deciding what to animate and how */
8708 AnimateMove(board, fromX, fromY, toX, toY)
8717 XPoint start, finish, mid;
8718 XPoint frames[kFactor * 2 + 1];
8719 int nFrames, startColor, endColor;
8721 /* Are we animating? */
8722 if (!appData.animate || appData.blindfold)
8725 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8726 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8727 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8729 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8730 piece = board[fromY][fromX];
8731 if (piece >= EmptySquare) return;
8736 hop = (piece == WhiteKnight || piece == BlackKnight);
8739 if (appData.debugMode) {
8740 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8741 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8742 piece, fromX, fromY, toX, toY); }
8744 ScreenSquare(fromX, fromY, &start, &startColor);
8745 ScreenSquare(toX, toY, &finish, &endColor);
8748 /* Knight: make diagonal movement then straight */
8749 if (abs(toY - fromY) < abs(toX - fromX)) {
8750 mid.x = start.x + (finish.x - start.x) / 2;
8754 mid.y = start.y + (finish.y - start.y) / 2;
8757 mid.x = start.x + (finish.x - start.x) / 2;
8758 mid.y = start.y + (finish.y - start.y) / 2;
8761 /* Don't use as many frames for very short moves */
8762 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8763 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8765 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8766 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8768 /* Be sure end square is redrawn */
8769 damage[0][toY][toX] = True;
8773 DragPieceBegin(x, y)
8776 int boardX, boardY, color;
8779 /* Are we animating? */
8780 if (!appData.animateDragging || appData.blindfold)
8783 /* Figure out which square we start in and the
8784 mouse position relative to top left corner. */
8785 BoardSquare(x, y, &boardX, &boardY);
8786 player.startBoardX = boardX;
8787 player.startBoardY = boardY;
8788 ScreenSquare(boardX, boardY, &corner, &color);
8789 player.startSquare = corner;
8790 player.startColor = color;
8791 /* As soon as we start dragging, the piece will jump slightly to
8792 be centered over the mouse pointer. */
8793 player.mouseDelta.x = squareSize/2;
8794 player.mouseDelta.y = squareSize/2;
8795 /* Initialise animation */
8796 player.dragPiece = PieceForSquare(boardX, boardY);
8798 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8799 player.dragActive = True;
8800 BeginAnimation(&player, player.dragPiece, color, &corner);
8801 /* Mark this square as needing to be redrawn. Note that
8802 we don't remove the piece though, since logically (ie
8803 as seen by opponent) the move hasn't been made yet. */
8804 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8805 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8806 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8807 corner.x, corner.y, squareSize, squareSize,
8808 0, 0); // [HGM] zh: unstack in stead of grab
8809 damage[0][boardY][boardX] = True;
8811 player.dragActive = False;
8821 /* Are we animating? */
8822 if (!appData.animateDragging || appData.blindfold)
8826 if (! player.dragActive)
8828 /* Move piece, maintaining same relative position
8829 of mouse within square */
8830 corner.x = x - player.mouseDelta.x;
8831 corner.y = y - player.mouseDelta.y;
8832 AnimationFrame(&player, &corner, player.dragPiece);
8834 if (appData.highlightDragging) {
8836 BoardSquare(x, y, &boardX, &boardY);
8837 SetHighlights(fromX, fromY, boardX, boardY);
8846 int boardX, boardY, color;
8849 /* Are we animating? */
8850 if (!appData.animateDragging || appData.blindfold)
8854 if (! player.dragActive)
8856 /* Last frame in sequence is square piece is
8857 placed on, which may not match mouse exactly. */
8858 BoardSquare(x, y, &boardX, &boardY);
8859 ScreenSquare(boardX, boardY, &corner, &color);
8860 EndAnimation(&player, &corner);
8862 /* Be sure end square is redrawn */
8863 damage[0][boardY][boardX] = True;
8865 /* This prevents weird things happening with fast successive
8866 clicks which on my Sun at least can cause motion events
8867 without corresponding press/release. */
8868 player.dragActive = False;
8871 /* Handle expose event while piece being dragged */
8876 if (!player.dragActive || appData.blindfold)
8879 /* What we're doing: logically, the move hasn't been made yet,
8880 so the piece is still in it's original square. But visually
8881 it's being dragged around the board. So we erase the square
8882 that the piece is on and draw it at the last known drag point. */
8883 BlankSquare(player.startSquare.x, player.startSquare.y,
8884 player.startColor, EmptySquare, xBoardWindow);
8885 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8886 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8889 #include <sys/ioctl.h>
8890 int get_term_width()
8892 int fd, default_width;
8895 default_width = 79; // this is FICS default anyway...
8897 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8899 if (!ioctl(fd, TIOCGSIZE, &win))
8900 default_width = win.ts_cols;
8901 #elif defined(TIOCGWINSZ)
8903 if (!ioctl(fd, TIOCGWINSZ, &win))
8904 default_width = win.ws_col;
8906 return default_width;
8909 void update_ics_width()
8911 static int old_width = 0;
8912 int new_width = get_term_width();
8914 if (old_width != new_width)
8915 ics_printf("set width %d\n", new_width);
8916 old_width = new_width;
8919 void NotifyFrontendLogin()