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];
1712 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1713 XSetWindowAttributes window_attributes;
1715 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1716 XrmValue vFrom, vTo;
1717 XtGeometryResult gres;
1720 int forceMono = False;
1722 srandom(time(0)); // [HGM] book: make random truly random
1724 setbuf(stdout, NULL);
1725 setbuf(stderr, NULL);
1728 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1729 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1733 programName = strrchr(argv[0], '/');
1734 if (programName == NULL)
1735 programName = argv[0];
1740 XtSetLanguageProc(NULL, NULL, NULL);
1741 bindtextdomain(PACKAGE, LOCALEDIR);
1742 textdomain(PACKAGE);
1746 XtAppInitialize(&appContext, "XBoard", shellOptions,
1747 XtNumber(shellOptions),
1748 &argc, argv, xboardResources, NULL, 0);
1749 appData.boardSize = "";
1750 InitAppData(ConvertToLine(argc, argv));
1752 if (p == NULL) p = "/tmp";
1753 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1754 gameCopyFilename = (char*) malloc(i);
1755 gamePasteFilename = (char*) malloc(i);
1756 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1757 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1759 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1760 clientResources, XtNumber(clientResources),
1763 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1764 static char buf[MSG_SIZ];
1765 EscapeExpand(buf, appData.initString);
1766 appData.initString = strdup(buf);
1767 EscapeExpand(buf, appData.secondInitString);
1768 appData.secondInitString = strdup(buf);
1769 EscapeExpand(buf, appData.firstComputerString);
1770 appData.firstComputerString = strdup(buf);
1771 EscapeExpand(buf, appData.secondComputerString);
1772 appData.secondComputerString = strdup(buf);
1775 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1778 if (chdir(chessDir) != 0) {
1779 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1785 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1786 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1787 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1788 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1791 setbuf(debugFP, NULL);
1794 /* [HGM,HR] make sure board size is acceptable */
1795 if(appData.NrFiles > BOARD_FILES ||
1796 appData.NrRanks > BOARD_RANKS )
1797 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1800 /* This feature does not work; animation needs a rewrite */
1801 appData.highlightDragging = FALSE;
1805 xDisplay = XtDisplay(shellWidget);
1806 xScreen = DefaultScreen(xDisplay);
1807 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1809 gameInfo.variant = StringToVariant(appData.variant);
1810 InitPosition(FALSE);
1813 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1815 if (isdigit(appData.boardSize[0])) {
1816 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1817 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1818 &fontPxlSize, &smallLayout, &tinyLayout);
1820 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1821 programName, appData.boardSize);
1825 /* Find some defaults; use the nearest known size */
1826 SizeDefaults *szd, *nearest;
1827 int distance = 99999;
1828 nearest = szd = sizeDefaults;
1829 while (szd->name != NULL) {
1830 if (abs(szd->squareSize - squareSize) < distance) {
1832 distance = abs(szd->squareSize - squareSize);
1833 if (distance == 0) break;
1837 if (i < 2) lineGap = nearest->lineGap;
1838 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1839 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1840 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1841 if (i < 6) smallLayout = nearest->smallLayout;
1842 if (i < 7) tinyLayout = nearest->tinyLayout;
1845 SizeDefaults *szd = sizeDefaults;
1846 if (*appData.boardSize == NULLCHAR) {
1847 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1848 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1851 if (szd->name == NULL) szd--;
1852 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1854 while (szd->name != NULL &&
1855 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1856 if (szd->name == NULL) {
1857 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1858 programName, appData.boardSize);
1862 squareSize = szd->squareSize;
1863 lineGap = szd->lineGap;
1864 clockFontPxlSize = szd->clockFontPxlSize;
1865 coordFontPxlSize = szd->coordFontPxlSize;
1866 fontPxlSize = szd->fontPxlSize;
1867 smallLayout = szd->smallLayout;
1868 tinyLayout = szd->tinyLayout;
1869 // [HGM] font: use defaults from settings file if available and not overruled
1871 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1872 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1873 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1874 appData.font = fontTable[MESSAGE_FONT][squareSize];
1875 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1876 appData.coordFont = fontTable[COORD_FONT][squareSize];
1878 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1879 if (strlen(appData.pixmapDirectory) > 0) {
1880 p = ExpandPathName(appData.pixmapDirectory);
1882 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1883 appData.pixmapDirectory);
1886 if (appData.debugMode) {
1887 fprintf(stderr, _("\
1888 XBoard square size (hint): %d\n\
1889 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1891 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1892 if (appData.debugMode) {
1893 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1897 /* [HR] height treated separately (hacked) */
1898 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1899 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1900 if (appData.showJail == 1) {
1901 /* Jail on top and bottom */
1902 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1903 XtSetArg(boardArgs[2], XtNheight,
1904 boardHeight + 2*(lineGap + squareSize));
1905 } else if (appData.showJail == 2) {
1907 XtSetArg(boardArgs[1], XtNwidth,
1908 boardWidth + 2*(lineGap + squareSize));
1909 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1912 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1913 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1917 * Determine what fonts to use.
1919 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1920 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1921 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1922 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1923 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1924 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1925 appData.font = FindFont(appData.font, fontPxlSize);
1926 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1927 countFontStruct = XQueryFont(xDisplay, countFontID);
1928 // appData.font = FindFont(appData.font, fontPxlSize);
1930 xdb = XtDatabase(xDisplay);
1931 XrmPutStringResource(&xdb, "*font", appData.font);
1934 * Detect if there are not enough colors available and adapt.
1936 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1937 appData.monoMode = True;
1940 if (!appData.monoMode) {
1941 vFrom.addr = (caddr_t) appData.lightSquareColor;
1942 vFrom.size = strlen(appData.lightSquareColor);
1943 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1944 if (vTo.addr == NULL) {
1945 appData.monoMode = True;
1948 lightSquareColor = *(Pixel *) vTo.addr;
1951 if (!appData.monoMode) {
1952 vFrom.addr = (caddr_t) appData.darkSquareColor;
1953 vFrom.size = strlen(appData.darkSquareColor);
1954 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1955 if (vTo.addr == NULL) {
1956 appData.monoMode = True;
1959 darkSquareColor = *(Pixel *) vTo.addr;
1962 if (!appData.monoMode) {
1963 vFrom.addr = (caddr_t) appData.whitePieceColor;
1964 vFrom.size = strlen(appData.whitePieceColor);
1965 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1966 if (vTo.addr == NULL) {
1967 appData.monoMode = True;
1970 whitePieceColor = *(Pixel *) vTo.addr;
1973 if (!appData.monoMode) {
1974 vFrom.addr = (caddr_t) appData.blackPieceColor;
1975 vFrom.size = strlen(appData.blackPieceColor);
1976 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1977 if (vTo.addr == NULL) {
1978 appData.monoMode = True;
1981 blackPieceColor = *(Pixel *) vTo.addr;
1985 if (!appData.monoMode) {
1986 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1987 vFrom.size = strlen(appData.highlightSquareColor);
1988 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1989 if (vTo.addr == NULL) {
1990 appData.monoMode = True;
1993 highlightSquareColor = *(Pixel *) vTo.addr;
1997 if (!appData.monoMode) {
1998 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1999 vFrom.size = strlen(appData.premoveHighlightColor);
2000 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2001 if (vTo.addr == NULL) {
2002 appData.monoMode = True;
2005 premoveHighlightColor = *(Pixel *) vTo.addr;
2010 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2013 if (appData.bitmapDirectory == NULL ||
2014 appData.bitmapDirectory[0] == NULLCHAR)
2015 appData.bitmapDirectory = DEF_BITMAP_DIR;
2018 if (appData.lowTimeWarning && !appData.monoMode) {
2019 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2020 vFrom.size = strlen(appData.lowTimeWarningColor);
2021 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2022 if (vTo.addr == NULL)
2023 appData.monoMode = True;
2025 lowTimeWarningColor = *(Pixel *) vTo.addr;
2028 if (appData.monoMode && appData.debugMode) {
2029 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2030 (unsigned long) XWhitePixel(xDisplay, xScreen),
2031 (unsigned long) XBlackPixel(xDisplay, xScreen));
2034 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2035 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2036 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2037 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2038 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2039 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2040 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2041 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2042 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2043 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2045 if (appData.colorize) {
2047 _("%s: can't parse color names; disabling colorization\n"),
2050 appData.colorize = FALSE;
2052 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2053 textColors[ColorNone].attr = 0;
2055 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2061 layoutName = "tinyLayout";
2062 } else if (smallLayout) {
2063 layoutName = "smallLayout";
2065 layoutName = "normalLayout";
2067 /* Outer layoutWidget is there only to provide a name for use in
2068 resources that depend on the layout style */
2070 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2071 layoutArgs, XtNumber(layoutArgs));
2073 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2074 formArgs, XtNumber(formArgs));
2075 XtSetArg(args[0], XtNdefaultDistance, &sep);
2076 XtGetValues(formWidget, args, 1);
2079 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2080 XtSetArg(args[0], XtNtop, XtChainTop);
2081 XtSetArg(args[1], XtNbottom, XtChainTop);
2082 XtSetArg(args[2], XtNright, XtChainLeft);
2083 XtSetValues(menuBarWidget, args, 3);
2085 widgetList[j++] = whiteTimerWidget =
2086 XtCreateWidget("whiteTime", labelWidgetClass,
2087 formWidget, timerArgs, XtNumber(timerArgs));
2088 XtSetArg(args[0], XtNfont, clockFontStruct);
2089 XtSetArg(args[1], XtNtop, XtChainTop);
2090 XtSetArg(args[2], XtNbottom, XtChainTop);
2091 XtSetValues(whiteTimerWidget, args, 3);
2093 widgetList[j++] = blackTimerWidget =
2094 XtCreateWidget("blackTime", labelWidgetClass,
2095 formWidget, timerArgs, XtNumber(timerArgs));
2096 XtSetArg(args[0], XtNfont, clockFontStruct);
2097 XtSetArg(args[1], XtNtop, XtChainTop);
2098 XtSetArg(args[2], XtNbottom, XtChainTop);
2099 XtSetValues(blackTimerWidget, args, 3);
2101 if (appData.titleInWindow) {
2102 widgetList[j++] = titleWidget =
2103 XtCreateWidget("title", labelWidgetClass, formWidget,
2104 titleArgs, XtNumber(titleArgs));
2105 XtSetArg(args[0], XtNtop, XtChainTop);
2106 XtSetArg(args[1], XtNbottom, XtChainTop);
2107 XtSetValues(titleWidget, args, 2);
2110 if (appData.showButtonBar) {
2111 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2112 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2113 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2114 XtSetArg(args[2], XtNtop, XtChainTop);
2115 XtSetArg(args[3], XtNbottom, XtChainTop);
2116 XtSetValues(buttonBarWidget, args, 4);
2119 widgetList[j++] = messageWidget =
2120 XtCreateWidget("message", labelWidgetClass, formWidget,
2121 messageArgs, XtNumber(messageArgs));
2122 XtSetArg(args[0], XtNtop, XtChainTop);
2123 XtSetArg(args[1], XtNbottom, XtChainTop);
2124 XtSetValues(messageWidget, args, 2);
2126 widgetList[j++] = boardWidget =
2127 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2128 XtNumber(boardArgs));
2130 XtManageChildren(widgetList, j);
2132 timerWidth = (boardWidth - sep) / 2;
2133 XtSetArg(args[0], XtNwidth, timerWidth);
2134 XtSetValues(whiteTimerWidget, args, 1);
2135 XtSetValues(blackTimerWidget, args, 1);
2137 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2138 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2139 XtGetValues(whiteTimerWidget, args, 2);
2141 if (appData.showButtonBar) {
2142 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2143 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2144 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2148 * formWidget uses these constraints but they are stored
2152 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2153 XtSetValues(menuBarWidget, args, i);
2154 if (appData.titleInWindow) {
2157 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2158 XtSetValues(whiteTimerWidget, args, i);
2160 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2161 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2162 XtSetValues(blackTimerWidget, args, i);
2164 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2165 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2166 XtSetValues(titleWidget, args, i);
2168 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2169 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2170 XtSetValues(messageWidget, args, i);
2171 if (appData.showButtonBar) {
2173 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2174 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2175 XtSetValues(buttonBarWidget, args, i);
2179 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2180 XtSetValues(whiteTimerWidget, args, i);
2182 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2183 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2184 XtSetValues(blackTimerWidget, args, i);
2186 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2187 XtSetValues(titleWidget, args, i);
2189 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2190 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2191 XtSetValues(messageWidget, args, i);
2192 if (appData.showButtonBar) {
2194 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2195 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2196 XtSetValues(buttonBarWidget, args, i);
2201 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2202 XtSetValues(whiteTimerWidget, args, i);
2204 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2205 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2206 XtSetValues(blackTimerWidget, args, i);
2208 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2209 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2210 XtSetValues(messageWidget, args, i);
2211 if (appData.showButtonBar) {
2213 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2214 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2215 XtSetValues(buttonBarWidget, args, i);
2219 XtSetArg(args[0], XtNfromVert, messageWidget);
2220 XtSetArg(args[1], XtNtop, XtChainTop);
2221 XtSetArg(args[2], XtNbottom, XtChainBottom);
2222 XtSetArg(args[3], XtNleft, XtChainLeft);
2223 XtSetArg(args[4], XtNright, XtChainRight);
2224 XtSetValues(boardWidget, args, 5);
2226 XtRealizeWidget(shellWidget);
2229 XtSetArg(args[0], XtNx, wpMain.x);
2230 XtSetArg(args[1], XtNy, wpMain.y);
2231 XtSetValues(shellWidget, args, 2);
2235 * Correct the width of the message and title widgets.
2236 * It is not known why some systems need the extra fudge term.
2237 * The value "2" is probably larger than needed.
2239 XawFormDoLayout(formWidget, False);
2241 #define WIDTH_FUDGE 2
2243 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2244 XtSetArg(args[i], XtNheight, &h); i++;
2245 XtGetValues(messageWidget, args, i);
2246 if (appData.showButtonBar) {
2248 XtSetArg(args[i], XtNwidth, &w); i++;
2249 XtGetValues(buttonBarWidget, args, i);
2250 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2252 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2255 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2256 if (gres != XtGeometryYes && appData.debugMode) {
2257 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2258 programName, gres, w, h, wr, hr);
2261 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2262 /* The size used for the child widget in layout lags one resize behind
2263 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2265 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2266 if (gres != XtGeometryYes && appData.debugMode) {
2267 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2268 programName, gres, w, h, wr, hr);
2271 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2272 XtSetArg(args[1], XtNright, XtChainRight);
2273 XtSetValues(messageWidget, args, 2);
2275 if (appData.titleInWindow) {
2277 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2278 XtSetArg(args[i], XtNheight, &h); i++;
2279 XtGetValues(titleWidget, args, i);
2281 w = boardWidth - 2*bor;
2283 XtSetArg(args[0], XtNwidth, &w);
2284 XtGetValues(menuBarWidget, args, 1);
2285 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2288 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2289 if (gres != XtGeometryYes && appData.debugMode) {
2291 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2292 programName, gres, w, h, wr, hr);
2295 XawFormDoLayout(formWidget, True);
2297 xBoardWindow = XtWindow(boardWidget);
2299 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2300 // not need to go into InitDrawingSizes().
2304 * Create X checkmark bitmap and initialize option menu checks.
2306 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2307 checkmark_bits, checkmark_width, checkmark_height);
2308 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2309 if (appData.alwaysPromoteToQueen) {
2310 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2313 if (appData.animateDragging) {
2314 XtSetValues(XtNameToWidget(menuBarWidget,
2315 "menuOptions.Animate Dragging"),
2318 if (appData.animate) {
2319 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2322 if (appData.autoComment) {
2323 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2326 if (appData.autoCallFlag) {
2327 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2330 if (appData.autoFlipView) {
2331 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2334 if (appData.autoObserve) {
2335 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2338 if (appData.autoRaiseBoard) {
2339 XtSetValues(XtNameToWidget(menuBarWidget,
2340 "menuOptions.Auto Raise Board"), args, 1);
2342 if (appData.autoSaveGames) {
2343 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2346 if (appData.saveGameFile[0] != NULLCHAR) {
2347 /* Can't turn this off from menu */
2348 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2350 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2354 if (appData.blindfold) {
2355 XtSetValues(XtNameToWidget(menuBarWidget,
2356 "menuOptions.Blindfold"), args, 1);
2358 if (appData.flashCount > 0) {
2359 XtSetValues(XtNameToWidget(menuBarWidget,
2360 "menuOptions.Flash Moves"),
2363 if (appData.getMoveList) {
2364 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2368 if (appData.highlightDragging) {
2369 XtSetValues(XtNameToWidget(menuBarWidget,
2370 "menuOptions.Highlight Dragging"),
2374 if (appData.highlightLastMove) {
2375 XtSetValues(XtNameToWidget(menuBarWidget,
2376 "menuOptions.Highlight Last Move"),
2379 if (appData.icsAlarm) {
2380 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2383 if (appData.ringBellAfterMoves) {
2384 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2387 if (appData.oldSaveStyle) {
2388 XtSetValues(XtNameToWidget(menuBarWidget,
2389 "menuOptions.Old Save Style"), args, 1);
2391 if (appData.periodicUpdates) {
2392 XtSetValues(XtNameToWidget(menuBarWidget,
2393 "menuOptions.Periodic Updates"), args, 1);
2395 if (appData.ponderNextMove) {
2396 XtSetValues(XtNameToWidget(menuBarWidget,
2397 "menuOptions.Ponder Next Move"), args, 1);
2399 if (appData.popupExitMessage) {
2400 XtSetValues(XtNameToWidget(menuBarWidget,
2401 "menuOptions.Popup Exit Message"), args, 1);
2403 if (appData.popupMoveErrors) {
2404 XtSetValues(XtNameToWidget(menuBarWidget,
2405 "menuOptions.Popup Move Errors"), args, 1);
2407 if (appData.premove) {
2408 XtSetValues(XtNameToWidget(menuBarWidget,
2409 "menuOptions.Premove"), args, 1);
2411 if (appData.quietPlay) {
2412 XtSetValues(XtNameToWidget(menuBarWidget,
2413 "menuOptions.Quiet Play"), args, 1);
2415 if (appData.showCoords) {
2416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2419 if (appData.hideThinkingFromHuman) {
2420 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2423 if (appData.testLegality) {
2424 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2427 if (saveSettingsOnExit) {
2428 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2435 ReadBitmap(&wIconPixmap, "icon_white.bm",
2436 icon_white_bits, icon_white_width, icon_white_height);
2437 ReadBitmap(&bIconPixmap, "icon_black.bm",
2438 icon_black_bits, icon_black_width, icon_black_height);
2439 iconPixmap = wIconPixmap;
2441 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2442 XtSetValues(shellWidget, args, i);
2445 * Create a cursor for the board widget.
2447 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2448 XChangeWindowAttributes(xDisplay, xBoardWindow,
2449 CWCursor, &window_attributes);
2452 * Inhibit shell resizing.
2454 shellArgs[0].value = (XtArgVal) &w;
2455 shellArgs[1].value = (XtArgVal) &h;
2456 XtGetValues(shellWidget, shellArgs, 2);
2457 shellArgs[4].value = shellArgs[2].value = w;
2458 shellArgs[5].value = shellArgs[3].value = h;
2459 XtSetValues(shellWidget, &shellArgs[2], 4);
2460 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2461 marginH = h - boardHeight;
2463 CatchDeleteWindow(shellWidget, "QuitProc");
2468 if (appData.bitmapDirectory[0] != NULLCHAR) {
2475 /* Create regular pieces */
2476 if (!useImages) CreatePieces();
2481 if (appData.animate || appData.animateDragging)
2484 XtAugmentTranslations(formWidget,
2485 XtParseTranslationTable(globalTranslations));
2486 XtAugmentTranslations(boardWidget,
2487 XtParseTranslationTable(boardTranslations));
2488 XtAugmentTranslations(whiteTimerWidget,
2489 XtParseTranslationTable(whiteTranslations));
2490 XtAugmentTranslations(blackTimerWidget,
2491 XtParseTranslationTable(blackTranslations));
2493 /* Why is the following needed on some versions of X instead
2494 * of a translation? */
2495 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2496 (XtEventHandler) EventProc, NULL);
2499 /* [AS] Restore layout */
2500 if( wpMoveHistory.visible ) {
2504 if( wpEvalGraph.visible )
2509 if( wpEngineOutput.visible ) {
2510 EngineOutputPopUp();
2515 if (errorExitStatus == -1) {
2516 if (appData.icsActive) {
2517 /* We now wait until we see "login:" from the ICS before
2518 sending the logon script (problems with timestamp otherwise) */
2519 /*ICSInitScript();*/
2520 if (appData.icsInputBox) ICSInputBoxPopUp();
2524 signal(SIGWINCH, TermSizeSigHandler);
2526 signal(SIGINT, IntSigHandler);
2527 signal(SIGTERM, IntSigHandler);
2528 if (*appData.cmailGameName != NULLCHAR) {
2529 signal(SIGUSR1, CmailSigHandler);
2532 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2534 XtSetKeyboardFocus(shellWidget, formWidget);
2536 XtAppMainLoop(appContext);
2537 if (appData.debugMode) fclose(debugFP); // [DM] debug
2544 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2545 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2547 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2548 unlink(gameCopyFilename);
2549 unlink(gamePasteFilename);
2552 RETSIGTYPE TermSizeSigHandler(int sig)
2565 CmailSigHandler(sig)
2571 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2573 /* Activate call-back function CmailSigHandlerCallBack() */
2574 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2576 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2580 CmailSigHandlerCallBack(isr, closure, message, count, error)
2588 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2590 /**** end signal code ****/
2600 f = fopen(appData.icsLogon, "r");
2606 strcat(buf, appData.icsLogon);
2607 f = fopen(buf, "r");
2611 ProcessICSInitScript(f);
2618 EditCommentPopDown();
2633 if (!menuBarWidget) return;
2634 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2636 DisplayError("menuStep.Revert", 0);
2638 XtSetSensitive(w, !grey);
2640 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2642 DisplayError("menuStep.Annotate", 0);
2644 XtSetSensitive(w, !grey);
2649 SetMenuEnables(enab)
2653 if (!menuBarWidget) return;
2654 while (enab->name != NULL) {
2655 w = XtNameToWidget(menuBarWidget, enab->name);
2657 DisplayError(enab->name, 0);
2659 XtSetSensitive(w, enab->value);
2665 Enables icsEnables[] = {
2666 { "menuFile.Mail Move", False },
2667 { "menuFile.Reload CMail Message", False },
2668 { "menuMode.Machine Black", False },
2669 { "menuMode.Machine White", False },
2670 { "menuMode.Analysis Mode", False },
2671 { "menuMode.Analyze File", False },
2672 { "menuMode.Two Machines", False },
2674 { "menuHelp.Hint", False },
2675 { "menuHelp.Book", False },
2676 { "menuStep.Move Now", False },
2677 { "menuOptions.Periodic Updates", False },
2678 { "menuOptions.Hide Thinking", False },
2679 { "menuOptions.Ponder Next Move", False },
2681 { "menuStep.Annotate", False },
2685 Enables ncpEnables[] = {
2686 { "menuFile.Mail Move", False },
2687 { "menuFile.Reload CMail Message", False },
2688 { "menuMode.Machine White", False },
2689 { "menuMode.Machine Black", False },
2690 { "menuMode.Analysis Mode", False },
2691 { "menuMode.Analyze File", False },
2692 { "menuMode.Two Machines", False },
2693 { "menuMode.ICS Client", False },
2694 { "menuMode.ICS Input Box", False },
2695 { "Action", False },
2696 { "menuStep.Revert", False },
2697 { "menuStep.Annotate", False },
2698 { "menuStep.Move Now", False },
2699 { "menuStep.Retract Move", False },
2700 { "menuOptions.Auto Comment", False },
2701 { "menuOptions.Auto Flag", False },
2702 { "menuOptions.Auto Flip View", False },
2703 { "menuOptions.Auto Observe", False },
2704 { "menuOptions.Auto Raise Board", False },
2705 { "menuOptions.Get Move List", False },
2706 { "menuOptions.ICS Alarm", False },
2707 { "menuOptions.Move Sound", False },
2708 { "menuOptions.Quiet Play", False },
2709 { "menuOptions.Hide Thinking", False },
2710 { "menuOptions.Periodic Updates", False },
2711 { "menuOptions.Ponder Next Move", False },
2712 { "menuHelp.Hint", False },
2713 { "menuHelp.Book", False },
2717 Enables gnuEnables[] = {
2718 { "menuMode.ICS Client", False },
2719 { "menuMode.ICS Input Box", False },
2720 { "menuAction.Accept", False },
2721 { "menuAction.Decline", False },
2722 { "menuAction.Rematch", False },
2723 { "menuAction.Adjourn", False },
2724 { "menuAction.Stop Examining", False },
2725 { "menuAction.Stop Observing", False },
2726 { "menuAction.Upload to Examine", False },
2727 { "menuStep.Revert", False },
2728 { "menuStep.Annotate", False },
2729 { "menuOptions.Auto Comment", False },
2730 { "menuOptions.Auto Observe", False },
2731 { "menuOptions.Auto Raise Board", False },
2732 { "menuOptions.Get Move List", False },
2733 { "menuOptions.Premove", False },
2734 { "menuOptions.Quiet Play", False },
2736 /* The next two options rely on SetCmailMode being called *after* */
2737 /* SetGNUMode so that when GNU is being used to give hints these */
2738 /* menu options are still available */
2740 { "menuFile.Mail Move", False },
2741 { "menuFile.Reload CMail Message", False },
2745 Enables cmailEnables[] = {
2747 { "menuAction.Call Flag", False },
2748 { "menuAction.Draw", True },
2749 { "menuAction.Adjourn", False },
2750 { "menuAction.Abort", False },
2751 { "menuAction.Stop Observing", False },
2752 { "menuAction.Stop Examining", False },
2753 { "menuFile.Mail Move", True },
2754 { "menuFile.Reload CMail Message", True },
2758 Enables trainingOnEnables[] = {
2759 { "menuMode.Edit Comment", False },
2760 { "menuMode.Pause", False },
2761 { "menuStep.Forward", False },
2762 { "menuStep.Backward", False },
2763 { "menuStep.Forward to End", False },
2764 { "menuStep.Back to Start", False },
2765 { "menuStep.Move Now", False },
2766 { "menuStep.Truncate Game", False },
2770 Enables trainingOffEnables[] = {
2771 { "menuMode.Edit Comment", True },
2772 { "menuMode.Pause", True },
2773 { "menuStep.Forward", True },
2774 { "menuStep.Backward", True },
2775 { "menuStep.Forward to End", True },
2776 { "menuStep.Back to Start", True },
2777 { "menuStep.Move Now", True },
2778 { "menuStep.Truncate Game", True },
2782 Enables machineThinkingEnables[] = {
2783 { "menuFile.Load Game", False },
2784 { "menuFile.Load Next Game", False },
2785 { "menuFile.Load Previous Game", False },
2786 { "menuFile.Reload Same Game", False },
2787 { "menuFile.Paste Game", False },
2788 { "menuFile.Load Position", False },
2789 { "menuFile.Load Next Position", False },
2790 { "menuFile.Load Previous Position", False },
2791 { "menuFile.Reload Same Position", False },
2792 { "menuFile.Paste Position", False },
2793 { "menuMode.Machine White", False },
2794 { "menuMode.Machine Black", False },
2795 { "menuMode.Two Machines", False },
2796 { "menuStep.Retract Move", False },
2800 Enables userThinkingEnables[] = {
2801 { "menuFile.Load Game", True },
2802 { "menuFile.Load Next Game", True },
2803 { "menuFile.Load Previous Game", True },
2804 { "menuFile.Reload Same Game", True },
2805 { "menuFile.Paste Game", True },
2806 { "menuFile.Load Position", True },
2807 { "menuFile.Load Next Position", True },
2808 { "menuFile.Load Previous Position", True },
2809 { "menuFile.Reload Same Position", True },
2810 { "menuFile.Paste Position", True },
2811 { "menuMode.Machine White", True },
2812 { "menuMode.Machine Black", True },
2813 { "menuMode.Two Machines", True },
2814 { "menuStep.Retract Move", True },
2820 SetMenuEnables(icsEnables);
2823 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2824 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2831 SetMenuEnables(ncpEnables);
2837 SetMenuEnables(gnuEnables);
2843 SetMenuEnables(cmailEnables);
2849 SetMenuEnables(trainingOnEnables);
2850 if (appData.showButtonBar) {
2851 XtSetSensitive(buttonBarWidget, False);
2857 SetTrainingModeOff()
2859 SetMenuEnables(trainingOffEnables);
2860 if (appData.showButtonBar) {
2861 XtSetSensitive(buttonBarWidget, True);
2866 SetUserThinkingEnables()
2868 if (appData.noChessProgram) return;
2869 SetMenuEnables(userThinkingEnables);
2873 SetMachineThinkingEnables()
2875 if (appData.noChessProgram) return;
2876 SetMenuEnables(machineThinkingEnables);
2878 case MachinePlaysBlack:
2879 case MachinePlaysWhite:
2880 case TwoMachinesPlay:
2881 XtSetSensitive(XtNameToWidget(menuBarWidget,
2882 ModeToWidgetName(gameMode)), True);
2889 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2890 #define HISTORY_SIZE 64
\r
2891 static char *history[HISTORY_SIZE];
\r
2892 int histIn = 0, histP = 0;
\r
2895 SaveInHistory(char *cmd)
\r
2897 if (history[histIn] != NULL) {
\r
2898 free(history[histIn]);
\r
2899 history[histIn] = NULL;
\r
2901 if (*cmd == NULLCHAR) return;
\r
2902 history[histIn] = StrSave(cmd);
\r
2903 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2904 if (history[histIn] != NULL) {
\r
2905 free(history[histIn]);
\r
2906 history[histIn] = NULL;
\r
2912 PrevInHistory(char *cmd)
\r
2915 if (histP == histIn) {
\r
2916 if (history[histIn] != NULL) free(history[histIn]);
\r
2917 history[histIn] = StrSave(cmd);
\r
2919 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2920 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2922 return history[histP];
\r
2928 if (histP == histIn) return NULL;
\r
2929 histP = (histP + 1) % HISTORY_SIZE;
\r
2930 return history[histP];
\r
2932 // end of borrowed code
\r
2934 #define Abs(n) ((n)<0 ? -(n) : (n))
2937 * Find a font that matches "pattern" that is as close as
2938 * possible to the targetPxlSize. Prefer fonts that are k
2939 * pixels smaller to fonts that are k pixels larger. The
2940 * pattern must be in the X Consortium standard format,
2941 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2942 * The return value should be freed with XtFree when no
2945 char *FindFont(pattern, targetPxlSize)
2949 char **fonts, *p, *best, *scalable, *scalableTail;
2950 int i, j, nfonts, minerr, err, pxlSize;
2953 char **missing_list;
2955 char *def_string, *base_fnt_lst, strInt[3];
2957 XFontStruct **fnt_list;
2959 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2960 sprintf(strInt, "%d", targetPxlSize);
2961 p = strstr(pattern, "--");
2962 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2963 strcat(base_fnt_lst, strInt);
2964 strcat(base_fnt_lst, strchr(p + 2, '-'));
2966 if ((fntSet = XCreateFontSet(xDisplay,
2970 &def_string)) == NULL) {
2972 fprintf(stderr, _("Unable to create font set.\n"));
2976 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2978 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2980 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2981 programName, pattern);
2989 for (i=0; i<nfonts; i++) {
2992 if (*p != '-') continue;
2994 if (*p == NULLCHAR) break;
2995 if (*p++ == '-') j++;
2997 if (j < 7) continue;
3000 scalable = fonts[i];
3003 err = pxlSize - targetPxlSize;
3004 if (Abs(err) < Abs(minerr) ||
3005 (minerr > 0 && err < 0 && -err == minerr)) {
3011 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3012 /* If the error is too big and there is a scalable font,
3013 use the scalable font. */
3014 int headlen = scalableTail - scalable;
3015 p = (char *) XtMalloc(strlen(scalable) + 10);
3016 while (isdigit(*scalableTail)) scalableTail++;
3017 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3019 p = (char *) XtMalloc(strlen(best) + 1);
3022 if (appData.debugMode) {
3023 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3024 pattern, targetPxlSize, p);
3027 if (missing_count > 0)
3028 XFreeStringList(missing_list);
3029 XFreeFontSet(xDisplay, fntSet);
3031 XFreeFontNames(fonts);
3038 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3039 | GCBackground | GCFunction | GCPlaneMask;
3040 XGCValues gc_values;
3043 gc_values.plane_mask = AllPlanes;
3044 gc_values.line_width = lineGap;
3045 gc_values.line_style = LineSolid;
3046 gc_values.function = GXcopy;
3048 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3049 gc_values.background = XBlackPixel(xDisplay, xScreen);
3050 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3052 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3053 gc_values.background = XWhitePixel(xDisplay, xScreen);
3054 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3055 XSetFont(xDisplay, coordGC, coordFontID);
3057 // [HGM] make font for holdings counts (white on black0
3058 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3059 gc_values.background = XBlackPixel(xDisplay, xScreen);
3060 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3061 XSetFont(xDisplay, countGC, countFontID);
3063 if (appData.monoMode) {
3064 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3065 gc_values.background = XWhitePixel(xDisplay, xScreen);
3066 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3068 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3069 gc_values.background = XBlackPixel(xDisplay, xScreen);
3070 lightSquareGC = wbPieceGC
3071 = XtGetGC(shellWidget, value_mask, &gc_values);
3073 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3074 gc_values.background = XWhitePixel(xDisplay, xScreen);
3075 darkSquareGC = bwPieceGC
3076 = XtGetGC(shellWidget, value_mask, &gc_values);
3078 if (DefaultDepth(xDisplay, xScreen) == 1) {
3079 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3080 gc_values.function = GXcopyInverted;
3081 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3082 gc_values.function = GXcopy;
3083 if (XBlackPixel(xDisplay, xScreen) == 1) {
3084 bwPieceGC = darkSquareGC;
3085 wbPieceGC = copyInvertedGC;
3087 bwPieceGC = copyInvertedGC;
3088 wbPieceGC = lightSquareGC;
3092 gc_values.foreground = highlightSquareColor;
3093 gc_values.background = highlightSquareColor;
3094 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3096 gc_values.foreground = premoveHighlightColor;
3097 gc_values.background = premoveHighlightColor;
3098 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3100 gc_values.foreground = lightSquareColor;
3101 gc_values.background = darkSquareColor;
3102 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3104 gc_values.foreground = darkSquareColor;
3105 gc_values.background = lightSquareColor;
3106 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3108 gc_values.foreground = jailSquareColor;
3109 gc_values.background = jailSquareColor;
3110 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3112 gc_values.foreground = whitePieceColor;
3113 gc_values.background = darkSquareColor;
3114 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3116 gc_values.foreground = whitePieceColor;
3117 gc_values.background = lightSquareColor;
3118 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3120 gc_values.foreground = whitePieceColor;
3121 gc_values.background = jailSquareColor;
3122 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3124 gc_values.foreground = blackPieceColor;
3125 gc_values.background = darkSquareColor;
3126 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3128 gc_values.foreground = blackPieceColor;
3129 gc_values.background = lightSquareColor;
3130 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3132 gc_values.foreground = blackPieceColor;
3133 gc_values.background = jailSquareColor;
3134 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3138 void loadXIM(xim, xmask, filename, dest, mask)
3151 fp = fopen(filename, "rb");
3153 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3160 for (y=0; y<h; ++y) {
3161 for (x=0; x<h; ++x) {
3166 XPutPixel(xim, x, y, blackPieceColor);
3168 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3171 XPutPixel(xim, x, y, darkSquareColor);
3173 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3176 XPutPixel(xim, x, y, whitePieceColor);
3178 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3181 XPutPixel(xim, x, y, lightSquareColor);
3183 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3189 /* create Pixmap of piece */
3190 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3192 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3195 /* create Pixmap of clipmask
3196 Note: We assume the white/black pieces have the same
3197 outline, so we make only 6 masks. This is okay
3198 since the XPM clipmask routines do the same. */
3200 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3202 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3205 /* now create the 1-bit version */
3206 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3209 values.foreground = 1;
3210 values.background = 0;
3212 /* Don't use XtGetGC, not read only */
3213 maskGC = XCreateGC(xDisplay, *mask,
3214 GCForeground | GCBackground, &values);
3215 XCopyPlane(xDisplay, temp, *mask, maskGC,
3216 0, 0, squareSize, squareSize, 0, 0, 1);
3217 XFreePixmap(xDisplay, temp);
3222 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3224 void CreateXIMPieces()
3229 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3234 /* The XSynchronize calls were copied from CreatePieces.
3235 Not sure if needed, but can't hurt */
3236 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3239 /* temp needed by loadXIM() */
3240 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3241 0, 0, ss, ss, AllPlanes, XYPixmap);
3243 if (strlen(appData.pixmapDirectory) == 0) {
3247 if (appData.monoMode) {
3248 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3252 fprintf(stderr, _("\nLoading XIMs...\n"));
3254 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3255 fprintf(stderr, "%d", piece+1);
3256 for (kind=0; kind<4; kind++) {
3257 fprintf(stderr, ".");
3258 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3259 ExpandPathName(appData.pixmapDirectory),
3260 piece <= (int) WhiteKing ? "" : "w",
3261 pieceBitmapNames[piece],
3263 ximPieceBitmap[kind][piece] =
3264 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3265 0, 0, ss, ss, AllPlanes, XYPixmap);
3266 if (appData.debugMode)
3267 fprintf(stderr, _("(File:%s:) "), buf);
3268 loadXIM(ximPieceBitmap[kind][piece],
3270 &(xpmPieceBitmap2[kind][piece]),
3271 &(ximMaskPm2[piece]));
3272 if(piece <= (int)WhiteKing)
3273 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3275 fprintf(stderr," ");
3277 /* Load light and dark squares */
3278 /* If the LSQ and DSQ pieces don't exist, we will
3279 draw them with solid squares. */
3280 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3281 if (access(buf, 0) != 0) {
3285 fprintf(stderr, _("light square "));
3287 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3288 0, 0, ss, ss, AllPlanes, XYPixmap);
3289 if (appData.debugMode)
3290 fprintf(stderr, _("(File:%s:) "), buf);
3292 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3293 fprintf(stderr, _("dark square "));
3294 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3295 ExpandPathName(appData.pixmapDirectory), ss);
3296 if (appData.debugMode)
3297 fprintf(stderr, _("(File:%s:) "), buf);
3299 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3300 0, 0, ss, ss, AllPlanes, XYPixmap);
3301 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3302 xpmJailSquare = xpmLightSquare;
3304 fprintf(stderr, _("Done.\n"));
3306 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3310 void CreateXPMPieces()
3314 u_int ss = squareSize;
3316 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3317 XpmColorSymbol symbols[4];
3319 /* The XSynchronize calls were copied from CreatePieces.
3320 Not sure if needed, but can't hurt */
3321 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3323 /* Setup translations so piece colors match square colors */
3324 symbols[0].name = "light_piece";
3325 symbols[0].value = appData.whitePieceColor;
3326 symbols[1].name = "dark_piece";
3327 symbols[1].value = appData.blackPieceColor;
3328 symbols[2].name = "light_square";
3329 symbols[2].value = appData.lightSquareColor;
3330 symbols[3].name = "dark_square";
3331 symbols[3].value = appData.darkSquareColor;
3333 attr.valuemask = XpmColorSymbols;
3334 attr.colorsymbols = symbols;
3335 attr.numsymbols = 4;
3337 if (appData.monoMode) {
3338 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3342 if (strlen(appData.pixmapDirectory) == 0) {
3343 XpmPieces* pieces = builtInXpms;
3346 while (pieces->size != squareSize && pieces->size) pieces++;
3347 if (!pieces->size) {
3348 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3351 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3352 for (kind=0; kind<4; kind++) {
3354 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3355 pieces->xpm[piece][kind],
3356 &(xpmPieceBitmap2[kind][piece]),
3357 NULL, &attr)) != 0) {
3358 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3362 if(piece <= (int) WhiteKing)
3363 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3367 xpmJailSquare = xpmLightSquare;
3371 fprintf(stderr, _("\nLoading XPMs...\n"));
3374 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3375 fprintf(stderr, "%d ", piece+1);
3376 for (kind=0; kind<4; kind++) {
3377 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3378 ExpandPathName(appData.pixmapDirectory),
3379 piece > (int) WhiteKing ? "w" : "",
3380 pieceBitmapNames[piece],
3382 if (appData.debugMode) {
3383 fprintf(stderr, _("(File:%s:) "), buf);
3385 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3386 &(xpmPieceBitmap2[kind][piece]),
3387 NULL, &attr)) != 0) {
3388 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3389 // [HGM] missing: read of unorthodox piece failed; substitute King.
3390 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3391 ExpandPathName(appData.pixmapDirectory),
3393 if (appData.debugMode) {
3394 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3396 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3397 &(xpmPieceBitmap2[kind][piece]),
3401 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3406 if(piece <= (int) WhiteKing)
3407 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3410 /* Load light and dark squares */
3411 /* If the LSQ and DSQ pieces don't exist, we will
3412 draw them with solid squares. */
3413 fprintf(stderr, _("light square "));
3414 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3415 if (access(buf, 0) != 0) {
3419 if (appData.debugMode)
3420 fprintf(stderr, _("(File:%s:) "), buf);
3422 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3423 &xpmLightSquare, NULL, &attr)) != 0) {
3424 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3427 fprintf(stderr, _("dark square "));
3428 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3429 ExpandPathName(appData.pixmapDirectory), ss);
3430 if (appData.debugMode) {
3431 fprintf(stderr, _("(File:%s:) "), buf);
3433 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3434 &xpmDarkSquare, NULL, &attr)) != 0) {
3435 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3439 xpmJailSquare = xpmLightSquare;
3440 fprintf(stderr, _("Done.\n"));
3442 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3445 #endif /* HAVE_LIBXPM */
3448 /* No built-in bitmaps */
3453 u_int ss = squareSize;
3455 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3458 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3459 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3460 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3461 pieceBitmapNames[piece],
3462 ss, kind == SOLID ? 's' : 'o');
3463 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3464 if(piece <= (int)WhiteKing)
3465 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3469 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3473 /* With built-in bitmaps */
3476 BuiltInBits* bib = builtInBits;
3479 u_int ss = squareSize;
3481 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3484 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3486 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3487 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3488 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3489 pieceBitmapNames[piece],
3490 ss, kind == SOLID ? 's' : 'o');
3491 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3492 bib->bits[kind][piece], ss, ss);
3493 if(piece <= (int)WhiteKing)
3494 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3498 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3503 void ReadBitmap(pm, name, bits, wreq, hreq)
3506 unsigned char bits[];
3512 char msg[MSG_SIZ], fullname[MSG_SIZ];
3514 if (*appData.bitmapDirectory != NULLCHAR) {
3515 strcpy(fullname, appData.bitmapDirectory);
3516 strcat(fullname, "/");
3517 strcat(fullname, name);
3518 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3519 &w, &h, pm, &x_hot, &y_hot);
3520 fprintf(stderr, "load %s\n", name);
3521 if (errcode != BitmapSuccess) {
3523 case BitmapOpenFailed:
3524 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3526 case BitmapFileInvalid:
3527 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3529 case BitmapNoMemory:
3530 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3534 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3538 fprintf(stderr, _("%s: %s...using built-in\n"),
3540 } else if (w != wreq || h != hreq) {
3542 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3543 programName, fullname, w, h, wreq, hreq);
3549 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3558 if (lineGap == 0) return;
3560 /* [HR] Split this into 2 loops for non-square boards. */
3562 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3563 gridSegments[i].x1 = 0;
3564 gridSegments[i].x2 =
3565 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3566 gridSegments[i].y1 = gridSegments[i].y2
3567 = lineGap / 2 + (i * (squareSize + lineGap));
3570 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3571 gridSegments[j + i].y1 = 0;
3572 gridSegments[j + i].y2 =
3573 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3574 gridSegments[j + i].x1 = gridSegments[j + i].x2
3575 = lineGap / 2 + (j * (squareSize + lineGap));
3579 static void MenuBarSelect(w, addr, index)
3584 XtActionProc proc = (XtActionProc) addr;
3586 (proc)(NULL, NULL, NULL, NULL);
3589 void CreateMenuBarPopup(parent, name, mb)
3599 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3602 XtSetArg(args[j], XtNleftMargin, 20); j++;
3603 XtSetArg(args[j], XtNrightMargin, 20); j++;
3605 while (mi->string != NULL) {
3606 if (strcmp(mi->string, "----") == 0) {
3607 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3610 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3611 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3613 XtAddCallback(entry, XtNcallback,
3614 (XtCallbackProc) MenuBarSelect,
3615 (caddr_t) mi->proc);
3621 Widget CreateMenuBar(mb)
3625 Widget anchor, menuBar;
3627 char menuName[MSG_SIZ];
3630 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3631 XtSetArg(args[j], XtNvSpace, 0); j++;
3632 XtSetArg(args[j], XtNborderWidth, 0); j++;
3633 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3634 formWidget, args, j);
3636 while (mb->name != NULL) {
3637 strcpy(menuName, "menu");
3638 strcat(menuName, mb->name);
3640 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3643 shortName[0] = _(mb->name)[0];
3644 shortName[1] = NULLCHAR;
3645 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3648 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3651 XtSetArg(args[j], XtNborderWidth, 0); j++;
3652 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3654 CreateMenuBarPopup(menuBar, menuName, mb);
3660 Widget CreateButtonBar(mi)
3664 Widget button, buttonBar;
3668 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3670 XtSetArg(args[j], XtNhSpace, 0); j++;
3672 XtSetArg(args[j], XtNborderWidth, 0); j++;
3673 XtSetArg(args[j], XtNvSpace, 0); j++;
3674 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3675 formWidget, args, j);
3677 while (mi->string != NULL) {
3680 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3681 XtSetArg(args[j], XtNborderWidth, 0); j++;
3683 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3684 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3685 buttonBar, args, j);
3686 XtAddCallback(button, XtNcallback,
3687 (XtCallbackProc) MenuBarSelect,
3688 (caddr_t) mi->proc);
3695 CreatePieceMenu(name, color)
3702 ChessSquare selection;
3704 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3705 boardWidget, args, 0);
3707 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3708 String item = pieceMenuStrings[color][i];
3710 if (strcmp(item, "----") == 0) {
3711 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3714 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3715 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3717 selection = pieceMenuTranslation[color][i];
3718 XtAddCallback(entry, XtNcallback,
3719 (XtCallbackProc) PieceMenuSelect,
3720 (caddr_t) selection);
3721 if (selection == WhitePawn || selection == BlackPawn) {
3722 XtSetArg(args[0], XtNpopupOnEntry, entry);
3723 XtSetValues(menu, args, 1);
3736 ChessSquare selection;
3738 whitePieceMenu = CreatePieceMenu("menuW", 0);
3739 blackPieceMenu = CreatePieceMenu("menuB", 1);
3741 XtRegisterGrabAction(PieceMenuPopup, True,
3742 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3743 GrabModeAsync, GrabModeAsync);
3745 XtSetArg(args[0], XtNlabel, _("Drop"));
3746 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3747 boardWidget, args, 1);
3748 for (i = 0; i < DROP_MENU_SIZE; i++) {
3749 String item = dropMenuStrings[i];
3751 if (strcmp(item, "----") == 0) {
3752 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3755 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3756 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3758 selection = dropMenuTranslation[i];
3759 XtAddCallback(entry, XtNcallback,
3760 (XtCallbackProc) DropMenuSelect,
3761 (caddr_t) selection);
3766 void SetupDropMenu()
3774 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3775 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3776 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3777 dmEnables[i].piece);
3778 XtSetSensitive(entry, p != NULL || !appData.testLegality
3779 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3780 && !appData.icsActive));
3782 while (p && *p++ == dmEnables[i].piece) count++;
3783 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3785 XtSetArg(args[j], XtNlabel, label); j++;
3786 XtSetValues(entry, args, j);
3790 void PieceMenuPopup(w, event, params, num_params)
3794 Cardinal *num_params;
3796 String whichMenu; int menuNr;
3797 if (event->type == ButtonRelease)
3798 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3799 else if (event->type == ButtonPress)
3800 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3802 case 0: whichMenu = params[0]; break;
3803 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3805 case -1: if (errorUp) ErrorPopDown();
3808 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3811 static void PieceMenuSelect(w, piece, junk)
3816 if (pmFromX < 0 || pmFromY < 0) return;
3817 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3820 static void DropMenuSelect(w, piece, junk)
3825 if (pmFromX < 0 || pmFromY < 0) return;
3826 DropMenuEvent(piece, pmFromX, pmFromY);
3829 void WhiteClock(w, event, prms, nprms)
3835 if (gameMode == EditPosition || gameMode == IcsExamining) {
3836 SetWhiteToPlayEvent();
3837 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3842 void BlackClock(w, event, prms, nprms)
3848 if (gameMode == EditPosition || gameMode == IcsExamining) {
3849 SetBlackToPlayEvent();
3850 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3857 * If the user selects on a border boundary, return -1; if off the board,
3858 * return -2. Otherwise map the event coordinate to the square.
3860 int EventToSquare(x, limit)
3868 if ((x % (squareSize + lineGap)) >= squareSize)
3870 x /= (squareSize + lineGap);
3876 static void do_flash_delay(msec)
3882 static void drawHighlight(file, rank, gc)
3888 if (lineGap == 0 || appData.blindfold) return;
3891 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3892 (squareSize + lineGap);
3893 y = lineGap/2 + rank * (squareSize + lineGap);
3895 x = lineGap/2 + file * (squareSize + lineGap);
3896 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3897 (squareSize + lineGap);
3900 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3901 squareSize+lineGap, squareSize+lineGap);
3904 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3905 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3908 SetHighlights(fromX, fromY, toX, toY)
3909 int fromX, fromY, toX, toY;
3911 if (hi1X != fromX || hi1Y != fromY) {
3912 if (hi1X >= 0 && hi1Y >= 0) {
3913 drawHighlight(hi1X, hi1Y, lineGC);
3915 } // [HGM] first erase both, then draw new!
3916 if (hi2X != toX || hi2Y != toY) {
3917 if (hi2X >= 0 && hi2Y >= 0) {
3918 drawHighlight(hi2X, hi2Y, lineGC);
3921 if (hi1X != fromX || hi1Y != fromY) {
3922 if (fromX >= 0 && fromY >= 0) {
3923 drawHighlight(fromX, fromY, highlineGC);
3926 if (hi2X != toX || hi2Y != toY) {
3927 if (toX >= 0 && toY >= 0) {
3928 drawHighlight(toX, toY, highlineGC);
3940 SetHighlights(-1, -1, -1, -1);
3945 SetPremoveHighlights(fromX, fromY, toX, toY)
3946 int fromX, fromY, toX, toY;
3948 if (pm1X != fromX || pm1Y != fromY) {
3949 if (pm1X >= 0 && pm1Y >= 0) {
3950 drawHighlight(pm1X, pm1Y, lineGC);
3952 if (fromX >= 0 && fromY >= 0) {
3953 drawHighlight(fromX, fromY, prelineGC);
3956 if (pm2X != toX || pm2Y != toY) {
3957 if (pm2X >= 0 && pm2Y >= 0) {
3958 drawHighlight(pm2X, pm2Y, lineGC);
3960 if (toX >= 0 && toY >= 0) {
3961 drawHighlight(toX, toY, prelineGC);
3971 ClearPremoveHighlights()
3973 SetPremoveHighlights(-1, -1, -1, -1);
3976 static void BlankSquare(x, y, color, piece, dest)
3981 if (useImages && useImageSqs) {
3985 pm = xpmLightSquare;
3990 case 2: /* neutral */
3995 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3996 squareSize, squareSize, x, y);
4006 case 2: /* neutral */
4011 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4016 I split out the routines to draw a piece so that I could
4017 make a generic flash routine.
4019 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4021 int square_color, x, y;
4024 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4025 switch (square_color) {
4027 case 2: /* neutral */
4029 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4030 ? *pieceToOutline(piece)
4031 : *pieceToSolid(piece),
4032 dest, bwPieceGC, 0, 0,
4033 squareSize, squareSize, x, y);
4036 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4037 ? *pieceToSolid(piece)
4038 : *pieceToOutline(piece),
4039 dest, wbPieceGC, 0, 0,
4040 squareSize, squareSize, x, y);
4045 static void monoDrawPiece(piece, square_color, x, y, dest)
4047 int square_color, x, y;
4050 switch (square_color) {
4052 case 2: /* neutral */
4054 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4055 ? *pieceToOutline(piece)
4056 : *pieceToSolid(piece),
4057 dest, bwPieceGC, 0, 0,
4058 squareSize, squareSize, x, y, 1);
4061 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4062 ? *pieceToSolid(piece)
4063 : *pieceToOutline(piece),
4064 dest, wbPieceGC, 0, 0,
4065 squareSize, squareSize, x, y, 1);
4070 static void colorDrawPiece(piece, square_color, x, y, dest)
4072 int square_color, x, y;
4075 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4076 switch (square_color) {
4078 XCopyPlane(xDisplay, *pieceToSolid(piece),
4079 dest, (int) piece < (int) BlackPawn
4080 ? wlPieceGC : blPieceGC, 0, 0,
4081 squareSize, squareSize, x, y, 1);
4084 XCopyPlane(xDisplay, *pieceToSolid(piece),
4085 dest, (int) piece < (int) BlackPawn
4086 ? wdPieceGC : bdPieceGC, 0, 0,
4087 squareSize, squareSize, x, y, 1);
4089 case 2: /* neutral */
4091 XCopyPlane(xDisplay, *pieceToSolid(piece),
4092 dest, (int) piece < (int) BlackPawn
4093 ? wjPieceGC : bjPieceGC, 0, 0,
4094 squareSize, squareSize, x, y, 1);
4099 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4101 int square_color, x, y;
4106 switch (square_color) {
4108 case 2: /* neutral */
4110 if ((int)piece < (int) BlackPawn) {
4118 if ((int)piece < (int) BlackPawn) {
4126 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4127 dest, wlPieceGC, 0, 0,
4128 squareSize, squareSize, x, y);
4131 typedef void (*DrawFunc)();
4133 DrawFunc ChooseDrawFunc()
4135 if (appData.monoMode) {
4136 if (DefaultDepth(xDisplay, xScreen) == 1) {
4137 return monoDrawPiece_1bit;
4139 return monoDrawPiece;
4143 return colorDrawPieceImage;
4145 return colorDrawPiece;
4149 /* [HR] determine square color depending on chess variant. */
4150 static int SquareColor(row, column)
4155 if (gameInfo.variant == VariantXiangqi) {
4156 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4158 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4160 } else if (row <= 4) {
4166 square_color = ((column + row) % 2) == 1;
4169 /* [hgm] holdings: next line makes all holdings squares light */
4170 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4172 return square_color;
4175 void DrawSquare(row, column, piece, do_flash)
4176 int row, column, do_flash;
4179 int square_color, x, y, direction, font_ascent, font_descent;
4182 XCharStruct overall;
4186 /* Calculate delay in milliseconds (2-delays per complete flash) */
4187 flash_delay = 500 / appData.flashRate;
4190 x = lineGap + ((BOARD_WIDTH-1)-column) *
4191 (squareSize + lineGap);
4192 y = lineGap + row * (squareSize + lineGap);
4194 x = lineGap + column * (squareSize + lineGap);
4195 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4196 (squareSize + lineGap);
4199 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4201 square_color = SquareColor(row, column);
4203 if ( // [HGM] holdings: blank out area between board and holdings
4204 column == BOARD_LEFT-1 || column == BOARD_RGHT
4205 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4206 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4207 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4209 // [HGM] print piece counts next to holdings
4210 string[1] = NULLCHAR;
4211 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4212 string[0] = '0' + piece;
4213 XTextExtents(countFontStruct, string, 1, &direction,
4214 &font_ascent, &font_descent, &overall);
4215 if (appData.monoMode) {
4216 XDrawImageString(xDisplay, xBoardWindow, countGC,
4217 x + squareSize - overall.width - 2,
4218 y + font_ascent + 1, string, 1);
4220 XDrawString(xDisplay, xBoardWindow, countGC,
4221 x + squareSize - overall.width - 2,
4222 y + font_ascent + 1, string, 1);
4225 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4226 string[0] = '0' + piece;
4227 XTextExtents(countFontStruct, string, 1, &direction,
4228 &font_ascent, &font_descent, &overall);
4229 if (appData.monoMode) {
4230 XDrawImageString(xDisplay, xBoardWindow, countGC,
4231 x + 2, y + font_ascent + 1, string, 1);
4233 XDrawString(xDisplay, xBoardWindow, countGC,
4234 x + 2, y + font_ascent + 1, string, 1);
4238 if (piece == EmptySquare || appData.blindfold) {
4239 BlankSquare(x, y, square_color, piece, xBoardWindow);
4241 drawfunc = ChooseDrawFunc();
4242 if (do_flash && appData.flashCount > 0) {
4243 for (i=0; i<appData.flashCount; ++i) {
4245 drawfunc(piece, square_color, x, y, xBoardWindow);
4246 XSync(xDisplay, False);
4247 do_flash_delay(flash_delay);
4249 BlankSquare(x, y, square_color, piece, xBoardWindow);
4250 XSync(xDisplay, False);
4251 do_flash_delay(flash_delay);
4254 drawfunc(piece, square_color, x, y, xBoardWindow);
4258 string[1] = NULLCHAR;
4259 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4260 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4261 string[0] = 'a' + column - BOARD_LEFT;
4262 XTextExtents(coordFontStruct, string, 1, &direction,
4263 &font_ascent, &font_descent, &overall);
4264 if (appData.monoMode) {
4265 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4266 x + squareSize - overall.width - 2,
4267 y + squareSize - font_descent - 1, string, 1);
4269 XDrawString(xDisplay, xBoardWindow, coordGC,
4270 x + squareSize - overall.width - 2,
4271 y + squareSize - font_descent - 1, string, 1);
4274 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4275 string[0] = ONE + row;
4276 XTextExtents(coordFontStruct, string, 1, &direction,
4277 &font_ascent, &font_descent, &overall);
4278 if (appData.monoMode) {
4279 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4280 x + 2, y + font_ascent + 1, string, 1);
4282 XDrawString(xDisplay, xBoardWindow, coordGC,
4283 x + 2, y + font_ascent + 1, string, 1);
4286 if(!partnerUp && marker[row][column]) {
4287 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4288 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4293 /* Why is this needed on some versions of X? */
4294 void EventProc(widget, unused, event)
4299 if (!XtIsRealized(widget))
4302 switch (event->type) {
4304 if (event->xexpose.count > 0) return; /* no clipping is done */
4305 XDrawPosition(widget, True, NULL);
4306 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4307 flipView = !flipView; partnerUp = !partnerUp;
4308 XDrawPosition(widget, True, NULL);
4309 flipView = !flipView; partnerUp = !partnerUp;
4313 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4320 void DrawPosition(fullRedraw, board)
4321 /*Boolean*/int fullRedraw;
4324 XDrawPosition(boardWidget, fullRedraw, board);
4327 /* Returns 1 if there are "too many" differences between b1 and b2
4328 (i.e. more than 1 move was made) */
4329 static int too_many_diffs(b1, b2)
4335 for (i=0; i<BOARD_HEIGHT; ++i) {
4336 for (j=0; j<BOARD_WIDTH; ++j) {
4337 if (b1[i][j] != b2[i][j]) {
4338 if (++c > 4) /* Castling causes 4 diffs */
4347 /* Matrix describing castling maneuvers */
4348 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4349 static int castling_matrix[4][5] = {
4350 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4351 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4352 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4353 { 7, 7, 4, 5, 6 } /* 0-0, black */
4356 /* Checks whether castling occurred. If it did, *rrow and *rcol
4357 are set to the destination (row,col) of the rook that moved.
4359 Returns 1 if castling occurred, 0 if not.
4361 Note: Only handles a max of 1 castling move, so be sure
4362 to call too_many_diffs() first.
4364 static int check_castle_draw(newb, oldb, rrow, rcol)
4371 /* For each type of castling... */
4372 for (i=0; i<4; ++i) {
4373 r = castling_matrix[i];
4375 /* Check the 4 squares involved in the castling move */
4377 for (j=1; j<=4; ++j) {
4378 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4385 /* All 4 changed, so it must be a castling move */
4394 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4395 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4397 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4400 void DrawSeekBackground( int left, int top, int right, int bottom )
4402 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4405 void DrawSeekText(char *buf, int x, int y)
4407 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4410 void DrawSeekDot(int x, int y, int colorNr)
4412 int square = colorNr & 0x80;
4415 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4417 XFillRectangle(xDisplay, xBoardWindow, color,
4418 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4420 XFillArc(xDisplay, xBoardWindow, color,
4421 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4424 static int damage[2][BOARD_RANKS][BOARD_FILES];
4427 * event handler for redrawing the board
4429 void XDrawPosition(w, repaint, board)
4431 /*Boolean*/int repaint;
4435 static int lastFlipView = 0;
4436 static int lastBoardValid[2] = {0, 0};
4437 static Board lastBoard[2];
4440 int nr = twoBoards*partnerUp;
4442 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4444 if (board == NULL) {
4445 if (!lastBoardValid) return;
4446 board = lastBoard[nr];
4448 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4449 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4450 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4455 * It would be simpler to clear the window with XClearWindow()
4456 * but this causes a very distracting flicker.
4459 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4461 /* If too much changes (begin observing new game, etc.), don't
4463 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4465 /* Special check for castling so we don't flash both the king
4466 and the rook (just flash the king). */
4468 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4469 /* Draw rook with NO flashing. King will be drawn flashing later */
4470 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4471 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4475 /* First pass -- Draw (newly) empty squares and repair damage.
4476 This prevents you from having a piece show up twice while it
4477 is flashing on its new square */
4478 for (i = 0; i < BOARD_HEIGHT; i++)
4479 for (j = 0; j < BOARD_WIDTH; j++)
4480 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4481 || damage[nr][i][j]) {
4482 DrawSquare(i, j, board[i][j], 0);
4483 damage[nr][i][j] = False;
4486 /* Second pass -- Draw piece(s) in new position and flash them */
4487 for (i = 0; i < BOARD_HEIGHT; i++)
4488 for (j = 0; j < BOARD_WIDTH; j++)
4489 if (board[i][j] != lastBoard[nr][i][j]) {
4490 DrawSquare(i, j, board[i][j], do_flash);
4494 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4495 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4496 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4498 for (i = 0; i < BOARD_HEIGHT; i++)
4499 for (j = 0; j < BOARD_WIDTH; j++) {
4500 DrawSquare(i, j, board[i][j], 0);
4501 damage[nr][i][j] = False;
4505 CopyBoard(lastBoard[nr], board);
4506 lastBoardValid[nr] = 1;
4507 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4508 lastFlipView = flipView;
4510 /* Draw highlights */
4511 if (pm1X >= 0 && pm1Y >= 0) {
4512 drawHighlight(pm1X, pm1Y, prelineGC);
4514 if (pm2X >= 0 && pm2Y >= 0) {
4515 drawHighlight(pm2X, pm2Y, prelineGC);
4517 if (hi1X >= 0 && hi1Y >= 0) {
4518 drawHighlight(hi1X, hi1Y, highlineGC);
4520 if (hi2X >= 0 && hi2Y >= 0) {
4521 drawHighlight(hi2X, hi2Y, highlineGC);
4524 /* If piece being dragged around board, must redraw that too */
4527 XSync(xDisplay, False);
4532 * event handler for redrawing the board
4534 void DrawPositionProc(w, event, prms, nprms)
4540 XDrawPosition(w, True, NULL);
4545 * event handler for parsing user moves
4547 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4548 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4549 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4550 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4551 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4552 // and at the end FinishMove() to perform the move after optional promotion popups.
4553 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4554 void HandleUserMove(w, event, prms, nprms)
4560 if (w != boardWidget || errorExitStatus != -1) return;
4563 if (event->type == ButtonPress) {
4564 XtPopdown(promotionShell);
4565 XtDestroyWidget(promotionShell);
4566 promotionUp = False;
4574 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4575 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4576 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4579 void AnimateUserMove (Widget w, XEvent * event,
4580 String * params, Cardinal * nParams)
4582 DragPieceMove(event->xmotion.x, event->xmotion.y);
4585 void HandlePV (Widget w, XEvent * event,
4586 String * params, Cardinal * nParams)
4587 { // [HGM] pv: walk PV
4588 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4591 Widget CommentCreate(name, text, mutable, callback, lines)
4593 int /*Boolean*/ mutable;
4594 XtCallbackProc callback;
4598 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4603 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4604 XtGetValues(boardWidget, args, j);
4607 XtSetArg(args[j], XtNresizable, True); j++;
4610 XtCreatePopupShell(name, topLevelShellWidgetClass,
4611 shellWidget, args, j);
4614 XtCreatePopupShell(name, transientShellWidgetClass,
4615 shellWidget, args, j);
4618 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4619 layoutArgs, XtNumber(layoutArgs));
4621 XtCreateManagedWidget("form", formWidgetClass, layout,
4622 formArgs, XtNumber(formArgs));
4626 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4627 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4629 XtSetArg(args[j], XtNstring, text); j++;
4630 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4631 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4632 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4633 XtSetArg(args[j], XtNright, XtChainRight); j++;
4634 XtSetArg(args[j], XtNresizable, True); j++;
4635 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4636 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4637 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4638 XtSetArg(args[j], XtNautoFill, True); j++;
4639 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4641 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4642 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4646 XtSetArg(args[j], XtNfromVert, edit); j++;
4647 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4648 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4649 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4650 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4652 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4653 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4656 XtSetArg(args[j], XtNfromVert, edit); j++;
4657 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4658 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4659 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4660 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4661 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4663 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4664 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4667 XtSetArg(args[j], XtNfromVert, edit); j++;
4668 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4669 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4670 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4671 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4672 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4674 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4675 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4678 XtSetArg(args[j], XtNfromVert, edit); j++;
4679 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4680 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4681 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4682 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4684 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4685 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4688 XtSetArg(args[j], XtNfromVert, edit); j++;
4689 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4690 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4691 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4692 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4693 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4695 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4696 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4699 XtRealizeWidget(shell);
4701 if (commentX == -1) {
4704 Dimension pw_height;
4705 Dimension ew_height;
4708 XtSetArg(args[j], XtNheight, &ew_height); j++;
4709 XtGetValues(edit, args, j);
4712 XtSetArg(args[j], XtNheight, &pw_height); j++;
4713 XtGetValues(shell, args, j);
4714 commentH = pw_height + (lines - 1) * ew_height;
4715 commentW = bw_width - 16;
4717 XSync(xDisplay, False);
4719 /* This code seems to tickle an X bug if it is executed too soon
4720 after xboard starts up. The coordinates get transformed as if
4721 the main window was positioned at (0, 0).
4723 XtTranslateCoords(shellWidget,
4724 (bw_width - commentW) / 2, 0 - commentH / 2,
4725 &commentX, &commentY);
4727 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4728 RootWindowOfScreen(XtScreen(shellWidget)),
4729 (bw_width - commentW) / 2, 0 - commentH / 2,
4734 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4737 if(wpComment.width > 0) {
4738 commentX = wpComment.x;
4739 commentY = wpComment.y;
4740 commentW = wpComment.width;
4741 commentH = wpComment.height;
4745 XtSetArg(args[j], XtNheight, commentH); j++;
4746 XtSetArg(args[j], XtNwidth, commentW); j++;
4747 XtSetArg(args[j], XtNx, commentX); j++;
4748 XtSetArg(args[j], XtNy, commentY); j++;
4749 XtSetValues(shell, args, j);
4750 XtSetKeyboardFocus(shell, edit);
4755 /* Used for analysis window and ICS input window */
4756 Widget MiscCreate(name, text, mutable, callback, lines)
4758 int /*Boolean*/ mutable;
4759 XtCallbackProc callback;
4763 Widget shell, layout, form, edit;
4765 Dimension bw_width, pw_height, ew_height, w, h;
4771 XtSetArg(args[j], XtNresizable, True); j++;
4774 XtCreatePopupShell(name, topLevelShellWidgetClass,
4775 shellWidget, args, j);
4778 XtCreatePopupShell(name, transientShellWidgetClass,
4779 shellWidget, args, j);
4782 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4783 layoutArgs, XtNumber(layoutArgs));
4785 XtCreateManagedWidget("form", formWidgetClass, layout,
4786 formArgs, XtNumber(formArgs));
4790 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4791 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4793 XtSetArg(args[j], XtNstring, text); j++;
4794 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4795 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4796 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4797 XtSetArg(args[j], XtNright, XtChainRight); j++;
4798 XtSetArg(args[j], XtNresizable, True); j++;
4799 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4800 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4801 XtSetArg(args[j], XtNautoFill, True); j++;
4802 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4804 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4806 XtRealizeWidget(shell);
4809 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4810 XtGetValues(boardWidget, args, j);
4813 XtSetArg(args[j], XtNheight, &ew_height); j++;
4814 XtGetValues(edit, args, j);
4817 XtSetArg(args[j], XtNheight, &pw_height); j++;
4818 XtGetValues(shell, args, j);
4819 h = pw_height + (lines - 1) * ew_height;
4822 XSync(xDisplay, False);
4824 /* This code seems to tickle an X bug if it is executed too soon
4825 after xboard starts up. The coordinates get transformed as if
4826 the main window was positioned at (0, 0).
4828 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4830 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4831 RootWindowOfScreen(XtScreen(shellWidget)),
4832 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4836 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4839 XtSetArg(args[j], XtNheight, h); j++;
4840 XtSetArg(args[j], XtNwidth, w); j++;
4841 XtSetArg(args[j], XtNx, x); j++;
4842 XtSetArg(args[j], XtNy, y); j++;
4843 XtSetValues(shell, args, j);
4849 static int savedIndex; /* gross that this is global */
4851 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4854 XawTextPosition index, dummy;
4857 XawTextGetSelectionPos(w, &index, &dummy);
4858 XtSetArg(arg, XtNstring, &val);
4859 XtGetValues(w, &arg, 1);
4860 ReplaceComment(savedIndex, val);
4861 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4862 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4865 void EditCommentPopUp(index, title, text)
4874 if (text == NULL) text = "";
4876 if (editShell == NULL) {
4878 CommentCreate(title, text, True, EditCommentCallback, 4);
4879 XtRealizeWidget(editShell);
4880 CatchDeleteWindow(editShell, "EditCommentPopDown");
4882 edit = XtNameToWidget(editShell, "*form.text");
4884 XtSetArg(args[j], XtNstring, text); j++;
4885 XtSetValues(edit, args, j);
4887 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4888 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4889 XtSetValues(editShell, args, j);
4892 XtPopup(editShell, XtGrabNone);
4896 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4897 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4901 void EditCommentCallback(w, client_data, call_data)
4903 XtPointer client_data, call_data;
4911 XtSetArg(args[j], XtNlabel, &name); j++;
4912 XtGetValues(w, args, j);
4914 if (strcmp(name, _("ok")) == 0) {
4915 edit = XtNameToWidget(editShell, "*form.text");
4917 XtSetArg(args[j], XtNstring, &val); j++;
4918 XtGetValues(edit, args, j);
4919 ReplaceComment(savedIndex, val);
4920 EditCommentPopDown();
4921 } else if (strcmp(name, _("cancel")) == 0) {
4922 EditCommentPopDown();
4923 } else if (strcmp(name, _("clear")) == 0) {
4924 edit = XtNameToWidget(editShell, "*form.text");
4925 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4926 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4930 void EditCommentPopDown()
4935 if (!editUp) return;
4937 XtSetArg(args[j], XtNx, &commentX); j++;
4938 XtSetArg(args[j], XtNy, &commentY); j++;
4939 XtSetArg(args[j], XtNheight, &commentH); j++;
4940 XtSetArg(args[j], XtNwidth, &commentW); j++;
4941 XtGetValues(editShell, args, j);
4942 XtPopdown(editShell);
4945 XtSetArg(args[j], XtNleftBitmap, None); j++;
4946 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4950 void ICSInputBoxPopUp()
4955 char *title = _("ICS Input");
4958 if (ICSInputShell == NULL) {
4959 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4960 tr = XtParseTranslationTable(ICSInputTranslations);
4961 edit = XtNameToWidget(ICSInputShell, "*form.text");
4962 XtOverrideTranslations(edit, tr);
4963 XtRealizeWidget(ICSInputShell);
4964 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4967 edit = XtNameToWidget(ICSInputShell, "*form.text");
4969 XtSetArg(args[j], XtNstring, ""); j++;
4970 XtSetValues(edit, args, j);
4972 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4973 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4974 XtSetValues(ICSInputShell, args, j);
4977 XtPopup(ICSInputShell, XtGrabNone);
4978 XtSetKeyboardFocus(ICSInputShell, edit);
4980 ICSInputBoxUp = True;
4982 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4983 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4987 void ICSInputSendText()
4994 edit = XtNameToWidget(ICSInputShell, "*form.text");
4996 XtSetArg(args[j], XtNstring, &val); j++;
4997 XtGetValues(edit, args, j);
4999 SendMultiLineToICS(val);
5000 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5001 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5004 void ICSInputBoxPopDown()
5009 if (!ICSInputBoxUp) return;
5011 XtPopdown(ICSInputShell);
5012 ICSInputBoxUp = False;
5014 XtSetArg(args[j], XtNleftBitmap, None); j++;
5015 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5019 void CommentPopUp(title, text)
5026 savedIndex = currentMove; // [HGM] vari
5027 if (commentShell == NULL) {
5029 CommentCreate(title, text, False, CommentCallback, 4);
5030 XtRealizeWidget(commentShell);
5031 CatchDeleteWindow(commentShell, "CommentPopDown");
5033 edit = XtNameToWidget(commentShell, "*form.text");
5035 XtSetArg(args[j], XtNstring, text); j++;
5036 XtSetValues(edit, args, j);
5038 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5039 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5040 XtSetValues(commentShell, args, j);
5043 XtPopup(commentShell, XtGrabNone);
5044 XSync(xDisplay, False);
5049 void CommentCallback(w, client_data, call_data)
5051 XtPointer client_data, call_data;
5058 XtSetArg(args[j], XtNlabel, &name); j++;
5059 XtGetValues(w, args, j);
5061 if (strcmp(name, _("close")) == 0) {
5063 } else if (strcmp(name, _("edit")) == 0) {
5070 void CommentPopDown()
5075 if (!commentUp) return;
5077 XtSetArg(args[j], XtNx, &commentX); j++;
5078 XtSetArg(args[j], XtNy, &commentY); j++;
5079 XtSetArg(args[j], XtNwidth, &commentW); j++;
5080 XtSetArg(args[j], XtNheight, &commentH); j++;
5081 XtGetValues(commentShell, args, j);
5082 XtPopdown(commentShell);
5083 XSync(xDisplay, False);
5087 void FileNamePopUp(label, def, proc, openMode)
5094 Widget popup, layout, dialog, edit;
5100 fileProc = proc; /* I can't see a way not */
5101 fileOpenMode = openMode; /* to use globals here */
5102 { // [HGM] use file-selector dialog stolen from Ghostview
5104 int index; // this is not supported yet
5106 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5107 NULL, openMode, NULL, &name))
5108 (void) (*fileProc)(f, index=0, name);
5112 void FileNamePopDown()
5114 if (!filenameUp) return;
5115 XtPopdown(fileNameShell);
5116 XtDestroyWidget(fileNameShell);
5121 void FileNameCallback(w, client_data, call_data)
5123 XtPointer client_data, call_data;
5128 XtSetArg(args[0], XtNlabel, &name);
5129 XtGetValues(w, args, 1);
5131 if (strcmp(name, _("cancel")) == 0) {
5136 FileNameAction(w, NULL, NULL, NULL);
5139 void FileNameAction(w, event, prms, nprms)
5151 name = XawDialogGetValueString(w = XtParent(w));
5153 if ((name != NULL) && (*name != NULLCHAR)) {
5155 XtPopdown(w = XtParent(XtParent(w)));
5159 p = strrchr(buf, ' ');
5166 fullname = ExpandPathName(buf);
5168 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5171 f = fopen(fullname, fileOpenMode);
5173 DisplayError(_("Failed to open file"), errno);
5175 (void) (*fileProc)(f, index, buf);
5182 XtPopdown(w = XtParent(XtParent(w)));
5188 void PromotionPopUp()
5191 Widget dialog, layout;
5193 Dimension bw_width, pw_width;
5197 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5198 XtGetValues(boardWidget, args, j);
5201 XtSetArg(args[j], XtNresizable, True); j++;
5202 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5204 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5205 shellWidget, args, j);
5207 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5208 layoutArgs, XtNumber(layoutArgs));
5211 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5212 XtSetArg(args[j], XtNborderWidth, 0); j++;
5213 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5216 if(gameInfo.variant != VariantShogi) {
5217 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5218 (XtPointer) dialog);
5219 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5220 (XtPointer) dialog);
5221 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5222 (XtPointer) dialog);
5223 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5224 (XtPointer) dialog);
5225 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5226 gameInfo.variant == VariantGiveaway) {
5227 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5228 (XtPointer) dialog);
5230 if(gameInfo.variant == VariantCapablanca ||
5231 gameInfo.variant == VariantGothic ||
5232 gameInfo.variant == VariantCapaRandom) {
5233 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5234 (XtPointer) dialog);
5235 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5236 (XtPointer) dialog);
5238 } else // [HGM] shogi
5240 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5241 (XtPointer) dialog);
5242 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5243 (XtPointer) dialog);
5245 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5246 (XtPointer) dialog);
5248 XtRealizeWidget(promotionShell);
5249 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5252 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5253 XtGetValues(promotionShell, args, j);
5255 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5256 lineGap + squareSize/3 +
5257 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5258 0 : 6*(squareSize + lineGap)), &x, &y);
5261 XtSetArg(args[j], XtNx, x); j++;
5262 XtSetArg(args[j], XtNy, y); j++;
5263 XtSetValues(promotionShell, args, j);
5265 XtPopup(promotionShell, XtGrabNone);
5270 void PromotionPopDown()
5272 if (!promotionUp) return;
5273 XtPopdown(promotionShell);
5274 XtDestroyWidget(promotionShell);
5275 promotionUp = False;
5278 void PromotionCallback(w, client_data, call_data)
5280 XtPointer client_data, call_data;
5286 XtSetArg(args[0], XtNlabel, &name);
5287 XtGetValues(w, args, 1);
5291 if (fromX == -1) return;
5293 if (strcmp(name, _("cancel")) == 0) {
5297 } else if (strcmp(name, _("Knight")) == 0) {
5299 } else if (strcmp(name, _("Promote")) == 0) {
5301 } else if (strcmp(name, _("Defer")) == 0) {
5304 promoChar = ToLower(name[0]);
5307 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5309 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5310 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5315 void ErrorCallback(w, client_data, call_data)
5317 XtPointer client_data, call_data;
5320 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5322 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5328 if (!errorUp) return;
5330 XtPopdown(errorShell);
5331 XtDestroyWidget(errorShell);
5332 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5335 void ErrorPopUp(title, label, modal)
5336 char *title, *label;
5340 Widget dialog, layout;
5344 Dimension bw_width, pw_width;
5345 Dimension pw_height;
5349 XtSetArg(args[i], XtNresizable, True); i++;
5350 XtSetArg(args[i], XtNtitle, title); i++;
5352 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5353 shellWidget, args, i);
5355 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5356 layoutArgs, XtNumber(layoutArgs));
5359 XtSetArg(args[i], XtNlabel, label); i++;
5360 XtSetArg(args[i], XtNborderWidth, 0); i++;
5361 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5364 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5366 XtRealizeWidget(errorShell);
5367 CatchDeleteWindow(errorShell, "ErrorPopDown");
5370 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5371 XtGetValues(boardWidget, args, i);
5373 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5374 XtSetArg(args[i], XtNheight, &pw_height); i++;
5375 XtGetValues(errorShell, args, i);
5378 /* This code seems to tickle an X bug if it is executed too soon
5379 after xboard starts up. The coordinates get transformed as if
5380 the main window was positioned at (0, 0).
5382 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5383 0 - pw_height + squareSize / 3, &x, &y);
5385 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5386 RootWindowOfScreen(XtScreen(boardWidget)),
5387 (bw_width - pw_width) / 2,
5388 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5392 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5395 XtSetArg(args[i], XtNx, x); i++;
5396 XtSetArg(args[i], XtNy, y); i++;
5397 XtSetValues(errorShell, args, i);
5400 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5403 /* Disable all user input other than deleting the window */
5404 static int frozen = 0;
5408 /* Grab by a widget that doesn't accept input */
5409 XtAddGrab(messageWidget, TRUE, FALSE);
5413 /* Undo a FreezeUI */
5416 if (!frozen) return;
5417 XtRemoveGrab(messageWidget);
5421 char *ModeToWidgetName(mode)
5425 case BeginningOfGame:
5426 if (appData.icsActive)
5427 return "menuMode.ICS Client";
5428 else if (appData.noChessProgram ||
5429 *appData.cmailGameName != NULLCHAR)
5430 return "menuMode.Edit Game";
5432 return "menuMode.Machine Black";
5433 case MachinePlaysBlack:
5434 return "menuMode.Machine Black";
5435 case MachinePlaysWhite:
5436 return "menuMode.Machine White";
5438 return "menuMode.Analysis Mode";
5440 return "menuMode.Analyze File";
5441 case TwoMachinesPlay:
5442 return "menuMode.Two Machines";
5444 return "menuMode.Edit Game";
5445 case PlayFromGameFile:
5446 return "menuFile.Load Game";
5448 return "menuMode.Edit Position";
5450 return "menuMode.Training";
5451 case IcsPlayingWhite:
5452 case IcsPlayingBlack:
5456 return "menuMode.ICS Client";
5463 void ModeHighlight()
5466 static int oldPausing = FALSE;
5467 static GameMode oldmode = (GameMode) -1;
5470 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5472 if (pausing != oldPausing) {
5473 oldPausing = pausing;
5475 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5477 XtSetArg(args[0], XtNleftBitmap, None);
5479 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5482 if (appData.showButtonBar) {
5483 /* Always toggle, don't set. Previous code messes up when
5484 invoked while the button is pressed, as releasing it
5485 toggles the state again. */
5488 XtSetArg(args[0], XtNbackground, &oldbg);
5489 XtSetArg(args[1], XtNforeground, &oldfg);
5490 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5492 XtSetArg(args[0], XtNbackground, oldfg);
5493 XtSetArg(args[1], XtNforeground, oldbg);
5495 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5499 wname = ModeToWidgetName(oldmode);
5500 if (wname != NULL) {
5501 XtSetArg(args[0], XtNleftBitmap, None);
5502 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5504 wname = ModeToWidgetName(gameMode);
5505 if (wname != NULL) {
5506 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5507 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5511 /* Maybe all the enables should be handled here, not just this one */
5512 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5513 gameMode == Training || gameMode == PlayFromGameFile);
5518 * Button/menu procedures
5520 void ResetProc(w, event, prms, nprms)
5529 int LoadGamePopUp(f, gameNumber, title)
5534 cmailMsgLoaded = FALSE;
5535 if (gameNumber == 0) {
5536 int error = GameListBuild(f);
5538 DisplayError(_("Cannot build game list"), error);
5539 } else if (!ListEmpty(&gameList) &&
5540 ((ListGame *) gameList.tailPred)->number > 1) {
5541 GameListPopUp(f, title);
5547 return LoadGame(f, gameNumber, title, FALSE);
5550 void LoadGameProc(w, event, prms, nprms)
5556 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5559 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5562 void LoadNextGameProc(w, event, prms, nprms)
5571 void LoadPrevGameProc(w, event, prms, nprms)
5580 void ReloadGameProc(w, event, prms, nprms)
5589 void LoadNextPositionProc(w, event, prms, nprms)
5598 void LoadPrevPositionProc(w, event, prms, nprms)
5607 void ReloadPositionProc(w, event, prms, nprms)
5616 void LoadPositionProc(w, event, prms, nprms)
5622 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5625 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5628 void SaveGameProc(w, event, prms, nprms)
5634 FileNamePopUp(_("Save game file name?"),
5635 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5639 void SavePositionProc(w, event, prms, nprms)
5645 FileNamePopUp(_("Save position file name?"),
5646 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5650 void ReloadCmailMsgProc(w, event, prms, nprms)
5656 ReloadCmailMsgEvent(FALSE);
5659 void MailMoveProc(w, event, prms, nprms)
5668 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5669 char *selected_fen_position=NULL;
5672 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5673 Atom *type_return, XtPointer *value_return,
5674 unsigned long *length_return, int *format_return)
5676 char *selection_tmp;
5678 if (!selected_fen_position) return False; /* should never happen */
5679 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5680 /* note: since no XtSelectionDoneProc was registered, Xt will
5681 * automatically call XtFree on the value returned. So have to
5682 * make a copy of it allocated with XtMalloc */
5683 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5684 strcpy(selection_tmp, selected_fen_position);
5686 *value_return=selection_tmp;
5687 *length_return=strlen(selection_tmp);
5688 *type_return=*target;
5689 *format_return = 8; /* bits per byte */
5691 } else if (*target == XA_TARGETS(xDisplay)) {
5692 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5693 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5694 targets_tmp[1] = XA_STRING;
5695 *value_return = targets_tmp;
5696 *type_return = XA_ATOM;
5698 *format_return = 8 * sizeof(Atom);
5699 if (*format_return > 32) {
5700 *length_return *= *format_return / 32;
5701 *format_return = 32;
5709 /* note: when called from menu all parameters are NULL, so no clue what the
5710 * Widget which was clicked on was, or what the click event was
5712 void CopyPositionProc(w, event, prms, nprms)
5719 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5720 * have a notion of a position that is selected but not copied.
5721 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5723 if(gameMode == EditPosition) EditPositionDone(TRUE);
5724 if (selected_fen_position) free(selected_fen_position);
5725 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5726 if (!selected_fen_position) return;
5727 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5729 SendPositionSelection,
5730 NULL/* lose_ownership_proc */ ,
5731 NULL/* transfer_done_proc */);
5732 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5734 SendPositionSelection,
5735 NULL/* lose_ownership_proc */ ,
5736 NULL/* transfer_done_proc */);
5739 /* function called when the data to Paste is ready */
5741 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5742 Atom *type, XtPointer value, unsigned long *len, int *format)
5745 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5746 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5747 EditPositionPasteFEN(fenstr);
5751 /* called when Paste Position button is pressed,
5752 * all parameters will be NULL */
5753 void PastePositionProc(w, event, prms, nprms)
5759 XtGetSelectionValue(menuBarWidget,
5760 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5761 /* (XtSelectionCallbackProc) */ PastePositionCB,
5762 NULL, /* client_data passed to PastePositionCB */
5764 /* better to use the time field from the event that triggered the
5765 * call to this function, but that isn't trivial to get
5773 SendGameSelection(Widget w, Atom *selection, Atom *target,
5774 Atom *type_return, XtPointer *value_return,
5775 unsigned long *length_return, int *format_return)
5777 char *selection_tmp;
5779 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5780 FILE* f = fopen(gameCopyFilename, "r");
5783 if (f == NULL) return False;
5787 selection_tmp = XtMalloc(len + 1);
5788 count = fread(selection_tmp, 1, len, f);
5790 XtFree(selection_tmp);
5793 selection_tmp[len] = NULLCHAR;
5794 *value_return = selection_tmp;
5795 *length_return = len;
5796 *type_return = *target;
5797 *format_return = 8; /* bits per byte */
5799 } else if (*target == XA_TARGETS(xDisplay)) {
5800 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5801 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5802 targets_tmp[1] = XA_STRING;
5803 *value_return = targets_tmp;
5804 *type_return = XA_ATOM;
5806 *format_return = 8 * sizeof(Atom);
5807 if (*format_return > 32) {
5808 *length_return *= *format_return / 32;
5809 *format_return = 32;
5817 /* note: when called from menu all parameters are NULL, so no clue what the
5818 * Widget which was clicked on was, or what the click event was
5820 void CopyGameProc(w, event, prms, nprms)
5828 ret = SaveGameToFile(gameCopyFilename, FALSE);
5832 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5833 * have a notion of a game that is selected but not copied.
5834 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5836 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5839 NULL/* lose_ownership_proc */ ,
5840 NULL/* transfer_done_proc */);
5841 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5844 NULL/* lose_ownership_proc */ ,
5845 NULL/* transfer_done_proc */);
5848 /* function called when the data to Paste is ready */
5850 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5851 Atom *type, XtPointer value, unsigned long *len, int *format)
5854 if (value == NULL || *len == 0) {
5855 return; /* nothing had been selected to copy */
5857 f = fopen(gamePasteFilename, "w");
5859 DisplayError(_("Can't open temp file"), errno);
5862 fwrite(value, 1, *len, f);
5865 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5868 /* called when Paste Game button is pressed,
5869 * all parameters will be NULL */
5870 void PasteGameProc(w, event, prms, nprms)
5876 XtGetSelectionValue(menuBarWidget,
5877 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5878 /* (XtSelectionCallbackProc) */ PasteGameCB,
5879 NULL, /* client_data passed to PasteGameCB */
5881 /* better to use the time field from the event that triggered the
5882 * call to this function, but that isn't trivial to get
5892 SaveGameProc(NULL, NULL, NULL, NULL);
5896 void QuitProc(w, event, prms, nprms)
5905 void PauseProc(w, event, prms, nprms)
5915 void MachineBlackProc(w, event, prms, nprms)
5921 MachineBlackEvent();
5924 void MachineWhiteProc(w, event, prms, nprms)
5930 MachineWhiteEvent();
5933 void AnalyzeModeProc(w, event, prms, nprms)
5941 if (!first.analysisSupport) {
5942 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5943 DisplayError(buf, 0);
5946 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5947 if (appData.icsActive) {
5948 if (gameMode != IcsObserving) {
5949 sprintf(buf,_("You are not observing a game"));
5950 DisplayError(buf, 0);
5952 if (appData.icsEngineAnalyze) {
5953 if (appData.debugMode)
5954 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5960 /* if enable, use want disable icsEngineAnalyze */
5961 if (appData.icsEngineAnalyze) {
5966 appData.icsEngineAnalyze = TRUE;
5967 if (appData.debugMode)
5968 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5970 if (!appData.showThinking)
5971 ShowThinkingProc(w,event,prms,nprms);
5976 void AnalyzeFileProc(w, event, prms, nprms)
5982 if (!first.analysisSupport) {
5984 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5985 DisplayError(buf, 0);
5990 if (!appData.showThinking)
5991 ShowThinkingProc(w,event,prms,nprms);
5994 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5995 AnalysisPeriodicEvent(1);
5998 void TwoMachinesProc(w, event, prms, nprms)
6007 void IcsClientProc(w, event, prms, nprms)
6016 void EditGameProc(w, event, prms, nprms)
6025 void EditPositionProc(w, event, prms, nprms)
6031 EditPositionEvent();
6034 void TrainingProc(w, event, prms, nprms)
6043 void EditCommentProc(w, event, prms, nprms)
6050 EditCommentPopDown();
6056 void IcsInputBoxProc(w, event, prms, nprms)
6062 if (ICSInputBoxUp) {
6063 ICSInputBoxPopDown();
6069 void AcceptProc(w, event, prms, nprms)
6078 void DeclineProc(w, event, prms, nprms)
6087 void RematchProc(w, event, prms, nprms)
6096 void CallFlagProc(w, event, prms, nprms)
6105 void DrawProc(w, event, prms, nprms)
6114 void AbortProc(w, event, prms, nprms)
6123 void AdjournProc(w, event, prms, nprms)
6132 void ResignProc(w, event, prms, nprms)
6141 void AdjuWhiteProc(w, event, prms, nprms)
6147 UserAdjudicationEvent(+1);
6150 void AdjuBlackProc(w, event, prms, nprms)
6156 UserAdjudicationEvent(-1);
6159 void AdjuDrawProc(w, event, prms, nprms)
6165 UserAdjudicationEvent(0);
6168 void EnterKeyProc(w, event, prms, nprms)
6174 if (ICSInputBoxUp == True)
6178 void UpKeyProc(w, event, prms, nprms)
6183 { // [HGM] input: let up-arrow recall previous line from history
6190 if (!ICSInputBoxUp) return;
6191 edit = XtNameToWidget(ICSInputShell, "*form.text");
6193 XtSetArg(args[j], XtNstring, &val); j++;
6194 XtGetValues(edit, args, j);
6195 val = PrevInHistory(val);
6196 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6197 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6199 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6200 XawTextReplace(edit, 0, 0, &t);
6201 XawTextSetInsertionPoint(edit, 9999);
6205 void DownKeyProc(w, event, prms, nprms)
6210 { // [HGM] input: let down-arrow recall next line from history
6215 if (!ICSInputBoxUp) return;
6216 edit = XtNameToWidget(ICSInputShell, "*form.text");
6217 val = NextInHistory();
6218 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6219 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6221 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6222 XawTextReplace(edit, 0, 0, &t);
6223 XawTextSetInsertionPoint(edit, 9999);
6227 void StopObservingProc(w, event, prms, nprms)
6233 StopObservingEvent();
6236 void StopExaminingProc(w, event, prms, nprms)
6242 StopExaminingEvent();
6245 void UploadProc(w, event, prms, nprms)
6255 void ForwardProc(w, event, prms, nprms)
6265 void BackwardProc(w, event, prms, nprms)
6274 void ToStartProc(w, event, prms, nprms)
6283 void ToEndProc(w, event, prms, nprms)
6292 void RevertProc(w, event, prms, nprms)
6301 void AnnotateProc(w, event, prms, nprms)
6310 void TruncateGameProc(w, event, prms, nprms)
6316 TruncateGameEvent();
6318 void RetractMoveProc(w, event, prms, nprms)
6327 void MoveNowProc(w, event, prms, nprms)
6337 void AlwaysQueenProc(w, event, prms, nprms)
6345 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6347 if (appData.alwaysPromoteToQueen) {
6348 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6350 XtSetArg(args[0], XtNleftBitmap, None);
6352 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6356 void AnimateDraggingProc(w, event, prms, nprms)
6364 appData.animateDragging = !appData.animateDragging;
6366 if (appData.animateDragging) {
6367 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6370 XtSetArg(args[0], XtNleftBitmap, None);
6372 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6376 void AnimateMovingProc(w, event, prms, nprms)
6384 appData.animate = !appData.animate;
6386 if (appData.animate) {
6387 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6390 XtSetArg(args[0], XtNleftBitmap, None);
6392 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6396 void AutocommProc(w, event, prms, nprms)
6404 appData.autoComment = !appData.autoComment;
6406 if (appData.autoComment) {
6407 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6409 XtSetArg(args[0], XtNleftBitmap, None);
6411 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6416 void AutoflagProc(w, event, prms, nprms)
6424 appData.autoCallFlag = !appData.autoCallFlag;
6426 if (appData.autoCallFlag) {
6427 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6429 XtSetArg(args[0], XtNleftBitmap, None);
6431 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6435 void AutoflipProc(w, event, prms, nprms)
6443 appData.autoFlipView = !appData.autoFlipView;
6445 if (appData.autoFlipView) {
6446 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6448 XtSetArg(args[0], XtNleftBitmap, None);
6450 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6454 void AutobsProc(w, event, prms, nprms)
6462 appData.autoObserve = !appData.autoObserve;
6464 if (appData.autoObserve) {
6465 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6467 XtSetArg(args[0], XtNleftBitmap, None);
6469 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6473 void AutoraiseProc(w, event, prms, nprms)
6481 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6483 if (appData.autoRaiseBoard) {
6484 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6486 XtSetArg(args[0], XtNleftBitmap, None);
6488 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6492 void AutosaveProc(w, event, prms, nprms)
6500 appData.autoSaveGames = !appData.autoSaveGames;
6502 if (appData.autoSaveGames) {
6503 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6505 XtSetArg(args[0], XtNleftBitmap, None);
6507 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6511 void BlindfoldProc(w, event, prms, nprms)
6519 appData.blindfold = !appData.blindfold;
6521 if (appData.blindfold) {
6522 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6524 XtSetArg(args[0], XtNleftBitmap, None);
6526 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6529 DrawPosition(True, NULL);
6532 void TestLegalityProc(w, event, prms, nprms)
6540 appData.testLegality = !appData.testLegality;
6542 if (appData.testLegality) {
6543 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6545 XtSetArg(args[0], XtNleftBitmap, None);
6547 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6552 void FlashMovesProc(w, event, prms, nprms)
6560 if (appData.flashCount == 0) {
6561 appData.flashCount = 3;
6563 appData.flashCount = -appData.flashCount;
6566 if (appData.flashCount > 0) {
6567 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6569 XtSetArg(args[0], XtNleftBitmap, None);
6571 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6575 void FlipViewProc(w, event, prms, nprms)
6581 flipView = !flipView;
6582 DrawPosition(True, NULL);
6585 void GetMoveListProc(w, event, prms, nprms)
6593 appData.getMoveList = !appData.getMoveList;
6595 if (appData.getMoveList) {
6596 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6599 XtSetArg(args[0], XtNleftBitmap, None);
6601 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6606 void HighlightDraggingProc(w, event, prms, nprms)
6614 appData.highlightDragging = !appData.highlightDragging;
6616 if (appData.highlightDragging) {
6617 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6619 XtSetArg(args[0], XtNleftBitmap, None);
6621 XtSetValues(XtNameToWidget(menuBarWidget,
6622 "menuOptions.Highlight Dragging"), args, 1);
6626 void HighlightLastMoveProc(w, event, prms, nprms)
6634 appData.highlightLastMove = !appData.highlightLastMove;
6636 if (appData.highlightLastMove) {
6637 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6639 XtSetArg(args[0], XtNleftBitmap, None);
6641 XtSetValues(XtNameToWidget(menuBarWidget,
6642 "menuOptions.Highlight Last Move"), args, 1);
6645 void IcsAlarmProc(w, event, prms, nprms)
6653 appData.icsAlarm = !appData.icsAlarm;
6655 if (appData.icsAlarm) {
6656 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6658 XtSetArg(args[0], XtNleftBitmap, None);
6660 XtSetValues(XtNameToWidget(menuBarWidget,
6661 "menuOptions.ICS Alarm"), args, 1);
6664 void MoveSoundProc(w, event, prms, nprms)
6672 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6674 if (appData.ringBellAfterMoves) {
6675 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6677 XtSetArg(args[0], XtNleftBitmap, None);
6679 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6684 void OldSaveStyleProc(w, event, prms, nprms)
6692 appData.oldSaveStyle = !appData.oldSaveStyle;
6694 if (appData.oldSaveStyle) {
6695 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6697 XtSetArg(args[0], XtNleftBitmap, None);
6699 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6703 void PeriodicUpdatesProc(w, event, prms, nprms)
6711 PeriodicUpdatesEvent(!appData.periodicUpdates);
6713 if (appData.periodicUpdates) {
6714 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6716 XtSetArg(args[0], XtNleftBitmap, None);
6718 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6722 void PonderNextMoveProc(w, event, prms, nprms)
6730 PonderNextMoveEvent(!appData.ponderNextMove);
6732 if (appData.ponderNextMove) {
6733 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6735 XtSetArg(args[0], XtNleftBitmap, None);
6737 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6741 void PopupExitMessageProc(w, event, prms, nprms)
6749 appData.popupExitMessage = !appData.popupExitMessage;
6751 if (appData.popupExitMessage) {
6752 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6754 XtSetArg(args[0], XtNleftBitmap, None);
6756 XtSetValues(XtNameToWidget(menuBarWidget,
6757 "menuOptions.Popup Exit Message"), args, 1);
6760 void PopupMoveErrorsProc(w, event, prms, nprms)
6768 appData.popupMoveErrors = !appData.popupMoveErrors;
6770 if (appData.popupMoveErrors) {
6771 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6773 XtSetArg(args[0], XtNleftBitmap, None);
6775 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6779 void PremoveProc(w, event, prms, nprms)
6787 appData.premove = !appData.premove;
6789 if (appData.premove) {
6790 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6792 XtSetArg(args[0], XtNleftBitmap, None);
6794 XtSetValues(XtNameToWidget(menuBarWidget,
6795 "menuOptions.Premove"), args, 1);
6798 void QuietPlayProc(w, event, prms, nprms)
6806 appData.quietPlay = !appData.quietPlay;
6808 if (appData.quietPlay) {
6809 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6811 XtSetArg(args[0], XtNleftBitmap, None);
6813 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6817 void ShowCoordsProc(w, event, prms, nprms)
6825 appData.showCoords = !appData.showCoords;
6827 if (appData.showCoords) {
6828 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6830 XtSetArg(args[0], XtNleftBitmap, None);
6832 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6835 DrawPosition(True, NULL);
6838 void ShowThinkingProc(w, event, prms, nprms)
6844 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6845 ShowThinkingEvent();
6848 void HideThinkingProc(w, event, prms, nprms)
6856 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6857 ShowThinkingEvent();
6859 if (appData.hideThinkingFromHuman) {
6860 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6862 XtSetArg(args[0], XtNleftBitmap, None);
6864 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6868 void SaveOnExitProc(w, event, prms, nprms)
6876 saveSettingsOnExit = !saveSettingsOnExit;
6878 if (saveSettingsOnExit) {
6879 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6881 XtSetArg(args[0], XtNleftBitmap, None);
6883 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6887 void SaveSettingsProc(w, event, prms, nprms)
6893 SaveSettings(settingsFileName);
6896 void InfoProc(w, event, prms, nprms)
6903 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6908 void ManProc(w, event, prms, nprms)
6916 if (nprms && *nprms > 0)
6920 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6924 void HintProc(w, event, prms, nprms)
6933 void BookProc(w, event, prms, nprms)
6942 void AboutProc(w, event, prms, nprms)
6950 char *zippy = " (with Zippy code)";
6954 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6955 programVersion, zippy,
6956 "Copyright 1991 Digital Equipment Corporation",
6957 "Enhancements Copyright 1992-2009 Free Software Foundation",
6958 "Enhancements Copyright 2005 Alessandro Scotti",
6959 PACKAGE, " is free software and carries NO WARRANTY;",
6960 "see the file COPYING for more information.");
6961 ErrorPopUp(_("About XBoard"), buf, FALSE);
6964 void DebugProc(w, event, prms, nprms)
6970 appData.debugMode = !appData.debugMode;
6973 void AboutGameProc(w, event, prms, nprms)
6982 void NothingProc(w, event, prms, nprms)
6991 void Iconify(w, event, prms, nprms)
7000 XtSetArg(args[0], XtNiconic, True);
7001 XtSetValues(shellWidget, args, 1);
7004 void DisplayMessage(message, extMessage)
7005 char *message, *extMessage;
7007 /* display a message in the message widget */
7016 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7021 message = extMessage;
7025 /* need to test if messageWidget already exists, since this function
7026 can also be called during the startup, if for example a Xresource
7027 is not set up correctly */
7030 XtSetArg(arg, XtNlabel, message);
7031 XtSetValues(messageWidget, &arg, 1);
7037 void DisplayTitle(text)
7042 char title[MSG_SIZ];
7045 if (text == NULL) text = "";
7047 if (appData.titleInWindow) {
7049 XtSetArg(args[i], XtNlabel, text); i++;
7050 XtSetValues(titleWidget, args, i);
7053 if (*text != NULLCHAR) {
7055 strcpy(title, text);
7056 } else if (appData.icsActive) {
7057 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7058 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7059 } else if (appData.cmailGameName[0] != NULLCHAR) {
7060 snprintf(icon, sizeof(icon), "%s", "CMail");
7061 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7063 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7064 } else if (gameInfo.variant == VariantGothic) {
7065 strcpy(icon, programName);
7066 strcpy(title, GOTHIC);
7069 } else if (gameInfo.variant == VariantFalcon) {
7070 strcpy(icon, programName);
7071 strcpy(title, FALCON);
7073 } else if (appData.noChessProgram) {
7074 strcpy(icon, programName);
7075 strcpy(title, programName);
7077 strcpy(icon, first.tidy);
7078 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7081 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7082 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7083 XtSetValues(shellWidget, args, i);
7087 void DisplayError(message, error)
7094 if (appData.debugMode || appData.matchMode) {
7095 fprintf(stderr, "%s: %s\n", programName, message);
7098 if (appData.debugMode || appData.matchMode) {
7099 fprintf(stderr, "%s: %s: %s\n",
7100 programName, message, strerror(error));
7102 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7105 ErrorPopUp(_("Error"), message, FALSE);
7109 void DisplayMoveError(message)
7114 DrawPosition(FALSE, NULL);
7115 if (appData.debugMode || appData.matchMode) {
7116 fprintf(stderr, "%s: %s\n", programName, message);
7118 if (appData.popupMoveErrors) {
7119 ErrorPopUp(_("Error"), message, FALSE);
7121 DisplayMessage(message, "");
7126 void DisplayFatalError(message, error, status)
7132 errorExitStatus = status;
7134 fprintf(stderr, "%s: %s\n", programName, message);
7136 fprintf(stderr, "%s: %s: %s\n",
7137 programName, message, strerror(error));
7138 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7141 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7142 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7148 void DisplayInformation(message)
7152 ErrorPopUp(_("Information"), message, TRUE);
7155 void DisplayNote(message)
7159 ErrorPopUp(_("Note"), message, FALSE);
7163 NullXErrorCheck(dpy, error_event)
7165 XErrorEvent *error_event;
7170 void DisplayIcsInteractionTitle(message)
7173 if (oldICSInteractionTitle == NULL) {
7174 /* Magic to find the old window title, adapted from vim */
7175 char *wina = getenv("WINDOWID");
7177 Window win = (Window) atoi(wina);
7178 Window root, parent, *children;
7179 unsigned int nchildren;
7180 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7182 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7183 if (!XQueryTree(xDisplay, win, &root, &parent,
7184 &children, &nchildren)) break;
7185 if (children) XFree((void *)children);
7186 if (parent == root || parent == 0) break;
7189 XSetErrorHandler(oldHandler);
7191 if (oldICSInteractionTitle == NULL) {
7192 oldICSInteractionTitle = "xterm";
7195 printf("\033]0;%s\007", message);
7199 char pendingReplyPrefix[MSG_SIZ];
7200 ProcRef pendingReplyPR;
7202 void AskQuestionProc(w, event, prms, nprms)
7209 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7213 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7216 void AskQuestionPopDown()
7218 if (!askQuestionUp) return;
7219 XtPopdown(askQuestionShell);
7220 XtDestroyWidget(askQuestionShell);
7221 askQuestionUp = False;
7224 void AskQuestionReplyAction(w, event, prms, nprms)
7234 reply = XawDialogGetValueString(w = XtParent(w));
7235 strcpy(buf, pendingReplyPrefix);
7236 if (*buf) strcat(buf, " ");
7239 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7240 AskQuestionPopDown();
7242 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7245 void AskQuestionCallback(w, client_data, call_data)
7247 XtPointer client_data, call_data;
7252 XtSetArg(args[0], XtNlabel, &name);
7253 XtGetValues(w, args, 1);
7255 if (strcmp(name, _("cancel")) == 0) {
7256 AskQuestionPopDown();
7258 AskQuestionReplyAction(w, NULL, NULL, NULL);
7262 void AskQuestion(title, question, replyPrefix, pr)
7263 char *title, *question, *replyPrefix;
7267 Widget popup, layout, dialog, edit;
7273 strcpy(pendingReplyPrefix, replyPrefix);
7274 pendingReplyPR = pr;
7277 XtSetArg(args[i], XtNresizable, True); i++;
7278 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7279 askQuestionShell = popup =
7280 XtCreatePopupShell(title, transientShellWidgetClass,
7281 shellWidget, args, i);
7284 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7285 layoutArgs, XtNumber(layoutArgs));
7288 XtSetArg(args[i], XtNlabel, question); i++;
7289 XtSetArg(args[i], XtNvalue, ""); i++;
7290 XtSetArg(args[i], XtNborderWidth, 0); i++;
7291 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7294 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7295 (XtPointer) dialog);
7296 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7297 (XtPointer) dialog);
7299 XtRealizeWidget(popup);
7300 CatchDeleteWindow(popup, "AskQuestionPopDown");
7302 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7303 &x, &y, &win_x, &win_y, &mask);
7305 XtSetArg(args[0], XtNx, x - 10);
7306 XtSetArg(args[1], XtNy, y - 30);
7307 XtSetValues(popup, args, 2);
7309 XtPopup(popup, XtGrabExclusive);
7310 askQuestionUp = True;
7312 edit = XtNameToWidget(dialog, "*value");
7313 XtSetKeyboardFocus(popup, edit);
7321 if (*name == NULLCHAR) {
7323 } else if (strcmp(name, "$") == 0) {
7324 putc(BELLCHAR, stderr);
7327 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7335 PlaySound(appData.soundMove);
7341 PlaySound(appData.soundIcsWin);
7347 PlaySound(appData.soundIcsLoss);
7353 PlaySound(appData.soundIcsDraw);
7357 PlayIcsUnfinishedSound()
7359 PlaySound(appData.soundIcsUnfinished);
7365 PlaySound(appData.soundIcsAlarm);
7371 system("stty echo");
7377 system("stty -echo");
7381 Colorize(cc, continuation)
7386 int count, outCount, error;
7388 if (textColors[(int)cc].bg > 0) {
7389 if (textColors[(int)cc].fg > 0) {
7390 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7391 textColors[(int)cc].fg, textColors[(int)cc].bg);
7393 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7394 textColors[(int)cc].bg);
7397 if (textColors[(int)cc].fg > 0) {
7398 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7399 textColors[(int)cc].fg);
7401 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7404 count = strlen(buf);
7405 outCount = OutputToProcess(NoProc, buf, count, &error);
7406 if (outCount < count) {
7407 DisplayFatalError(_("Error writing to display"), error, 1);
7410 if (continuation) return;
7413 PlaySound(appData.soundShout);
7416 PlaySound(appData.soundSShout);
7419 PlaySound(appData.soundChannel1);
7422 PlaySound(appData.soundChannel);
7425 PlaySound(appData.soundKibitz);
7428 PlaySound(appData.soundTell);
7430 case ColorChallenge:
7431 PlaySound(appData.soundChallenge);
7434 PlaySound(appData.soundRequest);
7437 PlaySound(appData.soundSeek);
7448 return getpwuid(getuid())->pw_name;
7451 static char *ExpandPathName(path)
7454 static char static_buf[2000];
7455 char *d, *s, buf[2000];
7461 while (*s && isspace(*s))
7470 if (*(s+1) == '/') {
7471 strcpy(d, getpwuid(getuid())->pw_dir);
7476 *strchr(buf, '/') = 0;
7477 pwd = getpwnam(buf);
7480 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7484 strcpy(d, pwd->pw_dir);
7485 strcat(d, strchr(s+1, '/'));
7496 static char host_name[MSG_SIZ];
7498 #if HAVE_GETHOSTNAME
7499 gethostname(host_name, MSG_SIZ);
7501 #else /* not HAVE_GETHOSTNAME */
7502 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7503 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7505 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7507 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7508 #endif /* not HAVE_GETHOSTNAME */
7511 XtIntervalId delayedEventTimerXID = 0;
7512 DelayedEventCallback delayedEventCallback = 0;
7517 delayedEventTimerXID = 0;
7518 delayedEventCallback();
7522 ScheduleDelayedEvent(cb, millisec)
7523 DelayedEventCallback cb; long millisec;
7525 if(delayedEventTimerXID && delayedEventCallback == cb)
7526 // [HGM] alive: replace, rather than add or flush identical event
7527 XtRemoveTimeOut(delayedEventTimerXID);
7528 delayedEventCallback = cb;
7529 delayedEventTimerXID =
7530 XtAppAddTimeOut(appContext, millisec,
7531 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7534 DelayedEventCallback
7537 if (delayedEventTimerXID) {
7538 return delayedEventCallback;
7545 CancelDelayedEvent()
7547 if (delayedEventTimerXID) {
7548 XtRemoveTimeOut(delayedEventTimerXID);
7549 delayedEventTimerXID = 0;
7553 XtIntervalId loadGameTimerXID = 0;
7555 int LoadGameTimerRunning()
7557 return loadGameTimerXID != 0;
7560 int StopLoadGameTimer()
7562 if (loadGameTimerXID != 0) {
7563 XtRemoveTimeOut(loadGameTimerXID);
7564 loadGameTimerXID = 0;
7572 LoadGameTimerCallback(arg, id)
7576 loadGameTimerXID = 0;
7581 StartLoadGameTimer(millisec)
7585 XtAppAddTimeOut(appContext, millisec,
7586 (XtTimerCallbackProc) LoadGameTimerCallback,
7590 XtIntervalId analysisClockXID = 0;
7593 AnalysisClockCallback(arg, id)
7597 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7598 || appData.icsEngineAnalyze) { // [DM]
7599 AnalysisPeriodicEvent(0);
7600 StartAnalysisClock();
7605 StartAnalysisClock()
7608 XtAppAddTimeOut(appContext, 2000,
7609 (XtTimerCallbackProc) AnalysisClockCallback,
7613 XtIntervalId clockTimerXID = 0;
7615 int ClockTimerRunning()
7617 return clockTimerXID != 0;
7620 int StopClockTimer()
7622 if (clockTimerXID != 0) {
7623 XtRemoveTimeOut(clockTimerXID);
7632 ClockTimerCallback(arg, id)
7641 StartClockTimer(millisec)
7645 XtAppAddTimeOut(appContext, millisec,
7646 (XtTimerCallbackProc) ClockTimerCallback,
7651 DisplayTimerLabel(w, color, timer, highlight)
7660 /* check for low time warning */
7661 Pixel foregroundOrWarningColor = timerForegroundPixel;
7664 appData.lowTimeWarning &&
7665 (timer / 1000) < appData.icsAlarmTime)
7666 foregroundOrWarningColor = lowTimeWarningColor;
7668 if (appData.clockMode) {
7669 sprintf(buf, "%s: %s", color, TimeString(timer));
7670 XtSetArg(args[0], XtNlabel, buf);
7672 sprintf(buf, "%s ", color);
7673 XtSetArg(args[0], XtNlabel, buf);
7678 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7679 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7681 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7682 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7685 XtSetValues(w, args, 3);
7689 DisplayWhiteClock(timeRemaining, highlight)
7695 if(appData.noGUI) return;
7696 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7697 if (highlight && iconPixmap == bIconPixmap) {
7698 iconPixmap = wIconPixmap;
7699 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7700 XtSetValues(shellWidget, args, 1);
7705 DisplayBlackClock(timeRemaining, highlight)
7711 if(appData.noGUI) return;
7712 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7713 if (highlight && iconPixmap == wIconPixmap) {
7714 iconPixmap = bIconPixmap;
7715 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7716 XtSetValues(shellWidget, args, 1);
7734 int StartChildProcess(cmdLine, dir, pr)
7741 int to_prog[2], from_prog[2];
7745 if (appData.debugMode) {
7746 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7749 /* We do NOT feed the cmdLine to the shell; we just
7750 parse it into blank-separated arguments in the
7751 most simple-minded way possible.
7754 strcpy(buf, cmdLine);
7757 while(*p == ' ') p++;
7759 if(*p == '"' || *p == '\'')
7760 p = strchr(++argv[i-1], *p);
7761 else p = strchr(p, ' ');
7762 if (p == NULL) break;
7767 SetUpChildIO(to_prog, from_prog);
7769 if ((pid = fork()) == 0) {
7771 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7772 close(to_prog[1]); // first close the unused pipe ends
7773 close(from_prog[0]);
7774 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7775 dup2(from_prog[1], 1);
7776 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7777 close(from_prog[1]); // and closing again loses one of the pipes!
7778 if(fileno(stderr) >= 2) // better safe than sorry...
7779 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7781 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7786 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7788 execvp(argv[0], argv);
7790 /* If we get here, exec failed */
7795 /* Parent process */
7797 close(from_prog[1]);
7799 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7802 cp->fdFrom = from_prog[0];
7803 cp->fdTo = to_prog[1];
7808 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7809 static RETSIGTYPE AlarmCallBack(int n)
7815 DestroyChildProcess(pr, signalType)
7819 ChildProc *cp = (ChildProc *) pr;
7821 if (cp->kind != CPReal) return;
7823 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7824 signal(SIGALRM, AlarmCallBack);
7826 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7827 kill(cp->pid, SIGKILL); // kill it forcefully
7828 wait((int *) 0); // and wait again
7832 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7834 /* Process is exiting either because of the kill or because of
7835 a quit command sent by the backend; either way, wait for it to die.
7844 InterruptChildProcess(pr)
7847 ChildProc *cp = (ChildProc *) pr;
7849 if (cp->kind != CPReal) return;
7850 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7853 int OpenTelnet(host, port, pr)
7858 char cmdLine[MSG_SIZ];
7860 if (port[0] == NULLCHAR) {
7861 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7863 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7865 return StartChildProcess(cmdLine, "", pr);
7868 int OpenTCP(host, port, pr)
7874 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7875 #else /* !OMIT_SOCKETS */
7877 struct sockaddr_in sa;
7879 unsigned short uport;
7882 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7886 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7887 sa.sin_family = AF_INET;
7888 sa.sin_addr.s_addr = INADDR_ANY;
7889 uport = (unsigned short) 0;
7890 sa.sin_port = htons(uport);
7891 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7895 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7896 if (!(hp = gethostbyname(host))) {
7898 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7899 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7900 hp->h_addrtype = AF_INET;
7902 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7903 hp->h_addr_list[0] = (char *) malloc(4);
7904 hp->h_addr_list[0][0] = b0;
7905 hp->h_addr_list[0][1] = b1;
7906 hp->h_addr_list[0][2] = b2;
7907 hp->h_addr_list[0][3] = b3;
7912 sa.sin_family = hp->h_addrtype;
7913 uport = (unsigned short) atoi(port);
7914 sa.sin_port = htons(uport);
7915 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7917 if (connect(s, (struct sockaddr *) &sa,
7918 sizeof(struct sockaddr_in)) < 0) {
7922 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7929 #endif /* !OMIT_SOCKETS */
7934 int OpenCommPort(name, pr)
7941 fd = open(name, 2, 0);
7942 if (fd < 0) return errno;
7944 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7954 int OpenLoopback(pr)
7960 SetUpChildIO(to, from);
7962 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7965 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7972 int OpenRcmd(host, user, cmd, pr)
7973 char *host, *user, *cmd;
7976 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7980 #define INPUT_SOURCE_BUF_SIZE 8192
7989 char buf[INPUT_SOURCE_BUF_SIZE];
7994 DoInputCallback(closure, source, xid)
7999 InputSource *is = (InputSource *) closure;
8004 if (is->lineByLine) {
8005 count = read(is->fd, is->unused,
8006 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8008 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8011 is->unused += count;
8013 while (p < is->unused) {
8014 q = memchr(p, '\n', is->unused - p);
8015 if (q == NULL) break;
8017 (is->func)(is, is->closure, p, q - p, 0);
8021 while (p < is->unused) {
8026 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8031 (is->func)(is, is->closure, is->buf, count, error);
8035 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8042 ChildProc *cp = (ChildProc *) pr;
8044 is = (InputSource *) calloc(1, sizeof(InputSource));
8045 is->lineByLine = lineByLine;
8049 is->fd = fileno(stdin);
8051 is->kind = cp->kind;
8052 is->fd = cp->fdFrom;
8055 is->unused = is->buf;
8058 is->xid = XtAppAddInput(appContext, is->fd,
8059 (XtPointer) (XtInputReadMask),
8060 (XtInputCallbackProc) DoInputCallback,
8062 is->closure = closure;
8063 return (InputSourceRef) is;
8067 RemoveInputSource(isr)
8070 InputSource *is = (InputSource *) isr;
8072 if (is->xid == 0) return;
8073 XtRemoveInput(is->xid);
8077 int OutputToProcess(pr, message, count, outError)
8083 static int line = 0;
8084 ChildProc *cp = (ChildProc *) pr;
8089 if (appData.noJoin || !appData.useInternalWrap)
8090 outCount = fwrite(message, 1, count, stdout);
8093 int width = get_term_width();
8094 int len = wrap(NULL, message, count, width, &line);
8095 char *msg = malloc(len);
8099 outCount = fwrite(message, 1, count, stdout);
8102 dbgchk = wrap(msg, message, count, width, &line);
8103 if (dbgchk != len && appData.debugMode)
8104 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8105 outCount = fwrite(msg, 1, dbgchk, stdout);
8111 outCount = write(cp->fdTo, message, count);
8121 /* Output message to process, with "ms" milliseconds of delay
8122 between each character. This is needed when sending the logon
8123 script to ICC, which for some reason doesn't like the
8124 instantaneous send. */
8125 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8132 ChildProc *cp = (ChildProc *) pr;
8137 r = write(cp->fdTo, message++, 1);
8150 /**** Animation code by Hugh Fisher, DCS, ANU.
8152 Known problem: if a window overlapping the board is
8153 moved away while a piece is being animated underneath,
8154 the newly exposed area won't be updated properly.
8155 I can live with this.
8157 Known problem: if you look carefully at the animation
8158 of pieces in mono mode, they are being drawn as solid
8159 shapes without interior detail while moving. Fixing
8160 this would be a major complication for minimal return.
8163 /* Masks for XPM pieces. Black and white pieces can have
8164 different shapes, but in the interest of retaining my
8165 sanity pieces must have the same outline on both light
8166 and dark squares, and all pieces must use the same
8167 background square colors/images. */
8169 static int xpmDone = 0;
8172 CreateAnimMasks (pieceDepth)
8179 unsigned long plane;
8182 /* Need a bitmap just to get a GC with right depth */
8183 buf = XCreatePixmap(xDisplay, xBoardWindow,
8185 values.foreground = 1;
8186 values.background = 0;
8187 /* Don't use XtGetGC, not read only */
8188 maskGC = XCreateGC(xDisplay, buf,
8189 GCForeground | GCBackground, &values);
8190 XFreePixmap(xDisplay, buf);
8192 buf = XCreatePixmap(xDisplay, xBoardWindow,
8193 squareSize, squareSize, pieceDepth);
8194 values.foreground = XBlackPixel(xDisplay, xScreen);
8195 values.background = XWhitePixel(xDisplay, xScreen);
8196 bufGC = XCreateGC(xDisplay, buf,
8197 GCForeground | GCBackground, &values);
8199 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8200 /* Begin with empty mask */
8201 if(!xpmDone) // [HGM] pieces: keep using existing
8202 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8203 squareSize, squareSize, 1);
8204 XSetFunction(xDisplay, maskGC, GXclear);
8205 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8206 0, 0, squareSize, squareSize);
8208 /* Take a copy of the piece */
8213 XSetFunction(xDisplay, bufGC, GXcopy);
8214 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8216 0, 0, squareSize, squareSize, 0, 0);
8218 /* XOR the background (light) over the piece */
8219 XSetFunction(xDisplay, bufGC, GXxor);
8221 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8222 0, 0, squareSize, squareSize, 0, 0);
8224 XSetForeground(xDisplay, bufGC, lightSquareColor);
8225 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8228 /* We now have an inverted piece image with the background
8229 erased. Construct mask by just selecting all the non-zero
8230 pixels - no need to reconstruct the original image. */
8231 XSetFunction(xDisplay, maskGC, GXor);
8233 /* Might be quicker to download an XImage and create bitmap
8234 data from it rather than this N copies per piece, but it
8235 only takes a fraction of a second and there is a much
8236 longer delay for loading the pieces. */
8237 for (n = 0; n < pieceDepth; n ++) {
8238 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8239 0, 0, squareSize, squareSize,
8245 XFreePixmap(xDisplay, buf);
8246 XFreeGC(xDisplay, bufGC);
8247 XFreeGC(xDisplay, maskGC);
8251 InitAnimState (anim, info)
8253 XWindowAttributes * info;
8258 /* Each buffer is square size, same depth as window */
8259 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8260 squareSize, squareSize, info->depth);
8261 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8262 squareSize, squareSize, info->depth);
8264 /* Create a plain GC for blitting */
8265 mask = GCForeground | GCBackground | GCFunction |
8266 GCPlaneMask | GCGraphicsExposures;
8267 values.foreground = XBlackPixel(xDisplay, xScreen);
8268 values.background = XWhitePixel(xDisplay, xScreen);
8269 values.function = GXcopy;
8270 values.plane_mask = AllPlanes;
8271 values.graphics_exposures = False;
8272 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8274 /* Piece will be copied from an existing context at
8275 the start of each new animation/drag. */
8276 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8278 /* Outline will be a read-only copy of an existing */
8279 anim->outlineGC = None;
8285 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8286 XWindowAttributes info;
8288 if (xpmDone && gameInfo.variant == old) return;
8289 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8290 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8292 InitAnimState(&game, &info);
8293 InitAnimState(&player, &info);
8295 /* For XPM pieces, we need bitmaps to use as masks. */
8297 CreateAnimMasks(info.depth);
8303 static Boolean frameWaiting;
8305 static RETSIGTYPE FrameAlarm (sig)
8308 frameWaiting = False;
8309 /* In case System-V style signals. Needed?? */
8310 signal(SIGALRM, FrameAlarm);
8317 struct itimerval delay;
8319 XSync(xDisplay, False);
8322 frameWaiting = True;
8323 signal(SIGALRM, FrameAlarm);
8324 delay.it_interval.tv_sec =
8325 delay.it_value.tv_sec = time / 1000;
8326 delay.it_interval.tv_usec =
8327 delay.it_value.tv_usec = (time % 1000) * 1000;
8328 setitimer(ITIMER_REAL, &delay, NULL);
8329 while (frameWaiting) pause();
8330 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8331 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8332 setitimer(ITIMER_REAL, &delay, NULL);
8342 XSync(xDisplay, False);
8344 usleep(time * 1000);
8349 /* Convert board position to corner of screen rect and color */
8352 ScreenSquare(column, row, pt, color)
8353 int column; int row; XPoint * pt; int * color;
8356 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8357 pt->y = lineGap + row * (squareSize + lineGap);
8359 pt->x = lineGap + column * (squareSize + lineGap);
8360 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8362 *color = SquareColor(row, column);
8365 /* Convert window coords to square */
8368 BoardSquare(x, y, column, row)
8369 int x; int y; int * column; int * row;
8371 *column = EventToSquare(x, BOARD_WIDTH);
8372 if (flipView && *column >= 0)
8373 *column = BOARD_WIDTH - 1 - *column;
8374 *row = EventToSquare(y, BOARD_HEIGHT);
8375 if (!flipView && *row >= 0)
8376 *row = BOARD_HEIGHT - 1 - *row;
8381 #undef Max /* just in case */
8383 #define Max(a, b) ((a) > (b) ? (a) : (b))
8384 #define Min(a, b) ((a) < (b) ? (a) : (b))
8387 SetRect(rect, x, y, width, height)
8388 XRectangle * rect; int x; int y; int width; int height;
8392 rect->width = width;
8393 rect->height = height;
8396 /* Test if two frames overlap. If they do, return
8397 intersection rect within old and location of
8398 that rect within new. */
8401 Intersect(old, new, size, area, pt)
8402 XPoint * old; XPoint * new;
8403 int size; XRectangle * area; XPoint * pt;
8405 if (old->x > new->x + size || new->x > old->x + size ||
8406 old->y > new->y + size || new->y > old->y + size) {
8409 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8410 size - abs(old->x - new->x), size - abs(old->y - new->y));
8411 pt->x = Max(old->x - new->x, 0);
8412 pt->y = Max(old->y - new->y, 0);
8417 /* For two overlapping frames, return the rect(s)
8418 in the old that do not intersect with the new. */
8421 CalcUpdateRects(old, new, size, update, nUpdates)
8422 XPoint * old; XPoint * new; int size;
8423 XRectangle update[]; int * nUpdates;
8427 /* If old = new (shouldn't happen) then nothing to draw */
8428 if (old->x == new->x && old->y == new->y) {
8432 /* Work out what bits overlap. Since we know the rects
8433 are the same size we don't need a full intersect calc. */
8435 /* Top or bottom edge? */
8436 if (new->y > old->y) {
8437 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8439 } else if (old->y > new->y) {
8440 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8441 size, old->y - new->y);
8444 /* Left or right edge - don't overlap any update calculated above. */
8445 if (new->x > old->x) {
8446 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8447 new->x - old->x, size - abs(new->y - old->y));
8449 } else if (old->x > new->x) {
8450 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8451 old->x - new->x, size - abs(new->y - old->y));
8458 /* Generate a series of frame coords from start->mid->finish.
8459 The movement rate doubles until the half way point is
8460 reached, then halves back down to the final destination,
8461 which gives a nice slow in/out effect. The algorithmn
8462 may seem to generate too many intermediates for short
8463 moves, but remember that the purpose is to attract the
8464 viewers attention to the piece about to be moved and
8465 then to where it ends up. Too few frames would be less
8469 Tween(start, mid, finish, factor, frames, nFrames)
8470 XPoint * start; XPoint * mid;
8471 XPoint * finish; int factor;
8472 XPoint frames[]; int * nFrames;
8474 int fraction, n, count;
8478 /* Slow in, stepping 1/16th, then 1/8th, ... */
8480 for (n = 0; n < factor; n++)
8482 for (n = 0; n < factor; n++) {
8483 frames[count].x = start->x + (mid->x - start->x) / fraction;
8484 frames[count].y = start->y + (mid->y - start->y) / fraction;
8486 fraction = fraction / 2;
8490 frames[count] = *mid;
8493 /* Slow out, stepping 1/2, then 1/4, ... */
8495 for (n = 0; n < factor; n++) {
8496 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8497 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8499 fraction = fraction * 2;
8504 /* Draw a piece on the screen without disturbing what's there */
8507 SelectGCMask(piece, clip, outline, mask)
8508 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8512 /* Bitmap for piece being moved. */
8513 if (appData.monoMode) {
8514 *mask = *pieceToSolid(piece);
8515 } else if (useImages) {
8517 *mask = xpmMask[piece];
8519 *mask = ximMaskPm[piece];
8522 *mask = *pieceToSolid(piece);
8525 /* GC for piece being moved. Square color doesn't matter, but
8526 since it gets modified we make a copy of the original. */
8528 if (appData.monoMode)
8533 if (appData.monoMode)
8538 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8540 /* Outline only used in mono mode and is not modified */
8542 *outline = bwPieceGC;
8544 *outline = wbPieceGC;
8548 OverlayPiece(piece, clip, outline, dest)
8549 ChessSquare piece; GC clip; GC outline; Drawable dest;
8554 /* Draw solid rectangle which will be clipped to shape of piece */
8555 XFillRectangle(xDisplay, dest, clip,
8556 0, 0, squareSize, squareSize);
8557 if (appData.monoMode)
8558 /* Also draw outline in contrasting color for black
8559 on black / white on white cases */
8560 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8561 0, 0, squareSize, squareSize, 0, 0, 1);
8563 /* Copy the piece */
8568 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8570 0, 0, squareSize, squareSize,
8575 /* Animate the movement of a single piece */
8578 BeginAnimation(anim, piece, startColor, start)
8586 /* The old buffer is initialised with the start square (empty) */
8587 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8588 anim->prevFrame = *start;
8590 /* The piece will be drawn using its own bitmap as a matte */
8591 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8592 XSetClipMask(xDisplay, anim->pieceGC, mask);
8596 AnimationFrame(anim, frame, piece)
8601 XRectangle updates[4];
8606 /* Save what we are about to draw into the new buffer */
8607 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8608 frame->x, frame->y, squareSize, squareSize,
8611 /* Erase bits of the previous frame */
8612 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8613 /* Where the new frame overlapped the previous,
8614 the contents in newBuf are wrong. */
8615 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8616 overlap.x, overlap.y,
8617 overlap.width, overlap.height,
8619 /* Repaint the areas in the old that don't overlap new */
8620 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8621 for (i = 0; i < count; i++)
8622 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8623 updates[i].x - anim->prevFrame.x,
8624 updates[i].y - anim->prevFrame.y,
8625 updates[i].width, updates[i].height,
8626 updates[i].x, updates[i].y);
8628 /* Easy when no overlap */
8629 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8630 0, 0, squareSize, squareSize,
8631 anim->prevFrame.x, anim->prevFrame.y);
8634 /* Save this frame for next time round */
8635 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8636 0, 0, squareSize, squareSize,
8638 anim->prevFrame = *frame;
8640 /* Draw piece over original screen contents, not current,
8641 and copy entire rect. Wipes out overlapping piece images. */
8642 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8643 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8644 0, 0, squareSize, squareSize,
8645 frame->x, frame->y);
8649 EndAnimation (anim, finish)
8653 XRectangle updates[4];
8658 /* The main code will redraw the final square, so we
8659 only need to erase the bits that don't overlap. */
8660 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8661 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8662 for (i = 0; i < count; i++)
8663 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8664 updates[i].x - anim->prevFrame.x,
8665 updates[i].y - anim->prevFrame.y,
8666 updates[i].width, updates[i].height,
8667 updates[i].x, updates[i].y);
8669 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8670 0, 0, squareSize, squareSize,
8671 anim->prevFrame.x, anim->prevFrame.y);
8676 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8678 ChessSquare piece; int startColor;
8679 XPoint * start; XPoint * finish;
8680 XPoint frames[]; int nFrames;
8684 BeginAnimation(anim, piece, startColor, start);
8685 for (n = 0; n < nFrames; n++) {
8686 AnimationFrame(anim, &(frames[n]), piece);
8687 FrameDelay(appData.animSpeed);
8689 EndAnimation(anim, finish);
8692 /* Main control logic for deciding what to animate and how */
8695 AnimateMove(board, fromX, fromY, toX, toY)
8704 XPoint start, finish, mid;
8705 XPoint frames[kFactor * 2 + 1];
8706 int nFrames, startColor, endColor;
8708 /* Are we animating? */
8709 if (!appData.animate || appData.blindfold)
8712 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8713 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8714 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8716 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8717 piece = board[fromY][fromX];
8718 if (piece >= EmptySquare) return;
8723 hop = (piece == WhiteKnight || piece == BlackKnight);
8726 if (appData.debugMode) {
8727 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8728 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8729 piece, fromX, fromY, toX, toY); }
8731 ScreenSquare(fromX, fromY, &start, &startColor);
8732 ScreenSquare(toX, toY, &finish, &endColor);
8735 /* Knight: make diagonal movement then straight */
8736 if (abs(toY - fromY) < abs(toX - fromX)) {
8737 mid.x = start.x + (finish.x - start.x) / 2;
8741 mid.y = start.y + (finish.y - start.y) / 2;
8744 mid.x = start.x + (finish.x - start.x) / 2;
8745 mid.y = start.y + (finish.y - start.y) / 2;
8748 /* Don't use as many frames for very short moves */
8749 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8750 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8752 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8753 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8755 /* Be sure end square is redrawn */
8756 damage[0][toY][toX] = True;
8760 DragPieceBegin(x, y)
8763 int boardX, boardY, color;
8766 /* Are we animating? */
8767 if (!appData.animateDragging || appData.blindfold)
8770 /* Figure out which square we start in and the
8771 mouse position relative to top left corner. */
8772 BoardSquare(x, y, &boardX, &boardY);
8773 player.startBoardX = boardX;
8774 player.startBoardY = boardY;
8775 ScreenSquare(boardX, boardY, &corner, &color);
8776 player.startSquare = corner;
8777 player.startColor = color;
8778 /* As soon as we start dragging, the piece will jump slightly to
8779 be centered over the mouse pointer. */
8780 player.mouseDelta.x = squareSize/2;
8781 player.mouseDelta.y = squareSize/2;
8782 /* Initialise animation */
8783 player.dragPiece = PieceForSquare(boardX, boardY);
8785 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8786 player.dragActive = True;
8787 BeginAnimation(&player, player.dragPiece, color, &corner);
8788 /* Mark this square as needing to be redrawn. Note that
8789 we don't remove the piece though, since logically (ie
8790 as seen by opponent) the move hasn't been made yet. */
8791 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8792 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8793 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8794 corner.x, corner.y, squareSize, squareSize,
8795 0, 0); // [HGM] zh: unstack in stead of grab
8796 damage[0][boardY][boardX] = True;
8798 player.dragActive = False;
8808 /* Are we animating? */
8809 if (!appData.animateDragging || appData.blindfold)
8813 if (! player.dragActive)
8815 /* Move piece, maintaining same relative position
8816 of mouse within square */
8817 corner.x = x - player.mouseDelta.x;
8818 corner.y = y - player.mouseDelta.y;
8819 AnimationFrame(&player, &corner, player.dragPiece);
8821 if (appData.highlightDragging) {
8823 BoardSquare(x, y, &boardX, &boardY);
8824 SetHighlights(fromX, fromY, boardX, boardY);
8833 int boardX, boardY, color;
8836 /* Are we animating? */
8837 if (!appData.animateDragging || appData.blindfold)
8841 if (! player.dragActive)
8843 /* Last frame in sequence is square piece is
8844 placed on, which may not match mouse exactly. */
8845 BoardSquare(x, y, &boardX, &boardY);
8846 ScreenSquare(boardX, boardY, &corner, &color);
8847 EndAnimation(&player, &corner);
8849 /* Be sure end square is redrawn */
8850 damage[0][boardY][boardX] = True;
8852 /* This prevents weird things happening with fast successive
8853 clicks which on my Sun at least can cause motion events
8854 without corresponding press/release. */
8855 player.dragActive = False;
8858 /* Handle expose event while piece being dragged */
8863 if (!player.dragActive || appData.blindfold)
8866 /* What we're doing: logically, the move hasn't been made yet,
8867 so the piece is still in it's original square. But visually
8868 it's being dragged around the board. So we erase the square
8869 that the piece is on and draw it at the last known drag point. */
8870 BlankSquare(player.startSquare.x, player.startSquare.y,
8871 player.startColor, EmptySquare, xBoardWindow);
8872 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8873 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8876 #include <sys/ioctl.h>
8877 int get_term_width()
8879 int fd, default_width;
8882 default_width = 79; // this is FICS default anyway...
8884 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8886 if (!ioctl(fd, TIOCGSIZE, &win))
8887 default_width = win.ts_cols;
8888 #elif defined(TIOCGWINSZ)
8890 if (!ioctl(fd, TIOCGWINSZ, &win))
8891 default_width = win.ws_col;
8893 return default_width;
8896 void update_ics_width()
8898 static int old_width = 0;
8899 int new_width = get_term_width();
8901 if (old_width != new_width)
8902 ics_printf("set width %d\n", new_width);
8903 old_width = new_width;
8906 void NotifyFrontendLogin()