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 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. */
58 #include <sys/types.h>
63 # if HAVE_SYS_SOCKET_H
64 # include <sys/socket.h>
65 # include <netinet/in.h>
67 # else /* not HAVE_SYS_SOCKET_H */
68 # if HAVE_LAN_SOCKET_H
69 # include <lan/socket.h>
71 # include <lan/netdb.h>
72 # else /* not HAVE_LAN_SOCKET_H */
73 # define OMIT_SOCKETS 1
74 # endif /* not HAVE_LAN_SOCKET_H */
75 # endif /* not HAVE_SYS_SOCKET_H */
76 #endif /* !OMIT_SOCKETS */
81 #else /* not STDC_HEADERS */
82 extern char *getenv();
85 # else /* not HAVE_STRING_H */
87 # endif /* not HAVE_STRING_H */
88 #endif /* not STDC_HEADERS */
91 # include <sys/fcntl.h>
92 #else /* not HAVE_SYS_FCNTL_H */
95 # endif /* HAVE_FCNTL_H */
96 #endif /* not HAVE_SYS_FCNTL_H */
98 #if HAVE_SYS_SYSTEMINFO_H
99 # include <sys/systeminfo.h>
100 #endif /* HAVE_SYS_SYSTEMINFO_H */
102 #if TIME_WITH_SYS_TIME
103 # include <sys/time.h>
107 # include <sys/time.h>
118 # include <sys/wait.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 # define HAVE_DIR_STRUCT
126 # define dirent direct
127 # define NAMLEN(dirent) (dirent)->d_namlen
129 # include <sys/ndir.h>
130 # define HAVE_DIR_STRUCT
133 # include <sys/dir.h>
134 # define HAVE_DIR_STRUCT
138 # define HAVE_DIR_STRUCT
142 #include <X11/Intrinsic.h>
143 #include <X11/StringDefs.h>
144 #include <X11/Shell.h>
145 #include <X11/cursorfont.h>
146 #include <X11/Xatom.h>
147 #include <X11/Xmu/Atoms.h>
149 #include <X11/Xaw3d/Dialog.h>
150 #include <X11/Xaw3d/Form.h>
151 #include <X11/Xaw3d/List.h>
152 #include <X11/Xaw3d/Label.h>
153 #include <X11/Xaw3d/SimpleMenu.h>
154 #include <X11/Xaw3d/SmeBSB.h>
155 #include <X11/Xaw3d/SmeLine.h>
156 #include <X11/Xaw3d/Box.h>
157 #include <X11/Xaw3d/MenuButton.h>
158 #include <X11/Xaw3d/Text.h>
159 #include <X11/Xaw3d/AsciiText.h>
161 #include <X11/Xaw/Dialog.h>
162 #include <X11/Xaw/Form.h>
163 #include <X11/Xaw/List.h>
164 #include <X11/Xaw/Label.h>
165 #include <X11/Xaw/SimpleMenu.h>
166 #include <X11/Xaw/SmeBSB.h>
167 #include <X11/Xaw/SmeLine.h>
168 #include <X11/Xaw/Box.h>
169 #include <X11/Xaw/MenuButton.h>
170 #include <X11/Xaw/Text.h>
171 #include <X11/Xaw/AsciiText.h>
174 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
179 #include "pixmaps/pixmaps.h"
180 #define IMAGE_EXT "xpm"
182 #define IMAGE_EXT "xim"
183 #include "bitmaps/bitmaps.h"
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
195 #include "xgamelist.h"
196 #include "xhistory.h"
197 #include "xedittags.h"
200 // must be moved to xengineoutput.h
202 void EngineOutputProc P((Widget w, XEvent *event,
203 String *prms, Cardinal *nprms));
204 void EvalGraphProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
233 int main P((int argc, char **argv));
234 RETSIGTYPE CmailSigHandler P((int sig));
235 RETSIGTYPE IntSigHandler P((int sig));
236 RETSIGTYPE TermSizeSigHandler P((int sig));
237 void CreateGCs P((void));
238 void CreateXIMPieces P((void));
239 void CreateXPMPieces P((void));
240 void CreatePieces P((void));
241 void CreatePieceMenus P((void));
242 Widget CreateMenuBar P((Menu *mb));
243 Widget CreateButtonBar P ((MenuItem *mi));
244 char *FindFont P((char *pattern, int targetPxlSize));
245 void PieceMenuPopup P((Widget w, XEvent *event,
246 String *params, Cardinal *num_params));
247 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
248 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
249 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
250 u_int wreq, u_int hreq));
251 void CreateGrid P((void));
252 int EventToSquare P((int x, int limit));
253 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
254 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
255 void HandleUserMove P((Widget w, XEvent *event,
256 String *prms, Cardinal *nprms));
257 void AnimateUserMove P((Widget w, XEvent * event,
258 String * params, Cardinal * nParams));
259 void WhiteClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void BlackClock P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void DrawPositionProc P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
267 void CommentPopUp P((char *title, char *label));
268 void CommentPopDown P((void));
269 void CommentCallback P((Widget w, XtPointer client_data,
270 XtPointer call_data));
271 void ICSInputBoxPopUp P((void));
272 void ICSInputBoxPopDown P((void));
273 void FileNamePopUp P((char *label, char *def,
274 FileProc proc, char *openMode));
275 void FileNamePopDown P((void));
276 void FileNameCallback P((Widget w, XtPointer client_data,
277 XtPointer call_data));
278 void FileNameAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionReplyAction P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionProc P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionPopDown P((void));
285 void PromotionPopDown P((void));
286 void PromotionCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void EditCommentPopDown P((void));
289 void EditCommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
292 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
294 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
296 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
298 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPositionProc P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
304 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
306 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
308 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
310 void PastePositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
315 void SavePositionProc P((Widget w, XEvent *event,
316 String *prms, Cardinal *nprms));
317 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
320 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
324 void MachineWhiteProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeModeProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void AnalyzeFileProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
332 void IcsClientProc P((Widget w, XEvent *event, String *prms,
334 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void EditPositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void EditCommentProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void IcsInputBoxProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void StopObservingProc P((Widget w, XEvent *event, String *prms,
356 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
358 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
365 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
367 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
370 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
372 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
374 void AutocommProc P((Widget w, XEvent *event, String *prms,
376 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AutobsProc P((Widget w, XEvent *event, String *prms,
380 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
385 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
388 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
390 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
392 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
396 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
398 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
400 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
402 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
404 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
408 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
410 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
412 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
414 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void DisplayMove P((int moveNumber));
426 void DisplayTitle P((char *title));
427 void ICSInitScript P((void));
428 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
429 void ErrorPopUp P((char *title, char *text, int modal));
430 void ErrorPopDown P((void));
431 static char *ExpandPathName P((char *path));
432 static void CreateAnimVars P((void));
433 static void DragPieceMove P((int x, int y));
434 static void DrawDragPiece P((void));
435 char *ModeToWidgetName P((GameMode mode));
436 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void ShufflePopDown P(());
444 void EnginePopDown P(());
445 void UciPopDown P(());
446 void TimeControlPopDown P(());
447 void NewVariantPopDown P(());
448 void SettingsPopDown P(());
449 void update_ics_width P(());
450 int get_term_width P(());
451 int CopyMemoProc P(());
452 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
453 char *init_path, char *mode, int (*show_entry)(), char **name_return));
455 * XBoard depends on Xt R4 or higher
457 int xtVersion = XtSpecificationRelease;
462 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
463 jailSquareColor, highlightSquareColor, premoveHighlightColor;
464 Pixel lowTimeWarningColor;
465 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
466 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
467 wjPieceGC, bjPieceGC, prelineGC, countGC;
468 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
469 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
470 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
471 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
472 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
473 ICSInputShell, fileNameShell, askQuestionShell;
474 Widget historyShell, evalGraphShell, gameListShell;
475 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
476 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
477 Font clockFontID, coordFontID, countFontID;
478 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
479 XtAppContext appContext;
481 char *oldICSInteractionTitle;
485 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
487 Position commentX = -1, commentY = -1;
488 Dimension commentW, commentH;
489 typedef unsigned int BoardSize;
491 Boolean chessProgram;
493 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
494 int squareSize, smallLayout = 0, tinyLayout = 0,
495 marginW, marginH, // [HGM] for run-time resizing
496 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
497 ICSInputBoxUp = False, askQuestionUp = False,
498 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
499 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
500 Pixel timerForegroundPixel, timerBackgroundPixel;
501 Pixel buttonForegroundPixel, buttonBackgroundPixel;
502 char *chessDir, *programName, *programVersion,
503 *gameCopyFilename, *gamePasteFilename;
504 Boolean alwaysOnTop = False;
505 Boolean saveSettingsOnExit;
506 char *settingsFileName;
507 char *icsTextMenuString;
509 char *firstChessProgramNames;
510 char *secondChessProgramNames;
512 WindowPlacement wpMain;
513 WindowPlacement wpConsole;
514 WindowPlacement wpComment;
515 WindowPlacement wpMoveHistory;
516 WindowPlacement wpEvalGraph;
517 WindowPlacement wpEngineOutput;
518 WindowPlacement wpGameList;
519 WindowPlacement wpTags;
523 Pixmap pieceBitmap[2][(int)BlackPawn];
524 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
525 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
526 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
527 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
528 int useImages, useImageSqs;
529 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
530 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
531 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
532 XImage *ximLightSquare, *ximDarkSquare;
535 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
536 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
538 #define White(piece) ((int)(piece) < (int)BlackPawn)
540 /* Variables for doing smooth animation. This whole thing
541 would be much easier if the board was double-buffered,
542 but that would require a fairly major rewrite. */
547 GC blitGC, pieceGC, outlineGC;
548 XPoint startSquare, prevFrame, mouseDelta;
552 int startBoardX, startBoardY;
555 /* There can be two pieces being animated at once: a player
556 can begin dragging a piece before the remote opponent has moved. */
558 static AnimState game, player;
560 /* Bitmaps for use as masks when drawing XPM pieces.
561 Need one for each black and white piece. */
562 static Pixmap xpmMask[BlackKing + 1];
564 /* This magic number is the number of intermediate frames used
565 in each half of the animation. For short moves it's reduced
566 by 1. The total number of frames will be factor * 2 + 1. */
569 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
571 MenuItem fileMenu[] = {
572 {N_("New Game"), ResetProc},
573 {N_("New Shuffle Game ..."), ShuffleMenuProc},
574 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
575 {"----", NothingProc},
576 {N_("Load Game"), LoadGameProc},
577 {N_("Load Next Game"), LoadNextGameProc},
578 {N_("Load Previous Game"), LoadPrevGameProc},
579 {N_("Reload Same Game"), ReloadGameProc},
580 {N_("Save Game"), SaveGameProc},
581 {"----", NothingProc},
582 {N_("Copy Game"), CopyGameProc},
583 {N_("Paste Game"), PasteGameProc},
584 {"----", NothingProc},
585 {N_("Load Position"), LoadPositionProc},
586 {N_("Load Next Position"), LoadNextPositionProc},
587 {N_("Load Previous Position"), LoadPrevPositionProc},
588 {N_("Reload Same Position"), ReloadPositionProc},
589 {N_("Save Position"), SavePositionProc},
590 {"----", NothingProc},
591 {N_("Copy Position"), CopyPositionProc},
592 {N_("Paste Position"), PastePositionProc},
593 {"----", NothingProc},
594 {N_("Mail Move"), MailMoveProc},
595 {N_("Reload CMail Message"), ReloadCmailMsgProc},
596 {"----", NothingProc},
597 {N_("Exit"), QuitProc},
601 MenuItem modeMenu[] = {
602 {N_("Machine White"), MachineWhiteProc},
603 {N_("Machine Black"), MachineBlackProc},
604 {N_("Two Machines"), TwoMachinesProc},
605 {N_("Analysis Mode"), AnalyzeModeProc},
606 {N_("Analyze File"), AnalyzeFileProc },
607 {N_("ICS Client"), IcsClientProc},
608 {N_("Edit Game"), EditGameProc},
609 {N_("Edit Position"), EditPositionProc},
610 {N_("Training"), TrainingProc},
611 {"----", NothingProc},
612 {N_("Show Engine Output"), EngineOutputProc},
613 {N_("Show Evaluation Graph"), EvalGraphProc},
614 {N_("Show Game List"), ShowGameListProc},
615 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
616 {"----", NothingProc},
617 {N_("Edit Tags"), EditTagsProc},
618 {N_("Edit Comment"), EditCommentProc},
619 {N_("ICS Input Box"), IcsInputBoxProc},
620 {N_("Pause"), PauseProc},
624 MenuItem actionMenu[] = {
625 {N_("Accept"), AcceptProc},
626 {N_("Decline"), DeclineProc},
627 {N_("Rematch"), RematchProc},
628 {"----", NothingProc},
629 {N_("Call Flag"), CallFlagProc},
630 {N_("Draw"), DrawProc},
631 {N_("Adjourn"), AdjournProc},
632 {N_("Abort"), AbortProc},
633 {N_("Resign"), ResignProc},
634 {"----", NothingProc},
635 {N_("Stop Observing"), StopObservingProc},
636 {N_("Stop Examining"), StopExaminingProc},
637 {"----", NothingProc},
638 {N_("Adjudicate to White"), AdjuWhiteProc},
639 {N_("Adjudicate to Black"), AdjuBlackProc},
640 {N_("Adjudicate Draw"), AdjuDrawProc},
644 MenuItem stepMenu[] = {
645 {N_("Backward"), BackwardProc},
646 {N_("Forward"), ForwardProc},
647 {N_("Back to Start"), ToStartProc},
648 {N_("Forward to End"), ToEndProc},
649 {N_("Revert"), RevertProc},
650 {N_("Truncate Game"), TruncateGameProc},
651 {"----", NothingProc},
652 {N_("Move Now"), MoveNowProc},
653 {N_("Retract Move"), RetractMoveProc},
657 MenuItem optionsMenu[] = {
658 {N_("Flip View"), FlipViewProc},
659 {"----", NothingProc},
660 {N_("Adjudications ..."), EngineMenuProc},
661 {N_("General Settings ..."), UciMenuProc},
662 {N_("Engine #1 Settings ..."), FirstSettingsProc},
663 {N_("Engine #2 Settings ..."), SecondSettingsProc},
664 {N_("Time Control ..."), TimeControlProc},
665 {"----", NothingProc},
666 {N_("Always Queen"), AlwaysQueenProc},
667 {N_("Animate Dragging"), AnimateDraggingProc},
668 {N_("Animate Moving"), AnimateMovingProc},
669 {N_("Auto Comment"), AutocommProc},
670 {N_("Auto Flag"), AutoflagProc},
671 {N_("Auto Flip View"), AutoflipProc},
672 {N_("Auto Observe"), AutobsProc},
673 {N_("Auto Raise Board"), AutoraiseProc},
674 {N_("Auto Save"), AutosaveProc},
675 {N_("Blindfold"), BlindfoldProc},
676 {N_("Flash Moves"), FlashMovesProc},
677 {N_("Get Move List"), GetMoveListProc},
679 {N_("Highlight Dragging"), HighlightDraggingProc},
681 {N_("Highlight Last Move"), HighlightLastMoveProc},
682 {N_("Move Sound"), MoveSoundProc},
683 {N_("ICS Alarm"), IcsAlarmProc},
684 {N_("Old Save Style"), OldSaveStyleProc},
685 {N_("Periodic Updates"), PeriodicUpdatesProc},
686 {N_("Ponder Next Move"), PonderNextMoveProc},
687 {N_("Popup Exit Message"), PopupExitMessageProc},
688 {N_("Popup Move Errors"), PopupMoveErrorsProc},
689 {N_("Premove"), PremoveProc},
690 {N_("Quiet Play"), QuietPlayProc},
691 {N_("Show Coords"), ShowCoordsProc},
692 {N_("Hide Thinking"), HideThinkingProc},
693 {N_("Test Legality"), TestLegalityProc},
694 {"----", NothingProc},
695 {N_("Save Settings Now"), SaveSettingsProc},
696 {N_("Save Settings on Exit"), SaveOnExitProc},
700 MenuItem helpMenu[] = {
701 {N_("Info XBoard"), InfoProc},
702 {N_("Man XBoard"), ManProc},
703 {"----", NothingProc},
704 {N_("Hint"), HintProc},
705 {N_("Book"), BookProc},
706 {"----", NothingProc},
707 {N_("About XBoard"), AboutProc},
712 {N_("File"), fileMenu},
713 {N_("Mode"), modeMenu},
714 {N_("Action"), actionMenu},
715 {N_("Step"), stepMenu},
716 {N_("Options"), optionsMenu},
717 {N_("Help"), helpMenu},
721 #define PAUSE_BUTTON N_("P")
722 MenuItem buttonBar[] = {
725 {PAUSE_BUTTON, PauseProc},
731 #define PIECE_MENU_SIZE 18
732 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
733 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
734 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
735 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
736 N_("Empty square"), N_("Clear board") },
737 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
738 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
739 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
740 N_("Empty square"), N_("Clear board") }
742 /* must be in same order as PieceMenuStrings! */
743 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
744 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
745 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
746 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
747 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
748 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
749 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
750 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
751 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
754 #define DROP_MENU_SIZE 6
755 String dropMenuStrings[DROP_MENU_SIZE] = {
756 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
758 /* must be in same order as PieceMenuStrings! */
759 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
760 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
761 WhiteRook, WhiteQueen
769 DropMenuEnables dmEnables[] = {
787 { XtNborderWidth, 0 },
788 { XtNdefaultDistance, 0 },
792 { XtNborderWidth, 0 },
793 { XtNresizable, (XtArgVal) True },
797 { XtNborderWidth, 0 },
803 { XtNjustify, (XtArgVal) XtJustifyRight },
804 { XtNlabel, (XtArgVal) "..." },
805 { XtNresizable, (XtArgVal) True },
806 { XtNresize, (XtArgVal) False }
809 Arg messageArgs[] = {
810 { XtNjustify, (XtArgVal) XtJustifyLeft },
811 { XtNlabel, (XtArgVal) "..." },
812 { XtNresizable, (XtArgVal) True },
813 { XtNresize, (XtArgVal) False }
817 { XtNborderWidth, 0 },
818 { XtNjustify, (XtArgVal) XtJustifyLeft }
821 XtResource clientResources[] = {
822 { "flashCount", "flashCount", XtRInt, sizeof(int),
823 XtOffset(AppDataPtr, flashCount), XtRImmediate,
824 (XtPointer) FLASH_COUNT },
827 XrmOptionDescRec shellOptions[] = {
828 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
829 { "-flash", "flashCount", XrmoptionNoArg, "3" },
830 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
833 XtActionsRec boardActions[] = {
834 { "DrawPosition", DrawPositionProc },
835 { "HandleUserMove", HandleUserMove },
836 { "AnimateUserMove", AnimateUserMove },
837 { "FileNameAction", FileNameAction },
838 { "AskQuestionProc", AskQuestionProc },
839 { "AskQuestionReplyAction", AskQuestionReplyAction },
840 { "PieceMenuPopup", PieceMenuPopup },
841 { "WhiteClock", WhiteClock },
842 { "BlackClock", BlackClock },
843 { "Iconify", Iconify },
844 { "ResetProc", ResetProc },
845 { "LoadGameProc", LoadGameProc },
846 { "LoadNextGameProc", LoadNextGameProc },
847 { "LoadPrevGameProc", LoadPrevGameProc },
848 { "LoadSelectedProc", LoadSelectedProc },
849 { "ReloadGameProc", ReloadGameProc },
850 { "LoadPositionProc", LoadPositionProc },
851 { "LoadNextPositionProc", LoadNextPositionProc },
852 { "LoadPrevPositionProc", LoadPrevPositionProc },
853 { "ReloadPositionProc", ReloadPositionProc },
854 { "CopyPositionProc", CopyPositionProc },
855 { "PastePositionProc", PastePositionProc },
856 { "CopyGameProc", CopyGameProc },
857 { "PasteGameProc", PasteGameProc },
858 { "SaveGameProc", SaveGameProc },
859 { "SavePositionProc", SavePositionProc },
860 { "MailMoveProc", MailMoveProc },
861 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
862 { "QuitProc", QuitProc },
863 { "MachineWhiteProc", MachineWhiteProc },
864 { "MachineBlackProc", MachineBlackProc },
865 { "AnalysisModeProc", AnalyzeModeProc },
866 { "AnalyzeFileProc", AnalyzeFileProc },
867 { "TwoMachinesProc", TwoMachinesProc },
868 { "IcsClientProc", IcsClientProc },
869 { "EditGameProc", EditGameProc },
870 { "EditPositionProc", EditPositionProc },
871 { "TrainingProc", EditPositionProc },
872 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
873 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
874 { "ShowGameListProc", ShowGameListProc },
875 { "ShowMoveListProc", HistoryShowProc},
876 { "EditTagsProc", EditCommentProc },
877 { "EditCommentProc", EditCommentProc },
878 { "IcsAlarmProc", IcsAlarmProc },
879 { "IcsInputBoxProc", IcsInputBoxProc },
880 { "PauseProc", PauseProc },
881 { "AcceptProc", AcceptProc },
882 { "DeclineProc", DeclineProc },
883 { "RematchProc", RematchProc },
884 { "CallFlagProc", CallFlagProc },
885 { "DrawProc", DrawProc },
886 { "AdjournProc", AdjournProc },
887 { "AbortProc", AbortProc },
888 { "ResignProc", ResignProc },
889 { "AdjuWhiteProc", AdjuWhiteProc },
890 { "AdjuBlackProc", AdjuBlackProc },
891 { "AdjuDrawProc", AdjuDrawProc },
892 { "EnterKeyProc", EnterKeyProc },
893 { "StopObservingProc", StopObservingProc },
894 { "StopExaminingProc", StopExaminingProc },
895 { "BackwardProc", BackwardProc },
896 { "ForwardProc", ForwardProc },
897 { "ToStartProc", ToStartProc },
898 { "ToEndProc", ToEndProc },
899 { "RevertProc", RevertProc },
900 { "TruncateGameProc", TruncateGameProc },
901 { "MoveNowProc", MoveNowProc },
902 { "RetractMoveProc", RetractMoveProc },
903 { "AlwaysQueenProc", AlwaysQueenProc },
904 { "AnimateDraggingProc", AnimateDraggingProc },
905 { "AnimateMovingProc", AnimateMovingProc },
906 { "AutoflagProc", AutoflagProc },
907 { "AutoflipProc", AutoflipProc },
908 { "AutobsProc", AutobsProc },
909 { "AutoraiseProc", AutoraiseProc },
910 { "AutosaveProc", AutosaveProc },
911 { "BlindfoldProc", BlindfoldProc },
912 { "FlashMovesProc", FlashMovesProc },
913 { "FlipViewProc", FlipViewProc },
914 { "GetMoveListProc", GetMoveListProc },
916 { "HighlightDraggingProc", HighlightDraggingProc },
918 { "HighlightLastMoveProc", HighlightLastMoveProc },
919 { "IcsAlarmProc", IcsAlarmProc },
920 { "MoveSoundProc", MoveSoundProc },
921 { "OldSaveStyleProc", OldSaveStyleProc },
922 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
923 { "PonderNextMoveProc", PonderNextMoveProc },
924 { "PopupExitMessageProc", PopupExitMessageProc },
925 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
926 { "PremoveProc", PremoveProc },
927 { "QuietPlayProc", QuietPlayProc },
928 { "ShowCoordsProc", ShowCoordsProc },
929 { "ShowThinkingProc", ShowThinkingProc },
930 { "HideThinkingProc", HideThinkingProc },
931 { "TestLegalityProc", TestLegalityProc },
932 { "SaveSettingsProc", SaveSettingsProc },
933 { "SaveOnExitProc", SaveOnExitProc },
934 { "InfoProc", InfoProc },
935 { "ManProc", ManProc },
936 { "HintProc", HintProc },
937 { "BookProc", BookProc },
938 { "AboutGameProc", AboutGameProc },
939 { "AboutProc", AboutProc },
940 { "DebugProc", DebugProc },
941 { "NothingProc", NothingProc },
942 { "CommentPopDown", (XtActionProc) CommentPopDown },
943 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
944 { "TagsPopDown", (XtActionProc) TagsPopDown },
945 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
946 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
947 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
948 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
949 { "GameListPopDown", (XtActionProc) GameListPopDown },
950 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
951 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
952 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
953 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
954 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
955 { "EnginePopDown", (XtActionProc) EnginePopDown },
956 { "UciPopDown", (XtActionProc) UciPopDown },
957 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
958 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
959 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
960 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
963 char globalTranslations[] =
964 ":<Key>R: ResignProc() \n \
965 :<Key>r: ResetProc() \n \
966 :<Key>g: LoadGameProc() \n \
967 :<Key>N: LoadNextGameProc() \n \
968 :<Key>P: LoadPrevGameProc() \n \
969 :<Key>Q: QuitProc() \n \
970 :<Key>F: ToEndProc() \n \
971 :<Key>f: ForwardProc() \n \
972 :<Key>B: ToStartProc() \n \
973 :<Key>b: BackwardProc() \n \
974 :<Key>p: PauseProc() \n \
975 :<Key>d: DrawProc() \n \
976 :<Key>t: CallFlagProc() \n \
977 :<Key>i: Iconify() \n \
978 :<Key>c: Iconify() \n \
979 :<Key>v: FlipViewProc() \n \
980 <KeyDown>Control_L: BackwardProc() \n \
981 <KeyUp>Control_L: ForwardProc() \n \
982 <KeyDown>Control_R: BackwardProc() \n \
983 <KeyUp>Control_R: ForwardProc() \n \
984 Shift<Key>1: AskQuestionProc(\"Direct command\",\
985 \"Send to chess program:\",,1) \n \
986 Shift<Key>2: AskQuestionProc(\"Direct command\",\
987 \"Send to second chess program:\",,2) \n";
989 char boardTranslations[] =
990 "<Btn1Down>: HandleUserMove() \n \
991 <Btn1Up>: HandleUserMove() \n \
992 <Btn1Motion>: AnimateUserMove() \n \
993 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
994 PieceMenuPopup(menuB) \n \
995 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
996 PieceMenuPopup(menuW) \n \
997 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
998 PieceMenuPopup(menuW) \n \
999 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1000 PieceMenuPopup(menuB) \n";
1002 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1003 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1005 char ICSInputTranslations[] =
1006 "<Key>Return: EnterKeyProc() \n";
1008 String xboardResources[] = {
1009 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1010 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1011 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1016 /* Max possible square size */
1017 #define MAXSQSIZE 256
1019 static int xpm_avail[MAXSQSIZE];
1021 #ifdef HAVE_DIR_STRUCT
1023 /* Extract piece size from filename */
1025 xpm_getsize(name, len, ext)
1036 if ((p=strchr(name, '.')) == NULL ||
1037 StrCaseCmp(p+1, ext) != 0)
1043 while (*p && isdigit(*p))
1050 /* Setup xpm_avail */
1052 xpm_getavail(dirname, ext)
1060 for (i=0; i<MAXSQSIZE; ++i)
1063 if (appData.debugMode)
1064 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1066 dir = opendir(dirname);
1069 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1070 programName, dirname);
1074 while ((ent=readdir(dir)) != NULL) {
1075 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1076 if (i > 0 && i < MAXSQSIZE)
1086 xpm_print_avail(fp, ext)
1092 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1093 for (i=1; i<MAXSQSIZE; ++i) {
1099 /* Return XPM piecesize closest to size */
1101 xpm_closest_to(dirname, size, ext)
1107 int sm_diff = MAXSQSIZE;
1111 xpm_getavail(dirname, ext);
1113 if (appData.debugMode)
1114 xpm_print_avail(stderr, ext);
1116 for (i=1; i<MAXSQSIZE; ++i) {
1119 diff = (diff<0) ? -diff : diff;
1120 if (diff < sm_diff) {
1128 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1134 #else /* !HAVE_DIR_STRUCT */
1135 /* If we are on a system without a DIR struct, we can't
1136 read the directory, so we can't collect a list of
1137 filenames, etc., so we can't do any size-fitting. */
1139 xpm_closest_to(dirname, size, ext)
1144 fprintf(stderr, _("\
1145 Warning: No DIR structure found on this system --\n\
1146 Unable to autosize for XPM/XIM pieces.\n\
1147 Please report this error to frankm@hiwaay.net.\n\
1148 Include system type & operating system in message.\n"));
1151 #endif /* HAVE_DIR_STRUCT */
1153 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1154 "magenta", "cyan", "white" };
1158 TextColors textColors[(int)NColorClasses];
1160 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1162 parse_color(str, which)
1166 char *p, buf[100], *d;
1169 if (strlen(str) > 99) /* watch bounds on buf */
1174 for (i=0; i<which; ++i) {
1181 /* Could be looking at something like:
1183 .. in which case we want to stop on a comma also */
1184 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1188 return -1; /* Use default for empty field */
1191 if (which == 2 || isdigit(*p))
1194 while (*p && isalpha(*p))
1199 for (i=0; i<8; ++i) {
1200 if (!StrCaseCmp(buf, cnames[i]))
1201 return which? (i+40) : (i+30);
1203 if (!StrCaseCmp(buf, "default")) return -1;
1205 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1210 parse_cpair(cc, str)
1214 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1215 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1220 /* bg and attr are optional */
1221 textColors[(int)cc].bg = parse_color(str, 1);
1222 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1223 textColors[(int)cc].attr = 0;
1229 /* Arrange to catch delete-window events */
1230 Atom wm_delete_window;
1232 CatchDeleteWindow(Widget w, String procname)
1235 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1236 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1237 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1244 XtSetArg(args[0], XtNiconic, False);
1245 XtSetValues(shellWidget, args, 1);
1247 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1250 //---------------------------------------------------------------------------------------------------------
1251 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1254 #define CW_USEDEFAULT (1<<31)
1255 #define ICS_TEXT_MENU_SIZE 90
1256 #define DEBUG_FILE "xboard.debug"
1257 #define SetCurrentDirectory chdir
1258 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1262 // these two must some day move to frontend.h, when they are implemented
1263 Boolean MoveHistoryIsUp();
1264 Boolean GameListIsUp();
1266 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1269 // front-end part of option handling
1271 // [HGM] This platform-dependent table provides the location for storing the color info
1272 extern char *crWhite, * crBlack;
1276 &appData.whitePieceColor,
1277 &appData.blackPieceColor,
1278 &appData.lightSquareColor,
1279 &appData.darkSquareColor,
1280 &appData.highlightSquareColor,
1281 &appData.premoveHighlightColor,
1294 ParseFont(char *name, int number)
1295 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1297 case 0: // CLOCK_FONT
1298 appData.clockFont = strdup(name);
1300 case 1: // MESSAGE_FONT
1301 appData.font = strdup(name);
1303 case 2: // COORD_FONT
1304 appData.coordFont = strdup(name);
1313 { // only 2 fonts currently
1314 appData.clockFont = CLOCK_FONT_NAME;
1315 appData.coordFont = COORD_FONT_NAME;
1316 appData.font = DEFAULT_FONT_NAME;
1321 { // no-op, until we identify the code for this already in XBoard and move it here
1325 ParseColor(int n, char *name)
1326 { // in XBoard, just copy the color-name string
1327 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1331 ParseTextAttribs(ColorClass cc, char *s)
1333 (&appData.colorShout)[cc] = strdup(s);
1337 ParseBoardSize(void *addr, char *name)
1339 appData.boardSize = strdup(name);
1344 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1348 SetCommPortDefaults()
1349 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1352 // [HGM] args: these three cases taken out to stay in front-end
1354 SaveFontArg(FILE *f, ArgDescriptor *ad)
1357 switch((int)ad->argLoc) {
1358 case 0: // CLOCK_FONT
1359 name = appData.clockFont;
1361 case 1: // MESSAGE_FONT
1362 name = appData.font;
1364 case 2: // COORD_FONT
1365 name = appData.coordFont;
1370 // Do not save fonts for now, as the saved font would be board-size specific
1371 // and not suitable for a re-start at another board size
1372 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1377 { // nothing to do, as the sounds are at all times represented by their text-string names already
1381 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1382 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1383 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1387 SaveColor(FILE *f, ArgDescriptor *ad)
1388 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1389 if(colorVariable[(int)ad->argLoc])
1390 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1394 SaveBoardSize(FILE *f, char *name, void *addr)
1395 { // wrapper to shield back-end from BoardSize & sizeInfo
1396 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1400 ParseCommPortSettings(char *s)
1401 { // no such option in XBoard (yet)
1404 extern Widget engineOutputShell;
1405 extern Widget tagsShell, editTagsShell;
1407 GetActualPlacement(Widget wg, WindowPlacement *wp)
1417 XtSetArg(args[i], XtNx, &x); i++;
1418 XtSetArg(args[i], XtNy, &y); i++;
1419 XtSetArg(args[i], XtNwidth, &w); i++;
1420 XtSetArg(args[i], XtNheight, &h); i++;
1421 XtGetValues(wg, args, i);
1430 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1431 // In XBoard this will have to wait until awareness of window parameters is implemented
1432 GetActualPlacement(shellWidget, &wpMain);
1433 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1434 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1435 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1436 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1437 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1438 else GetActualPlacement(editShell, &wpComment);
1439 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1440 else GetActualPlacement(editTagsShell, &wpTags);
1444 PrintCommPortSettings(FILE *f, char *name)
1445 { // This option does not exist in XBoard
1449 MySearchPath(char *installDir, char *name, char *fullname)
1450 { // just append installDir and name. Perhaps ExpandPath should be used here?
1451 name = ExpandPathName(name);
1452 if(name && name[0] == '/') strcpy(fullname, name); else {
1453 sprintf(fullname, "%s%c%s", installDir, '/', name);
1459 MyGetFullPathName(char *name, char *fullname)
1460 { // should use ExpandPath?
1461 name = ExpandPathName(name);
1462 strcpy(fullname, name);
1467 EnsureOnScreen(int *x, int *y, int minX, int minY)
1474 { // [HGM] args: allows testing if main window is realized from back-end
1475 return xBoardWindow != 0;
1479 PopUpStartupDialog()
1480 { // start menu not implemented in XBoard
1483 ConvertToLine(int argc, char **argv)
1485 static char line[128*1024], buf[1024];
1489 for(i=1; i<argc; i++) {
1490 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1491 && argv[i][0] != '{' )
1492 sprintf(buf, "{%s} ", argv[i]);
1493 else sprintf(buf, "%s ", argv[i]);
1496 line[strlen(line)-1] = NULLCHAR;
1500 //--------------------------------------------------------------------------------------------
1503 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1505 #define BoardSize int
1506 void InitDrawingSizes(BoardSize boardSize, int flags)
1507 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1508 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1510 XtGeometryResult gres;
1513 if(!formWidget) return;
1516 * Enable shell resizing.
1518 shellArgs[0].value = (XtArgVal) &w;
1519 shellArgs[1].value = (XtArgVal) &h;
1520 XtGetValues(shellWidget, shellArgs, 2);
1522 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1523 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1524 XtSetValues(shellWidget, &shellArgs[2], 4);
1526 XtSetArg(args[0], XtNdefaultDistance, &sep);
1527 XtGetValues(formWidget, args, 1);
1529 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1530 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1533 XtSetArg(args[0], XtNwidth, boardWidth);
1534 XtSetArg(args[1], XtNheight, boardHeight);
1535 XtSetValues(boardWidget, args, 2);
1537 timerWidth = (boardWidth - sep) / 2;
1538 XtSetArg(args[0], XtNwidth, timerWidth);
1539 XtSetValues(whiteTimerWidget, args, 1);
1540 XtSetValues(blackTimerWidget, args, 1);
1542 XawFormDoLayout(formWidget, False);
1544 if (appData.titleInWindow) {
1546 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1547 XtSetArg(args[i], XtNheight, &h); i++;
1548 XtGetValues(titleWidget, args, i);
1550 w = boardWidth - 2*bor;
1552 XtSetArg(args[0], XtNwidth, &w);
1553 XtGetValues(menuBarWidget, args, 1);
1554 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1557 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1558 if (gres != XtGeometryYes && appData.debugMode) {
1560 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1561 programName, gres, w, h, wr, hr);
1565 XawFormDoLayout(formWidget, True);
1568 * Inhibit shell resizing.
1570 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1571 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1572 shellArgs[4].value = shellArgs[2].value = w;
1573 shellArgs[5].value = shellArgs[3].value = h;
1574 XtSetValues(shellWidget, &shellArgs[0], 6);
1576 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1579 for(i=0; i<4; i++) {
1581 for(p=0; p<=(int)WhiteKing; p++)
1582 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1583 if(gameInfo.variant == VariantShogi) {
1584 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1585 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1586 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1587 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1588 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1591 if(gameInfo.variant == VariantGothic) {
1592 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1596 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1597 for(p=0; p<=(int)WhiteKing; p++)
1598 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1599 if(gameInfo.variant == VariantShogi) {
1600 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1601 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1602 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1603 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1604 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1607 if(gameInfo.variant == VariantGothic) {
1608 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1614 for(i=0; i<2; i++) {
1616 for(p=0; p<=(int)WhiteKing; p++)
1617 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1618 if(gameInfo.variant == VariantShogi) {
1619 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1620 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1621 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1622 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1623 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1626 if(gameInfo.variant == VariantGothic) {
1627 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1638 void EscapeExpand(char *p, char *q)
1639 { // [HGM] initstring: routine to shape up string arguments
1640 while(*p++ = *q++) if(p[-1] == '\\')
1642 case 'n': p[-1] = '\n'; break;
1643 case 'r': p[-1] = '\r'; break;
1644 case 't': p[-1] = '\t'; break;
1645 case '\\': p[-1] = '\\'; break;
1646 case 0: *p = 0; return;
1647 default: p[-1] = q[-1]; break;
1656 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1657 XSetWindowAttributes window_attributes;
1659 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1660 XrmValue vFrom, vTo;
1661 XtGeometryResult gres;
1664 int forceMono = False;
1666 srandom(time(0)); // [HGM] book: make random truly random
1668 setbuf(stdout, NULL);
1669 setbuf(stderr, NULL);
1672 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1673 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1677 programName = strrchr(argv[0], '/');
1678 if (programName == NULL)
1679 programName = argv[0];
1684 XtSetLanguageProc(NULL, NULL, NULL);
1685 bindtextdomain(PACKAGE, LOCALEDIR);
1686 textdomain(PACKAGE);
1690 XtAppInitialize(&appContext, "XBoard", shellOptions,
1691 XtNumber(shellOptions),
1692 &argc, argv, xboardResources, NULL, 0);
1693 appData.boardSize = "";
1694 InitAppData(ConvertToLine(argc, argv));
1696 if (p == NULL) p = "/tmp";
1697 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1698 gameCopyFilename = (char*) malloc(i);
1699 gamePasteFilename = (char*) malloc(i);
1700 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1701 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1703 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1704 clientResources, XtNumber(clientResources),
1707 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1708 static char buf[MSG_SIZ];
1709 EscapeExpand(buf, appData.initString);
1710 appData.initString = strdup(buf);
1711 EscapeExpand(buf, appData.secondInitString);
1712 appData.secondInitString = strdup(buf);
1713 EscapeExpand(buf, appData.firstComputerString);
1714 appData.firstComputerString = strdup(buf);
1715 EscapeExpand(buf, appData.secondComputerString);
1716 appData.secondComputerString = strdup(buf);
1719 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1722 if (chdir(chessDir) != 0) {
1723 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1729 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1730 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1731 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1732 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1735 setbuf(debugFP, NULL);
1738 /* [HGM,HR] make sure board size is acceptable */
1739 if(appData.NrFiles > BOARD_FILES ||
1740 appData.NrRanks > BOARD_RANKS )
1741 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1744 /* This feature does not work; animation needs a rewrite */
1745 appData.highlightDragging = FALSE;
1749 xDisplay = XtDisplay(shellWidget);
1750 xScreen = DefaultScreen(xDisplay);
1751 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1753 gameInfo.variant = StringToVariant(appData.variant);
1754 InitPosition(FALSE);
1757 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1759 if (isdigit(appData.boardSize[0])) {
1760 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1761 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1762 &fontPxlSize, &smallLayout, &tinyLayout);
1764 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1765 programName, appData.boardSize);
1769 /* Find some defaults; use the nearest known size */
1770 SizeDefaults *szd, *nearest;
1771 int distance = 99999;
1772 nearest = szd = sizeDefaults;
1773 while (szd->name != NULL) {
1774 if (abs(szd->squareSize - squareSize) < distance) {
1776 distance = abs(szd->squareSize - squareSize);
1777 if (distance == 0) break;
1781 if (i < 2) lineGap = nearest->lineGap;
1782 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1783 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1784 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1785 if (i < 6) smallLayout = nearest->smallLayout;
1786 if (i < 7) tinyLayout = nearest->tinyLayout;
1789 SizeDefaults *szd = sizeDefaults;
1790 if (*appData.boardSize == NULLCHAR) {
1791 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1792 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1795 if (szd->name == NULL) szd--;
1796 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1798 while (szd->name != NULL &&
1799 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1800 if (szd->name == NULL) {
1801 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1802 programName, appData.boardSize);
1806 squareSize = szd->squareSize;
1807 lineGap = szd->lineGap;
1808 clockFontPxlSize = szd->clockFontPxlSize;
1809 coordFontPxlSize = szd->coordFontPxlSize;
1810 fontPxlSize = szd->fontPxlSize;
1811 smallLayout = szd->smallLayout;
1812 tinyLayout = szd->tinyLayout;
1815 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1816 if (strlen(appData.pixmapDirectory) > 0) {
1817 p = ExpandPathName(appData.pixmapDirectory);
1819 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1820 appData.pixmapDirectory);
1823 if (appData.debugMode) {
1824 fprintf(stderr, _("\
1825 XBoard square size (hint): %d\n\
1826 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1828 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1829 if (appData.debugMode) {
1830 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1834 /* [HR] height treated separately (hacked) */
1835 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1836 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1837 if (appData.showJail == 1) {
1838 /* Jail on top and bottom */
1839 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1840 XtSetArg(boardArgs[2], XtNheight,
1841 boardHeight + 2*(lineGap + squareSize));
1842 } else if (appData.showJail == 2) {
1844 XtSetArg(boardArgs[1], XtNwidth,
1845 boardWidth + 2*(lineGap + squareSize));
1846 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1849 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1850 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1854 * Determine what fonts to use.
1856 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1857 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1858 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1859 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1860 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1861 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1862 appData.font = FindFont(appData.font, fontPxlSize);
1863 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1864 countFontStruct = XQueryFont(xDisplay, countFontID);
1865 // appData.font = FindFont(appData.font, fontPxlSize);
1867 xdb = XtDatabase(xDisplay);
1868 XrmPutStringResource(&xdb, "*font", appData.font);
1871 * Detect if there are not enough colors available and adapt.
1873 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1874 appData.monoMode = True;
1877 if (!appData.monoMode) {
1878 vFrom.addr = (caddr_t) appData.lightSquareColor;
1879 vFrom.size = strlen(appData.lightSquareColor);
1880 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1881 if (vTo.addr == NULL) {
1882 appData.monoMode = True;
1885 lightSquareColor = *(Pixel *) vTo.addr;
1888 if (!appData.monoMode) {
1889 vFrom.addr = (caddr_t) appData.darkSquareColor;
1890 vFrom.size = strlen(appData.darkSquareColor);
1891 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1892 if (vTo.addr == NULL) {
1893 appData.monoMode = True;
1896 darkSquareColor = *(Pixel *) vTo.addr;
1899 if (!appData.monoMode) {
1900 vFrom.addr = (caddr_t) appData.whitePieceColor;
1901 vFrom.size = strlen(appData.whitePieceColor);
1902 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1903 if (vTo.addr == NULL) {
1904 appData.monoMode = True;
1907 whitePieceColor = *(Pixel *) vTo.addr;
1910 if (!appData.monoMode) {
1911 vFrom.addr = (caddr_t) appData.blackPieceColor;
1912 vFrom.size = strlen(appData.blackPieceColor);
1913 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1914 if (vTo.addr == NULL) {
1915 appData.monoMode = True;
1918 blackPieceColor = *(Pixel *) vTo.addr;
1922 if (!appData.monoMode) {
1923 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1924 vFrom.size = strlen(appData.highlightSquareColor);
1925 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1926 if (vTo.addr == NULL) {
1927 appData.monoMode = True;
1930 highlightSquareColor = *(Pixel *) vTo.addr;
1934 if (!appData.monoMode) {
1935 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1936 vFrom.size = strlen(appData.premoveHighlightColor);
1937 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1938 if (vTo.addr == NULL) {
1939 appData.monoMode = True;
1942 premoveHighlightColor = *(Pixel *) vTo.addr;
1947 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1950 if (appData.bitmapDirectory == NULL ||
1951 appData.bitmapDirectory[0] == NULLCHAR)
1952 appData.bitmapDirectory = DEF_BITMAP_DIR;
1955 if (appData.lowTimeWarning && !appData.monoMode) {
1956 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1957 vFrom.size = strlen(appData.lowTimeWarningColor);
1958 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1959 if (vTo.addr == NULL)
1960 appData.monoMode = True;
1962 lowTimeWarningColor = *(Pixel *) vTo.addr;
1965 if (appData.monoMode && appData.debugMode) {
1966 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1967 (unsigned long) XWhitePixel(xDisplay, xScreen),
1968 (unsigned long) XBlackPixel(xDisplay, xScreen));
1971 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1972 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1973 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1974 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1975 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1976 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1977 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1978 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1979 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1980 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1982 if (appData.colorize) {
1984 _("%s: can't parse color names; disabling colorization\n"),
1987 appData.colorize = FALSE;
1989 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1990 textColors[ColorNone].attr = 0;
1992 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1998 layoutName = "tinyLayout";
1999 } else if (smallLayout) {
2000 layoutName = "smallLayout";
2002 layoutName = "normalLayout";
2004 /* Outer layoutWidget is there only to provide a name for use in
2005 resources that depend on the layout style */
2007 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2008 layoutArgs, XtNumber(layoutArgs));
2010 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2011 formArgs, XtNumber(formArgs));
2012 XtSetArg(args[0], XtNdefaultDistance, &sep);
2013 XtGetValues(formWidget, args, 1);
2016 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2017 XtSetArg(args[0], XtNtop, XtChainTop);
2018 XtSetArg(args[1], XtNbottom, XtChainTop);
2019 XtSetArg(args[2], XtNright, XtChainLeft);
2020 XtSetValues(menuBarWidget, args, 3);
2022 widgetList[j++] = whiteTimerWidget =
2023 XtCreateWidget("whiteTime", labelWidgetClass,
2024 formWidget, timerArgs, XtNumber(timerArgs));
2025 XtSetArg(args[0], XtNfont, clockFontStruct);
2026 XtSetArg(args[1], XtNtop, XtChainTop);
2027 XtSetArg(args[2], XtNbottom, XtChainTop);
2028 XtSetValues(whiteTimerWidget, args, 3);
2030 widgetList[j++] = blackTimerWidget =
2031 XtCreateWidget("blackTime", labelWidgetClass,
2032 formWidget, timerArgs, XtNumber(timerArgs));
2033 XtSetArg(args[0], XtNfont, clockFontStruct);
2034 XtSetArg(args[1], XtNtop, XtChainTop);
2035 XtSetArg(args[2], XtNbottom, XtChainTop);
2036 XtSetValues(blackTimerWidget, args, 3);
2038 if (appData.titleInWindow) {
2039 widgetList[j++] = titleWidget =
2040 XtCreateWidget("title", labelWidgetClass, formWidget,
2041 titleArgs, XtNumber(titleArgs));
2042 XtSetArg(args[0], XtNtop, XtChainTop);
2043 XtSetArg(args[1], XtNbottom, XtChainTop);
2044 XtSetValues(titleWidget, args, 2);
2047 if (appData.showButtonBar) {
2048 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2049 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2050 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2051 XtSetArg(args[2], XtNtop, XtChainTop);
2052 XtSetArg(args[3], XtNbottom, XtChainTop);
2053 XtSetValues(buttonBarWidget, args, 4);
2056 widgetList[j++] = messageWidget =
2057 XtCreateWidget("message", labelWidgetClass, formWidget,
2058 messageArgs, XtNumber(messageArgs));
2059 XtSetArg(args[0], XtNtop, XtChainTop);
2060 XtSetArg(args[1], XtNbottom, XtChainTop);
2061 XtSetValues(messageWidget, args, 2);
2063 widgetList[j++] = boardWidget =
2064 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2065 XtNumber(boardArgs));
2067 XtManageChildren(widgetList, j);
2069 timerWidth = (boardWidth - sep) / 2;
2070 XtSetArg(args[0], XtNwidth, timerWidth);
2071 XtSetValues(whiteTimerWidget, args, 1);
2072 XtSetValues(blackTimerWidget, args, 1);
2074 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2075 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2076 XtGetValues(whiteTimerWidget, args, 2);
2078 if (appData.showButtonBar) {
2079 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2080 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2081 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2085 * formWidget uses these constraints but they are stored
2089 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2090 XtSetValues(menuBarWidget, args, i);
2091 if (appData.titleInWindow) {
2094 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2095 XtSetValues(whiteTimerWidget, args, i);
2097 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2098 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2099 XtSetValues(blackTimerWidget, args, i);
2101 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2102 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2103 XtSetValues(titleWidget, args, i);
2105 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2106 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2107 XtSetValues(messageWidget, args, i);
2108 if (appData.showButtonBar) {
2110 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2111 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2112 XtSetValues(buttonBarWidget, args, i);
2116 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2117 XtSetValues(whiteTimerWidget, args, i);
2119 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2120 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2121 XtSetValues(blackTimerWidget, args, i);
2123 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2124 XtSetValues(titleWidget, args, i);
2126 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2127 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2128 XtSetValues(messageWidget, args, i);
2129 if (appData.showButtonBar) {
2131 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2132 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2133 XtSetValues(buttonBarWidget, args, i);
2138 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2139 XtSetValues(whiteTimerWidget, args, i);
2141 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2142 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2143 XtSetValues(blackTimerWidget, args, i);
2145 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2146 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2147 XtSetValues(messageWidget, args, i);
2148 if (appData.showButtonBar) {
2150 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2151 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2152 XtSetValues(buttonBarWidget, args, i);
2156 XtSetArg(args[0], XtNfromVert, messageWidget);
2157 XtSetArg(args[1], XtNtop, XtChainTop);
2158 XtSetArg(args[2], XtNbottom, XtChainBottom);
2159 XtSetArg(args[3], XtNleft, XtChainLeft);
2160 XtSetArg(args[4], XtNright, XtChainRight);
2161 XtSetValues(boardWidget, args, 5);
2163 XtRealizeWidget(shellWidget);
2166 XtSetArg(args[0], XtNx, wpMain.x);
2167 XtSetArg(args[1], XtNy, wpMain.y);
2168 XtSetValues(shellWidget, args, 2);
2172 * Correct the width of the message and title widgets.
2173 * It is not known why some systems need the extra fudge term.
2174 * The value "2" is probably larger than needed.
2176 XawFormDoLayout(formWidget, False);
2178 #define WIDTH_FUDGE 2
2180 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2181 XtSetArg(args[i], XtNheight, &h); i++;
2182 XtGetValues(messageWidget, args, i);
2183 if (appData.showButtonBar) {
2185 XtSetArg(args[i], XtNwidth, &w); i++;
2186 XtGetValues(buttonBarWidget, args, i);
2187 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2189 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2192 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2193 if (gres != XtGeometryYes && appData.debugMode) {
2194 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2195 programName, gres, w, h, wr, hr);
2198 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2199 /* The size used for the child widget in layout lags one resize behind
2200 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2202 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2203 if (gres != XtGeometryYes && appData.debugMode) {
2204 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2205 programName, gres, w, h, wr, hr);
2208 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2209 XtSetArg(args[1], XtNright, XtChainRight);
2210 XtSetValues(messageWidget, args, 2);
2212 if (appData.titleInWindow) {
2214 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2215 XtSetArg(args[i], XtNheight, &h); i++;
2216 XtGetValues(titleWidget, args, i);
2218 w = boardWidth - 2*bor;
2220 XtSetArg(args[0], XtNwidth, &w);
2221 XtGetValues(menuBarWidget, args, 1);
2222 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2225 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2226 if (gres != XtGeometryYes && appData.debugMode) {
2228 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2229 programName, gres, w, h, wr, hr);
2232 XawFormDoLayout(formWidget, True);
2234 xBoardWindow = XtWindow(boardWidget);
2236 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2237 // not need to go into InitDrawingSizes().
2241 * Create X checkmark bitmap and initialize option menu checks.
2243 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2244 checkmark_bits, checkmark_width, checkmark_height);
2245 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2246 if (appData.alwaysPromoteToQueen) {
2247 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2250 if (appData.animateDragging) {
2251 XtSetValues(XtNameToWidget(menuBarWidget,
2252 "menuOptions.Animate Dragging"),
2255 if (appData.animate) {
2256 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2259 if (appData.autoComment) {
2260 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2263 if (appData.autoCallFlag) {
2264 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2267 if (appData.autoFlipView) {
2268 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2271 if (appData.autoObserve) {
2272 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2275 if (appData.autoRaiseBoard) {
2276 XtSetValues(XtNameToWidget(menuBarWidget,
2277 "menuOptions.Auto Raise Board"), args, 1);
2279 if (appData.autoSaveGames) {
2280 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2283 if (appData.saveGameFile[0] != NULLCHAR) {
2284 /* Can't turn this off from menu */
2285 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2287 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2291 if (appData.blindfold) {
2292 XtSetValues(XtNameToWidget(menuBarWidget,
2293 "menuOptions.Blindfold"), args, 1);
2295 if (appData.flashCount > 0) {
2296 XtSetValues(XtNameToWidget(menuBarWidget,
2297 "menuOptions.Flash Moves"),
2300 if (appData.getMoveList) {
2301 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2305 if (appData.highlightDragging) {
2306 XtSetValues(XtNameToWidget(menuBarWidget,
2307 "menuOptions.Highlight Dragging"),
2311 if (appData.highlightLastMove) {
2312 XtSetValues(XtNameToWidget(menuBarWidget,
2313 "menuOptions.Highlight Last Move"),
2316 if (appData.icsAlarm) {
2317 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2320 if (appData.ringBellAfterMoves) {
2321 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2324 if (appData.oldSaveStyle) {
2325 XtSetValues(XtNameToWidget(menuBarWidget,
2326 "menuOptions.Old Save Style"), args, 1);
2328 if (appData.periodicUpdates) {
2329 XtSetValues(XtNameToWidget(menuBarWidget,
2330 "menuOptions.Periodic Updates"), args, 1);
2332 if (appData.ponderNextMove) {
2333 XtSetValues(XtNameToWidget(menuBarWidget,
2334 "menuOptions.Ponder Next Move"), args, 1);
2336 if (appData.popupExitMessage) {
2337 XtSetValues(XtNameToWidget(menuBarWidget,
2338 "menuOptions.Popup Exit Message"), args, 1);
2340 if (appData.popupMoveErrors) {
2341 XtSetValues(XtNameToWidget(menuBarWidget,
2342 "menuOptions.Popup Move Errors"), args, 1);
2344 if (appData.premove) {
2345 XtSetValues(XtNameToWidget(menuBarWidget,
2346 "menuOptions.Premove"), args, 1);
2348 if (appData.quietPlay) {
2349 XtSetValues(XtNameToWidget(menuBarWidget,
2350 "menuOptions.Quiet Play"), args, 1);
2352 if (appData.showCoords) {
2353 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2356 if (appData.hideThinkingFromHuman) {
2357 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2360 if (appData.testLegality) {
2361 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2364 if (saveSettingsOnExit) {
2365 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2372 ReadBitmap(&wIconPixmap, "icon_white.bm",
2373 icon_white_bits, icon_white_width, icon_white_height);
2374 ReadBitmap(&bIconPixmap, "icon_black.bm",
2375 icon_black_bits, icon_black_width, icon_black_height);
2376 iconPixmap = wIconPixmap;
2378 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2379 XtSetValues(shellWidget, args, i);
2382 * Create a cursor for the board widget.
2384 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2385 XChangeWindowAttributes(xDisplay, xBoardWindow,
2386 CWCursor, &window_attributes);
2389 * Inhibit shell resizing.
2391 shellArgs[0].value = (XtArgVal) &w;
2392 shellArgs[1].value = (XtArgVal) &h;
2393 XtGetValues(shellWidget, shellArgs, 2);
2394 shellArgs[4].value = shellArgs[2].value = w;
2395 shellArgs[5].value = shellArgs[3].value = h;
2396 XtSetValues(shellWidget, &shellArgs[2], 4);
2397 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2398 marginH = h - boardHeight;
2400 CatchDeleteWindow(shellWidget, "QuitProc");
2405 if (appData.bitmapDirectory[0] != NULLCHAR) {
2412 /* Create regular pieces */
2413 if (!useImages) CreatePieces();
2418 if (appData.animate || appData.animateDragging)
2421 XtAugmentTranslations(formWidget,
2422 XtParseTranslationTable(globalTranslations));
2423 XtAugmentTranslations(boardWidget,
2424 XtParseTranslationTable(boardTranslations));
2425 XtAugmentTranslations(whiteTimerWidget,
2426 XtParseTranslationTable(whiteTranslations));
2427 XtAugmentTranslations(blackTimerWidget,
2428 XtParseTranslationTable(blackTranslations));
2430 /* Why is the following needed on some versions of X instead
2431 * of a translation? */
2432 XtAddEventHandler(boardWidget, ExposureMask, False,
2433 (XtEventHandler) EventProc, NULL);
2436 /* [AS] Restore layout */
2437 if( wpMoveHistory.visible ) {
2441 if( wpEvalGraph.visible )
2446 if( wpEngineOutput.visible ) {
2447 EngineOutputPopUp();
2452 if (errorExitStatus == -1) {
2453 if (appData.icsActive) {
2454 /* We now wait until we see "login:" from the ICS before
2455 sending the logon script (problems with timestamp otherwise) */
2456 /*ICSInitScript();*/
2457 if (appData.icsInputBox) ICSInputBoxPopUp();
2461 signal(SIGWINCH, TermSizeSigHandler);
2463 signal(SIGINT, IntSigHandler);
2464 signal(SIGTERM, IntSigHandler);
2465 if (*appData.cmailGameName != NULLCHAR) {
2466 signal(SIGUSR1, CmailSigHandler);
2469 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2472 XtAppMainLoop(appContext);
2473 if (appData.debugMode) fclose(debugFP); // [DM] debug
2480 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2481 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2483 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2484 unlink(gameCopyFilename);
2485 unlink(gamePasteFilename);
2488 RETSIGTYPE TermSizeSigHandler(int sig)
2501 CmailSigHandler(sig)
2507 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2509 /* Activate call-back function CmailSigHandlerCallBack() */
2510 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2512 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2516 CmailSigHandlerCallBack(isr, closure, message, count, error)
2524 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2526 /**** end signal code ****/
2536 f = fopen(appData.icsLogon, "r");
2542 strcat(buf, appData.icsLogon);
2543 f = fopen(buf, "r");
2547 ProcessICSInitScript(f);
2554 EditCommentPopDown();
2569 if (!menuBarWidget) return;
2570 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2572 DisplayError("menuStep.Revert", 0);
2574 XtSetSensitive(w, !grey);
2579 SetMenuEnables(enab)
2583 if (!menuBarWidget) return;
2584 while (enab->name != NULL) {
2585 w = XtNameToWidget(menuBarWidget, enab->name);
2587 DisplayError(enab->name, 0);
2589 XtSetSensitive(w, enab->value);
2595 Enables icsEnables[] = {
2596 { "menuFile.Mail Move", False },
2597 { "menuFile.Reload CMail Message", False },
2598 { "menuMode.Machine Black", False },
2599 { "menuMode.Machine White", False },
2600 { "menuMode.Analysis Mode", False },
2601 { "menuMode.Analyze File", False },
2602 { "menuMode.Two Machines", False },
2604 { "menuHelp.Hint", False },
2605 { "menuHelp.Book", False },
2606 { "menuStep.Move Now", False },
2607 { "menuOptions.Periodic Updates", False },
2608 { "menuOptions.Hide Thinking", False },
2609 { "menuOptions.Ponder Next Move", False },
2614 Enables ncpEnables[] = {
2615 { "menuFile.Mail Move", False },
2616 { "menuFile.Reload CMail Message", False },
2617 { "menuMode.Machine White", False },
2618 { "menuMode.Machine Black", False },
2619 { "menuMode.Analysis Mode", False },
2620 { "menuMode.Analyze File", False },
2621 { "menuMode.Two Machines", False },
2622 { "menuMode.ICS Client", False },
2623 { "menuMode.ICS Input Box", False },
2624 { "Action", False },
2625 { "menuStep.Revert", False },
2626 { "menuStep.Move Now", False },
2627 { "menuStep.Retract Move", False },
2628 { "menuOptions.Auto Comment", False },
2629 { "menuOptions.Auto Flag", False },
2630 { "menuOptions.Auto Flip View", False },
2631 { "menuOptions.Auto Observe", False },
2632 { "menuOptions.Auto Raise Board", False },
2633 { "menuOptions.Get Move List", False },
2634 { "menuOptions.ICS Alarm", False },
2635 { "menuOptions.Move Sound", False },
2636 { "menuOptions.Quiet Play", False },
2637 { "menuOptions.Hide Thinking", False },
2638 { "menuOptions.Periodic Updates", False },
2639 { "menuOptions.Ponder Next Move", False },
2640 { "menuHelp.Hint", False },
2641 { "menuHelp.Book", False },
2645 Enables gnuEnables[] = {
2646 { "menuMode.ICS Client", False },
2647 { "menuMode.ICS Input Box", False },
2648 { "menuAction.Accept", False },
2649 { "menuAction.Decline", False },
2650 { "menuAction.Rematch", False },
2651 { "menuAction.Adjourn", False },
2652 { "menuAction.Stop Examining", False },
2653 { "menuAction.Stop Observing", False },
2654 { "menuStep.Revert", False },
2655 { "menuOptions.Auto Comment", False },
2656 { "menuOptions.Auto Observe", False },
2657 { "menuOptions.Auto Raise Board", False },
2658 { "menuOptions.Get Move List", False },
2659 { "menuOptions.Premove", False },
2660 { "menuOptions.Quiet Play", False },
2662 /* The next two options rely on SetCmailMode being called *after* */
2663 /* SetGNUMode so that when GNU is being used to give hints these */
2664 /* menu options are still available */
2666 { "menuFile.Mail Move", False },
2667 { "menuFile.Reload CMail Message", False },
2671 Enables cmailEnables[] = {
2673 { "menuAction.Call Flag", False },
2674 { "menuAction.Draw", True },
2675 { "menuAction.Adjourn", False },
2676 { "menuAction.Abort", False },
2677 { "menuAction.Stop Observing", False },
2678 { "menuAction.Stop Examining", False },
2679 { "menuFile.Mail Move", True },
2680 { "menuFile.Reload CMail Message", True },
2684 Enables trainingOnEnables[] = {
2685 { "menuMode.Edit Comment", False },
2686 { "menuMode.Pause", False },
2687 { "menuStep.Forward", False },
2688 { "menuStep.Backward", False },
2689 { "menuStep.Forward to End", False },
2690 { "menuStep.Back to Start", False },
2691 { "menuStep.Move Now", False },
2692 { "menuStep.Truncate Game", False },
2696 Enables trainingOffEnables[] = {
2697 { "menuMode.Edit Comment", True },
2698 { "menuMode.Pause", True },
2699 { "menuStep.Forward", True },
2700 { "menuStep.Backward", True },
2701 { "menuStep.Forward to End", True },
2702 { "menuStep.Back to Start", True },
2703 { "menuStep.Move Now", True },
2704 { "menuStep.Truncate Game", True },
2708 Enables machineThinkingEnables[] = {
2709 { "menuFile.Load Game", False },
2710 { "menuFile.Load Next Game", False },
2711 { "menuFile.Load Previous Game", False },
2712 { "menuFile.Reload Same Game", False },
2713 { "menuFile.Paste Game", False },
2714 { "menuFile.Load Position", False },
2715 { "menuFile.Load Next Position", False },
2716 { "menuFile.Load Previous Position", False },
2717 { "menuFile.Reload Same Position", False },
2718 { "menuFile.Paste Position", False },
2719 { "menuMode.Machine White", False },
2720 { "menuMode.Machine Black", False },
2721 { "menuMode.Two Machines", False },
2722 { "menuStep.Retract Move", False },
2726 Enables userThinkingEnables[] = {
2727 { "menuFile.Load Game", True },
2728 { "menuFile.Load Next Game", True },
2729 { "menuFile.Load Previous Game", True },
2730 { "menuFile.Reload Same Game", True },
2731 { "menuFile.Paste Game", True },
2732 { "menuFile.Load Position", True },
2733 { "menuFile.Load Next Position", True },
2734 { "menuFile.Load Previous Position", True },
2735 { "menuFile.Reload Same Position", True },
2736 { "menuFile.Paste Position", True },
2737 { "menuMode.Machine White", True },
2738 { "menuMode.Machine Black", True },
2739 { "menuMode.Two Machines", True },
2740 { "menuStep.Retract Move", True },
2746 SetMenuEnables(icsEnables);
2749 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2750 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2757 SetMenuEnables(ncpEnables);
2763 SetMenuEnables(gnuEnables);
2769 SetMenuEnables(cmailEnables);
2775 SetMenuEnables(trainingOnEnables);
2776 if (appData.showButtonBar) {
2777 XtSetSensitive(buttonBarWidget, False);
2783 SetTrainingModeOff()
2785 SetMenuEnables(trainingOffEnables);
2786 if (appData.showButtonBar) {
2787 XtSetSensitive(buttonBarWidget, True);
2792 SetUserThinkingEnables()
2794 if (appData.noChessProgram) return;
2795 SetMenuEnables(userThinkingEnables);
2799 SetMachineThinkingEnables()
2801 if (appData.noChessProgram) return;
2802 SetMenuEnables(machineThinkingEnables);
2804 case MachinePlaysBlack:
2805 case MachinePlaysWhite:
2806 case TwoMachinesPlay:
2807 XtSetSensitive(XtNameToWidget(menuBarWidget,
2808 ModeToWidgetName(gameMode)), True);
2815 #define Abs(n) ((n)<0 ? -(n) : (n))
2818 * Find a font that matches "pattern" that is as close as
2819 * possible to the targetPxlSize. Prefer fonts that are k
2820 * pixels smaller to fonts that are k pixels larger. The
2821 * pattern must be in the X Consortium standard format,
2822 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2823 * The return value should be freed with XtFree when no
2826 char *FindFont(pattern, targetPxlSize)
2830 char **fonts, *p, *best, *scalable, *scalableTail;
2831 int i, j, nfonts, minerr, err, pxlSize;
2834 char **missing_list;
2836 char *def_string, *base_fnt_lst, strInt[3];
2838 XFontStruct **fnt_list;
2840 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2841 sprintf(strInt, "%d", targetPxlSize);
2842 p = strstr(pattern, "--");
2843 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2844 strcat(base_fnt_lst, strInt);
2845 strcat(base_fnt_lst, strchr(p + 2, '-'));
2847 if ((fntSet = XCreateFontSet(xDisplay,
2851 &def_string)) == NULL) {
2853 fprintf(stderr, _("Unable to create font set.\n"));
2857 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2859 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2861 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2862 programName, pattern);
2870 for (i=0; i<nfonts; i++) {
2873 if (*p != '-') continue;
2875 if (*p == NULLCHAR) break;
2876 if (*p++ == '-') j++;
2878 if (j < 7) continue;
2881 scalable = fonts[i];
2884 err = pxlSize - targetPxlSize;
2885 if (Abs(err) < Abs(minerr) ||
2886 (minerr > 0 && err < 0 && -err == minerr)) {
2892 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2893 /* If the error is too big and there is a scalable font,
2894 use the scalable font. */
2895 int headlen = scalableTail - scalable;
2896 p = (char *) XtMalloc(strlen(scalable) + 10);
2897 while (isdigit(*scalableTail)) scalableTail++;
2898 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2900 p = (char *) XtMalloc(strlen(best) + 1);
2903 if (appData.debugMode) {
2904 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2905 pattern, targetPxlSize, p);
2908 if (missing_count > 0)
2909 XFreeStringList(missing_list);
2910 XFreeFontSet(xDisplay, fntSet);
2912 XFreeFontNames(fonts);
2919 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2920 | GCBackground | GCFunction | GCPlaneMask;
2921 XGCValues gc_values;
2924 gc_values.plane_mask = AllPlanes;
2925 gc_values.line_width = lineGap;
2926 gc_values.line_style = LineSolid;
2927 gc_values.function = GXcopy;
2929 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2930 gc_values.background = XBlackPixel(xDisplay, xScreen);
2931 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2933 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2934 gc_values.background = XWhitePixel(xDisplay, xScreen);
2935 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2936 XSetFont(xDisplay, coordGC, coordFontID);
2938 // [HGM] make font for holdings counts (white on black0
2939 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2940 gc_values.background = XBlackPixel(xDisplay, xScreen);
2941 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2942 XSetFont(xDisplay, countGC, countFontID);
2944 if (appData.monoMode) {
2945 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2946 gc_values.background = XWhitePixel(xDisplay, xScreen);
2947 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2949 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2950 gc_values.background = XBlackPixel(xDisplay, xScreen);
2951 lightSquareGC = wbPieceGC
2952 = XtGetGC(shellWidget, value_mask, &gc_values);
2954 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2955 gc_values.background = XWhitePixel(xDisplay, xScreen);
2956 darkSquareGC = bwPieceGC
2957 = XtGetGC(shellWidget, value_mask, &gc_values);
2959 if (DefaultDepth(xDisplay, xScreen) == 1) {
2960 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2961 gc_values.function = GXcopyInverted;
2962 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2963 gc_values.function = GXcopy;
2964 if (XBlackPixel(xDisplay, xScreen) == 1) {
2965 bwPieceGC = darkSquareGC;
2966 wbPieceGC = copyInvertedGC;
2968 bwPieceGC = copyInvertedGC;
2969 wbPieceGC = lightSquareGC;
2973 gc_values.foreground = highlightSquareColor;
2974 gc_values.background = highlightSquareColor;
2975 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2977 gc_values.foreground = premoveHighlightColor;
2978 gc_values.background = premoveHighlightColor;
2979 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2981 gc_values.foreground = lightSquareColor;
2982 gc_values.background = darkSquareColor;
2983 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2985 gc_values.foreground = darkSquareColor;
2986 gc_values.background = lightSquareColor;
2987 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2989 gc_values.foreground = jailSquareColor;
2990 gc_values.background = jailSquareColor;
2991 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2993 gc_values.foreground = whitePieceColor;
2994 gc_values.background = darkSquareColor;
2995 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2997 gc_values.foreground = whitePieceColor;
2998 gc_values.background = lightSquareColor;
2999 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3001 gc_values.foreground = whitePieceColor;
3002 gc_values.background = jailSquareColor;
3003 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3005 gc_values.foreground = blackPieceColor;
3006 gc_values.background = darkSquareColor;
3007 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3009 gc_values.foreground = blackPieceColor;
3010 gc_values.background = lightSquareColor;
3011 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3013 gc_values.foreground = blackPieceColor;
3014 gc_values.background = jailSquareColor;
3015 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3019 void loadXIM(xim, xmask, filename, dest, mask)
3032 fp = fopen(filename, "rb");
3034 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3041 for (y=0; y<h; ++y) {
3042 for (x=0; x<h; ++x) {
3047 XPutPixel(xim, x, y, blackPieceColor);
3049 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3052 XPutPixel(xim, x, y, darkSquareColor);
3054 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3057 XPutPixel(xim, x, y, whitePieceColor);
3059 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3062 XPutPixel(xim, x, y, lightSquareColor);
3064 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3070 /* create Pixmap of piece */
3071 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3073 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3076 /* create Pixmap of clipmask
3077 Note: We assume the white/black pieces have the same
3078 outline, so we make only 6 masks. This is okay
3079 since the XPM clipmask routines do the same. */
3081 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3083 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3086 /* now create the 1-bit version */
3087 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3090 values.foreground = 1;
3091 values.background = 0;
3093 /* Don't use XtGetGC, not read only */
3094 maskGC = XCreateGC(xDisplay, *mask,
3095 GCForeground | GCBackground, &values);
3096 XCopyPlane(xDisplay, temp, *mask, maskGC,
3097 0, 0, squareSize, squareSize, 0, 0, 1);
3098 XFreePixmap(xDisplay, temp);
3103 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3105 void CreateXIMPieces()
3110 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3115 /* The XSynchronize calls were copied from CreatePieces.
3116 Not sure if needed, but can't hurt */
3117 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3120 /* temp needed by loadXIM() */
3121 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3122 0, 0, ss, ss, AllPlanes, XYPixmap);
3124 if (strlen(appData.pixmapDirectory) == 0) {
3128 if (appData.monoMode) {
3129 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3133 fprintf(stderr, _("\nLoading XIMs...\n"));
3135 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3136 fprintf(stderr, "%d", piece+1);
3137 for (kind=0; kind<4; kind++) {
3138 fprintf(stderr, ".");
3139 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3140 ExpandPathName(appData.pixmapDirectory),
3141 piece <= (int) WhiteKing ? "" : "w",
3142 pieceBitmapNames[piece],
3144 ximPieceBitmap[kind][piece] =
3145 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3146 0, 0, ss, ss, AllPlanes, XYPixmap);
3147 if (appData.debugMode)
3148 fprintf(stderr, _("(File:%s:) "), buf);
3149 loadXIM(ximPieceBitmap[kind][piece],
3151 &(xpmPieceBitmap2[kind][piece]),
3152 &(ximMaskPm2[piece]));
3153 if(piece <= (int)WhiteKing)
3154 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3156 fprintf(stderr," ");
3158 /* Load light and dark squares */
3159 /* If the LSQ and DSQ pieces don't exist, we will
3160 draw them with solid squares. */
3161 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3162 if (access(buf, 0) != 0) {
3166 fprintf(stderr, _("light square "));
3168 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3169 0, 0, ss, ss, AllPlanes, XYPixmap);
3170 if (appData.debugMode)
3171 fprintf(stderr, _("(File:%s:) "), buf);
3173 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3174 fprintf(stderr, _("dark square "));
3175 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3176 ExpandPathName(appData.pixmapDirectory), ss);
3177 if (appData.debugMode)
3178 fprintf(stderr, _("(File:%s:) "), buf);
3180 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3181 0, 0, ss, ss, AllPlanes, XYPixmap);
3182 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3183 xpmJailSquare = xpmLightSquare;
3185 fprintf(stderr, _("Done.\n"));
3187 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3191 void CreateXPMPieces()
3195 u_int ss = squareSize;
3197 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3198 XpmColorSymbol symbols[4];
3200 /* The XSynchronize calls were copied from CreatePieces.
3201 Not sure if needed, but can't hurt */
3202 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3204 /* Setup translations so piece colors match square colors */
3205 symbols[0].name = "light_piece";
3206 symbols[0].value = appData.whitePieceColor;
3207 symbols[1].name = "dark_piece";
3208 symbols[1].value = appData.blackPieceColor;
3209 symbols[2].name = "light_square";
3210 symbols[2].value = appData.lightSquareColor;
3211 symbols[3].name = "dark_square";
3212 symbols[3].value = appData.darkSquareColor;
3214 attr.valuemask = XpmColorSymbols;
3215 attr.colorsymbols = symbols;
3216 attr.numsymbols = 4;
3218 if (appData.monoMode) {
3219 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3223 if (strlen(appData.pixmapDirectory) == 0) {
3224 XpmPieces* pieces = builtInXpms;
3227 while (pieces->size != squareSize && pieces->size) pieces++;
3228 if (!pieces->size) {
3229 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3232 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3233 for (kind=0; kind<4; kind++) {
3235 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3236 pieces->xpm[piece][kind],
3237 &(xpmPieceBitmap2[kind][piece]),
3238 NULL, &attr)) != 0) {
3239 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3243 if(piece <= (int) WhiteKing)
3244 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3248 xpmJailSquare = xpmLightSquare;
3252 fprintf(stderr, _("\nLoading XPMs...\n"));
3255 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3256 fprintf(stderr, "%d ", piece+1);
3257 for (kind=0; kind<4; kind++) {
3258 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3259 ExpandPathName(appData.pixmapDirectory),
3260 piece > (int) WhiteKing ? "w" : "",
3261 pieceBitmapNames[piece],
3263 if (appData.debugMode) {
3264 fprintf(stderr, _("(File:%s:) "), buf);
3266 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3267 &(xpmPieceBitmap2[kind][piece]),
3268 NULL, &attr)) != 0) {
3269 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3270 // [HGM] missing: read of unorthodox piece failed; substitute King.
3271 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3272 ExpandPathName(appData.pixmapDirectory),
3274 if (appData.debugMode) {
3275 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3277 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3278 &(xpmPieceBitmap2[kind][piece]),
3282 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3287 if(piece <= (int) WhiteKing)
3288 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3291 /* Load light and dark squares */
3292 /* If the LSQ and DSQ pieces don't exist, we will
3293 draw them with solid squares. */
3294 fprintf(stderr, _("light square "));
3295 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3296 if (access(buf, 0) != 0) {
3300 if (appData.debugMode)
3301 fprintf(stderr, _("(File:%s:) "), buf);
3303 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3304 &xpmLightSquare, NULL, &attr)) != 0) {
3305 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3308 fprintf(stderr, _("dark square "));
3309 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3310 ExpandPathName(appData.pixmapDirectory), ss);
3311 if (appData.debugMode) {
3312 fprintf(stderr, _("(File:%s:) "), buf);
3314 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3315 &xpmDarkSquare, NULL, &attr)) != 0) {
3316 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3320 xpmJailSquare = xpmLightSquare;
3321 fprintf(stderr, _("Done.\n"));
3323 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3326 #endif /* HAVE_LIBXPM */
3329 /* No built-in bitmaps */
3334 u_int ss = squareSize;
3336 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3339 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3340 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3341 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3342 pieceBitmapNames[piece],
3343 ss, kind == SOLID ? 's' : 'o');
3344 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3345 if(piece <= (int)WhiteKing)
3346 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3350 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3354 /* With built-in bitmaps */
3357 BuiltInBits* bib = builtInBits;
3360 u_int ss = squareSize;
3362 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3365 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3367 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3368 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3369 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3370 pieceBitmapNames[piece],
3371 ss, kind == SOLID ? 's' : 'o');
3372 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3373 bib->bits[kind][piece], ss, ss);
3374 if(piece <= (int)WhiteKing)
3375 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3379 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3384 void ReadBitmap(pm, name, bits, wreq, hreq)
3387 unsigned char bits[];
3393 char msg[MSG_SIZ], fullname[MSG_SIZ];
3395 if (*appData.bitmapDirectory != NULLCHAR) {
3396 strcpy(fullname, appData.bitmapDirectory);
3397 strcat(fullname, "/");
3398 strcat(fullname, name);
3399 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3400 &w, &h, pm, &x_hot, &y_hot);
3401 fprintf(stderr, "load %s\n", name);
3402 if (errcode != BitmapSuccess) {
3404 case BitmapOpenFailed:
3405 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3407 case BitmapFileInvalid:
3408 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3410 case BitmapNoMemory:
3411 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3415 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3419 fprintf(stderr, _("%s: %s...using built-in\n"),
3421 } else if (w != wreq || h != hreq) {
3423 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3424 programName, fullname, w, h, wreq, hreq);
3430 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3439 if (lineGap == 0) return;
3441 /* [HR] Split this into 2 loops for non-square boards. */
3443 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3444 gridSegments[i].x1 = 0;
3445 gridSegments[i].x2 =
3446 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3447 gridSegments[i].y1 = gridSegments[i].y2
3448 = lineGap / 2 + (i * (squareSize + lineGap));
3451 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3452 gridSegments[j + i].y1 = 0;
3453 gridSegments[j + i].y2 =
3454 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3455 gridSegments[j + i].x1 = gridSegments[j + i].x2
3456 = lineGap / 2 + (j * (squareSize + lineGap));
3460 static void MenuBarSelect(w, addr, index)
3465 XtActionProc proc = (XtActionProc) addr;
3467 (proc)(NULL, NULL, NULL, NULL);
3470 void CreateMenuBarPopup(parent, name, mb)
3480 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3483 XtSetArg(args[j], XtNleftMargin, 20); j++;
3484 XtSetArg(args[j], XtNrightMargin, 20); j++;
3486 while (mi->string != NULL) {
3487 if (strcmp(mi->string, "----") == 0) {
3488 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3491 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3492 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3494 XtAddCallback(entry, XtNcallback,
3495 (XtCallbackProc) MenuBarSelect,
3496 (caddr_t) mi->proc);
3502 Widget CreateMenuBar(mb)
3506 Widget anchor, menuBar;
3508 char menuName[MSG_SIZ];
3511 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3512 XtSetArg(args[j], XtNvSpace, 0); j++;
3513 XtSetArg(args[j], XtNborderWidth, 0); j++;
3514 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3515 formWidget, args, j);
3517 while (mb->name != NULL) {
3518 strcpy(menuName, "menu");
3519 strcat(menuName, mb->name);
3521 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3524 shortName[0] = _(mb->name)[0];
3525 shortName[1] = NULLCHAR;
3526 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3529 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3532 XtSetArg(args[j], XtNborderWidth, 0); j++;
3533 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3535 CreateMenuBarPopup(menuBar, menuName, mb);
3541 Widget CreateButtonBar(mi)
3545 Widget button, buttonBar;
3549 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3551 XtSetArg(args[j], XtNhSpace, 0); j++;
3553 XtSetArg(args[j], XtNborderWidth, 0); j++;
3554 XtSetArg(args[j], XtNvSpace, 0); j++;
3555 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3556 formWidget, args, j);
3558 while (mi->string != NULL) {
3561 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3562 XtSetArg(args[j], XtNborderWidth, 0); j++;
3564 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3565 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3566 buttonBar, args, j);
3567 XtAddCallback(button, XtNcallback,
3568 (XtCallbackProc) MenuBarSelect,
3569 (caddr_t) mi->proc);
3576 CreatePieceMenu(name, color)
3583 ChessSquare selection;
3585 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3586 boardWidget, args, 0);
3588 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3589 String item = pieceMenuStrings[color][i];
3591 if (strcmp(item, "----") == 0) {
3592 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3595 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3596 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3598 selection = pieceMenuTranslation[color][i];
3599 XtAddCallback(entry, XtNcallback,
3600 (XtCallbackProc) PieceMenuSelect,
3601 (caddr_t) selection);
3602 if (selection == WhitePawn || selection == BlackPawn) {
3603 XtSetArg(args[0], XtNpopupOnEntry, entry);
3604 XtSetValues(menu, args, 1);
3617 ChessSquare selection;
3619 whitePieceMenu = CreatePieceMenu("menuW", 0);
3620 blackPieceMenu = CreatePieceMenu("menuB", 1);
3622 XtRegisterGrabAction(PieceMenuPopup, True,
3623 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3624 GrabModeAsync, GrabModeAsync);
3626 XtSetArg(args[0], XtNlabel, _("Drop"));
3627 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3628 boardWidget, args, 1);
3629 for (i = 0; i < DROP_MENU_SIZE; i++) {
3630 String item = dropMenuStrings[i];
3632 if (strcmp(item, "----") == 0) {
3633 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3636 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3637 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3639 selection = dropMenuTranslation[i];
3640 XtAddCallback(entry, XtNcallback,
3641 (XtCallbackProc) DropMenuSelect,
3642 (caddr_t) selection);
3647 void SetupDropMenu()
3655 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3656 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3657 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3658 dmEnables[i].piece);
3659 XtSetSensitive(entry, p != NULL || !appData.testLegality
3660 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3661 && !appData.icsActive));
3663 while (p && *p++ == dmEnables[i].piece) count++;
3664 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3666 XtSetArg(args[j], XtNlabel, label); j++;
3667 XtSetValues(entry, args, j);
3671 void PieceMenuPopup(w, event, params, num_params)
3675 Cardinal *num_params;
3678 if (event->type != ButtonPress) return;
3679 if (errorUp) ErrorPopDown();
3683 whichMenu = params[0];
3685 case IcsPlayingWhite:
3686 case IcsPlayingBlack:
3688 case MachinePlaysWhite:
3689 case MachinePlaysBlack:
3690 if (appData.testLegality &&
3691 gameInfo.variant != VariantBughouse &&
3692 gameInfo.variant != VariantCrazyhouse) return;
3694 whichMenu = "menuD";
3700 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3701 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3702 pmFromX = pmFromY = -1;
3706 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3708 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3710 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3713 static void PieceMenuSelect(w, piece, junk)
3718 if (pmFromX < 0 || pmFromY < 0) return;
3719 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3722 static void DropMenuSelect(w, piece, junk)
3727 if (pmFromX < 0 || pmFromY < 0) return;
3728 DropMenuEvent(piece, pmFromX, pmFromY);
3731 void WhiteClock(w, event, prms, nprms)
3737 if (gameMode == EditPosition || gameMode == IcsExamining) {
3738 SetWhiteToPlayEvent();
3739 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3744 void BlackClock(w, event, prms, nprms)
3750 if (gameMode == EditPosition || gameMode == IcsExamining) {
3751 SetBlackToPlayEvent();
3752 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3759 * If the user selects on a border boundary, return -1; if off the board,
3760 * return -2. Otherwise map the event coordinate to the square.
3762 int EventToSquare(x, limit)
3770 if ((x % (squareSize + lineGap)) >= squareSize)
3772 x /= (squareSize + lineGap);
3778 static void do_flash_delay(msec)
3784 static void drawHighlight(file, rank, gc)
3790 if (lineGap == 0 || appData.blindfold) return;
3793 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3794 (squareSize + lineGap);
3795 y = lineGap/2 + rank * (squareSize + lineGap);
3797 x = lineGap/2 + file * (squareSize + lineGap);
3798 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3799 (squareSize + lineGap);
3802 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3803 squareSize+lineGap, squareSize+lineGap);
3806 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3807 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3810 SetHighlights(fromX, fromY, toX, toY)
3811 int fromX, fromY, toX, toY;
3813 if (hi1X != fromX || hi1Y != fromY) {
3814 if (hi1X >= 0 && hi1Y >= 0) {
3815 drawHighlight(hi1X, hi1Y, lineGC);
3817 if (fromX >= 0 && fromY >= 0) {
3818 drawHighlight(fromX, fromY, highlineGC);
3821 if (hi2X != toX || hi2Y != toY) {
3822 if (hi2X >= 0 && hi2Y >= 0) {
3823 drawHighlight(hi2X, hi2Y, lineGC);
3825 if (toX >= 0 && toY >= 0) {
3826 drawHighlight(toX, toY, highlineGC);
3838 SetHighlights(-1, -1, -1, -1);
3843 SetPremoveHighlights(fromX, fromY, toX, toY)
3844 int fromX, fromY, toX, toY;
3846 if (pm1X != fromX || pm1Y != fromY) {
3847 if (pm1X >= 0 && pm1Y >= 0) {
3848 drawHighlight(pm1X, pm1Y, lineGC);
3850 if (fromX >= 0 && fromY >= 0) {
3851 drawHighlight(fromX, fromY, prelineGC);
3854 if (pm2X != toX || pm2Y != toY) {
3855 if (pm2X >= 0 && pm2Y >= 0) {
3856 drawHighlight(pm2X, pm2Y, lineGC);
3858 if (toX >= 0 && toY >= 0) {
3859 drawHighlight(toX, toY, prelineGC);
3869 ClearPremoveHighlights()
3871 SetPremoveHighlights(-1, -1, -1, -1);
3874 static void BlankSquare(x, y, color, piece, dest)
3879 if (useImages && useImageSqs) {
3883 pm = xpmLightSquare;
3888 case 2: /* neutral */
3893 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3894 squareSize, squareSize, x, y);
3904 case 2: /* neutral */
3909 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3914 I split out the routines to draw a piece so that I could
3915 make a generic flash routine.
3917 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3919 int square_color, x, y;
3922 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3923 switch (square_color) {
3925 case 2: /* neutral */
3927 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3928 ? *pieceToOutline(piece)
3929 : *pieceToSolid(piece),
3930 dest, bwPieceGC, 0, 0,
3931 squareSize, squareSize, x, y);
3934 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3935 ? *pieceToSolid(piece)
3936 : *pieceToOutline(piece),
3937 dest, wbPieceGC, 0, 0,
3938 squareSize, squareSize, x, y);
3943 static void monoDrawPiece(piece, square_color, x, y, dest)
3945 int square_color, x, y;
3948 switch (square_color) {
3950 case 2: /* neutral */
3952 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3953 ? *pieceToOutline(piece)
3954 : *pieceToSolid(piece),
3955 dest, bwPieceGC, 0, 0,
3956 squareSize, squareSize, x, y, 1);
3959 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3960 ? *pieceToSolid(piece)
3961 : *pieceToOutline(piece),
3962 dest, wbPieceGC, 0, 0,
3963 squareSize, squareSize, x, y, 1);
3968 static void colorDrawPiece(piece, square_color, x, y, dest)
3970 int square_color, x, y;
3973 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3974 switch (square_color) {
3976 XCopyPlane(xDisplay, *pieceToSolid(piece),
3977 dest, (int) piece < (int) BlackPawn
3978 ? wlPieceGC : blPieceGC, 0, 0,
3979 squareSize, squareSize, x, y, 1);
3982 XCopyPlane(xDisplay, *pieceToSolid(piece),
3983 dest, (int) piece < (int) BlackPawn
3984 ? wdPieceGC : bdPieceGC, 0, 0,
3985 squareSize, squareSize, x, y, 1);
3987 case 2: /* neutral */
3989 XCopyPlane(xDisplay, *pieceToSolid(piece),
3990 dest, (int) piece < (int) BlackPawn
3991 ? wjPieceGC : bjPieceGC, 0, 0,
3992 squareSize, squareSize, x, y, 1);
3997 static void colorDrawPieceImage(piece, square_color, x, y, dest)
3999 int square_color, x, y;
4004 switch (square_color) {
4006 case 2: /* neutral */
4008 if ((int)piece < (int) BlackPawn) {
4016 if ((int)piece < (int) BlackPawn) {
4024 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4025 dest, wlPieceGC, 0, 0,
4026 squareSize, squareSize, x, y);
4029 typedef void (*DrawFunc)();
4031 DrawFunc ChooseDrawFunc()
4033 if (appData.monoMode) {
4034 if (DefaultDepth(xDisplay, xScreen) == 1) {
4035 return monoDrawPiece_1bit;
4037 return monoDrawPiece;
4041 return colorDrawPieceImage;
4043 return colorDrawPiece;
4047 /* [HR] determine square color depending on chess variant. */
4048 static int SquareColor(row, column)
4053 if (gameInfo.variant == VariantXiangqi) {
4054 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4056 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4058 } else if (row <= 4) {
4064 square_color = ((column + row) % 2) == 1;
4067 /* [hgm] holdings: next line makes all holdings squares light */
4068 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4070 return square_color;
4073 void DrawSquare(row, column, piece, do_flash)
4074 int row, column, do_flash;
4077 int square_color, x, y, direction, font_ascent, font_descent;
4080 XCharStruct overall;
4084 /* Calculate delay in milliseconds (2-delays per complete flash) */
4085 flash_delay = 500 / appData.flashRate;
4088 x = lineGap + ((BOARD_WIDTH-1)-column) *
4089 (squareSize + lineGap);
4090 y = lineGap + row * (squareSize + lineGap);
4092 x = lineGap + column * (squareSize + lineGap);
4093 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4094 (squareSize + lineGap);
4097 square_color = SquareColor(row, column);
4099 if ( // [HGM] holdings: blank out area between board and holdings
4100 column == BOARD_LEFT-1 || column == BOARD_RGHT
4101 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4102 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4103 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4105 // [HGM] print piece counts next to holdings
4106 string[1] = NULLCHAR;
4107 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4108 string[0] = '0' + piece;
4109 XTextExtents(countFontStruct, string, 1, &direction,
4110 &font_ascent, &font_descent, &overall);
4111 if (appData.monoMode) {
4112 XDrawImageString(xDisplay, xBoardWindow, countGC,
4113 x + squareSize - overall.width - 2,
4114 y + font_ascent + 1, string, 1);
4116 XDrawString(xDisplay, xBoardWindow, countGC,
4117 x + squareSize - overall.width - 2,
4118 y + font_ascent + 1, string, 1);
4121 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4122 string[0] = '0' + piece;
4123 XTextExtents(countFontStruct, string, 1, &direction,
4124 &font_ascent, &font_descent, &overall);
4125 if (appData.monoMode) {
4126 XDrawImageString(xDisplay, xBoardWindow, countGC,
4127 x + 2, y + font_ascent + 1, string, 1);
4129 XDrawString(xDisplay, xBoardWindow, countGC,
4130 x + 2, y + font_ascent + 1, string, 1);
4134 if (piece == EmptySquare || appData.blindfold) {
4135 BlankSquare(x, y, square_color, piece, xBoardWindow);
4137 drawfunc = ChooseDrawFunc();
4138 if (do_flash && appData.flashCount > 0) {
4139 for (i=0; i<appData.flashCount; ++i) {
4141 drawfunc(piece, square_color, x, y, xBoardWindow);
4142 XSync(xDisplay, False);
4143 do_flash_delay(flash_delay);
4145 BlankSquare(x, y, square_color, piece, xBoardWindow);
4146 XSync(xDisplay, False);
4147 do_flash_delay(flash_delay);
4150 drawfunc(piece, square_color, x, y, xBoardWindow);
4154 string[1] = NULLCHAR;
4155 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4156 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4157 string[0] = 'a' + column - BOARD_LEFT;
4158 XTextExtents(coordFontStruct, string, 1, &direction,
4159 &font_ascent, &font_descent, &overall);
4160 if (appData.monoMode) {
4161 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4162 x + squareSize - overall.width - 2,
4163 y + squareSize - font_descent - 1, string, 1);
4165 XDrawString(xDisplay, xBoardWindow, coordGC,
4166 x + squareSize - overall.width - 2,
4167 y + squareSize - font_descent - 1, string, 1);
4170 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4171 string[0] = ONE + row;
4172 XTextExtents(coordFontStruct, string, 1, &direction,
4173 &font_ascent, &font_descent, &overall);
4174 if (appData.monoMode) {
4175 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4176 x + 2, y + font_ascent + 1, string, 1);
4178 XDrawString(xDisplay, xBoardWindow, coordGC,
4179 x + 2, y + font_ascent + 1, string, 1);
4185 /* Why is this needed on some versions of X? */
4186 void EventProc(widget, unused, event)
4191 if (!XtIsRealized(widget))
4194 switch (event->type) {
4196 if (event->xexpose.count > 0) return; /* no clipping is done */
4197 XDrawPosition(widget, True, NULL);
4205 void DrawPosition(fullRedraw, board)
4206 /*Boolean*/int fullRedraw;
4209 XDrawPosition(boardWidget, fullRedraw, board);
4212 /* Returns 1 if there are "too many" differences between b1 and b2
4213 (i.e. more than 1 move was made) */
4214 static int too_many_diffs(b1, b2)
4220 for (i=0; i<BOARD_HEIGHT; ++i) {
4221 for (j=0; j<BOARD_WIDTH; ++j) {
4222 if (b1[i][j] != b2[i][j]) {
4223 if (++c > 4) /* Castling causes 4 diffs */
4232 /* Matrix describing castling maneuvers */
4233 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4234 static int castling_matrix[4][5] = {
4235 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4236 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4237 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4238 { 7, 7, 4, 5, 6 } /* 0-0, black */
4241 /* Checks whether castling occurred. If it did, *rrow and *rcol
4242 are set to the destination (row,col) of the rook that moved.
4244 Returns 1 if castling occurred, 0 if not.
4246 Note: Only handles a max of 1 castling move, so be sure
4247 to call too_many_diffs() first.
4249 static int check_castle_draw(newb, oldb, rrow, rcol)
4256 /* For each type of castling... */
4257 for (i=0; i<4; ++i) {
4258 r = castling_matrix[i];
4260 /* Check the 4 squares involved in the castling move */
4262 for (j=1; j<=4; ++j) {
4263 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4270 /* All 4 changed, so it must be a castling move */
4279 static int damage[BOARD_RANKS][BOARD_FILES];
4282 * event handler for redrawing the board
4284 void XDrawPosition(w, repaint, board)
4286 /*Boolean*/int repaint;
4290 static int lastFlipView = 0;
4291 static int lastBoardValid = 0;
4292 static Board lastBoard;
4296 if (board == NULL) {
4297 if (!lastBoardValid) return;
4300 if (!lastBoardValid || lastFlipView != flipView) {
4301 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4302 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4307 * It would be simpler to clear the window with XClearWindow()
4308 * but this causes a very distracting flicker.
4311 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4313 /* If too much changes (begin observing new game, etc.), don't
4315 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4317 /* Special check for castling so we don't flash both the king
4318 and the rook (just flash the king). */
4320 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4321 /* Draw rook with NO flashing. King will be drawn flashing later */
4322 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4323 lastBoard[rrow][rcol] = board[rrow][rcol];
4327 /* First pass -- Draw (newly) empty squares and repair damage.
4328 This prevents you from having a piece show up twice while it
4329 is flashing on its new square */
4330 for (i = 0; i < BOARD_HEIGHT; i++)
4331 for (j = 0; j < BOARD_WIDTH; j++)
4332 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4334 DrawSquare(i, j, board[i][j], 0);
4335 damage[i][j] = False;
4338 /* Second pass -- Draw piece(s) in new position and flash them */
4339 for (i = 0; i < BOARD_HEIGHT; i++)
4340 for (j = 0; j < BOARD_WIDTH; j++)
4341 if (board[i][j] != lastBoard[i][j]) {
4342 DrawSquare(i, j, board[i][j], do_flash);
4346 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4347 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4349 for (i = 0; i < BOARD_HEIGHT; i++)
4350 for (j = 0; j < BOARD_WIDTH; j++) {
4351 DrawSquare(i, j, board[i][j], 0);
4352 damage[i][j] = False;
4356 CopyBoard(lastBoard, board);
4358 lastFlipView = flipView;
4360 /* Draw highlights */
4361 if (pm1X >= 0 && pm1Y >= 0) {
4362 drawHighlight(pm1X, pm1Y, prelineGC);
4364 if (pm2X >= 0 && pm2Y >= 0) {
4365 drawHighlight(pm2X, pm2Y, prelineGC);
4367 if (hi1X >= 0 && hi1Y >= 0) {
4368 drawHighlight(hi1X, hi1Y, highlineGC);
4370 if (hi2X >= 0 && hi2Y >= 0) {
4371 drawHighlight(hi2X, hi2Y, highlineGC);
4374 /* If piece being dragged around board, must redraw that too */
4377 XSync(xDisplay, False);
4382 * event handler for redrawing the board
4384 void DrawPositionProc(w, event, prms, nprms)
4390 XDrawPosition(w, True, NULL);
4395 * event handler for parsing user moves
4397 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4398 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4399 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4400 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4401 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4402 // and at the end FinishMove() to perform the move after optional promotion popups.
4403 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4404 void HandleUserMove(w, event, prms, nprms)
4410 if (w != boardWidget || errorExitStatus != -1) return;
4413 if (event->type == ButtonPress) {
4414 XtPopdown(promotionShell);
4415 XtDestroyWidget(promotionShell);
4416 promotionUp = False;
4424 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4425 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4426 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4429 void AnimateUserMove (Widget w, XEvent * event,
4430 String * params, Cardinal * nParams)
4432 DragPieceMove(event->xmotion.x, event->xmotion.y);
4435 Widget CommentCreate(name, text, mutable, callback, lines)
4437 int /*Boolean*/ mutable;
4438 XtCallbackProc callback;
4442 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4447 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4448 XtGetValues(boardWidget, args, j);
4451 XtSetArg(args[j], XtNresizable, True); j++;
4454 XtCreatePopupShell(name, topLevelShellWidgetClass,
4455 shellWidget, args, j);
4458 XtCreatePopupShell(name, transientShellWidgetClass,
4459 shellWidget, args, j);
4462 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4463 layoutArgs, XtNumber(layoutArgs));
4465 XtCreateManagedWidget("form", formWidgetClass, layout,
4466 formArgs, XtNumber(formArgs));
4470 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4471 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4473 XtSetArg(args[j], XtNstring, text); j++;
4474 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4475 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4476 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4477 XtSetArg(args[j], XtNright, XtChainRight); j++;
4478 XtSetArg(args[j], XtNresizable, True); j++;
4479 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4480 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4481 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4482 XtSetArg(args[j], XtNautoFill, True); j++;
4483 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4485 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4489 XtSetArg(args[j], XtNfromVert, edit); j++;
4490 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4491 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4492 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4493 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4495 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4496 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4499 XtSetArg(args[j], XtNfromVert, edit); j++;
4500 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4501 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4502 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4503 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4504 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4506 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4507 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4510 XtSetArg(args[j], XtNfromVert, edit); j++;
4511 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4512 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4513 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4514 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4515 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4517 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4518 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4521 XtSetArg(args[j], XtNfromVert, edit); j++;
4522 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4523 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4524 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4525 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4527 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4528 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4531 XtSetArg(args[j], XtNfromVert, edit); j++;
4532 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4533 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4534 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4535 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4536 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4538 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4539 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4542 XtRealizeWidget(shell);
4544 if (commentX == -1) {
4547 Dimension pw_height;
4548 Dimension ew_height;
4551 XtSetArg(args[j], XtNheight, &ew_height); j++;
4552 XtGetValues(edit, args, j);
4555 XtSetArg(args[j], XtNheight, &pw_height); j++;
4556 XtGetValues(shell, args, j);
4557 commentH = pw_height + (lines - 1) * ew_height;
4558 commentW = bw_width - 16;
4560 XSync(xDisplay, False);
4562 /* This code seems to tickle an X bug if it is executed too soon
4563 after xboard starts up. The coordinates get transformed as if
4564 the main window was positioned at (0, 0).
4566 XtTranslateCoords(shellWidget,
4567 (bw_width - commentW) / 2, 0 - commentH / 2,
4568 &commentX, &commentY);
4570 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4571 RootWindowOfScreen(XtScreen(shellWidget)),
4572 (bw_width - commentW) / 2, 0 - commentH / 2,
4577 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4580 if(wpComment.width > 0) {
4581 commentX = wpComment.x;
4582 commentY = wpComment.y;
4583 commentW = wpComment.width;
4584 commentH = wpComment.height;
4588 XtSetArg(args[j], XtNheight, commentH); j++;
4589 XtSetArg(args[j], XtNwidth, commentW); j++;
4590 XtSetArg(args[j], XtNx, commentX); j++;
4591 XtSetArg(args[j], XtNy, commentY); j++;
4592 XtSetValues(shell, args, j);
4593 XtSetKeyboardFocus(shell, edit);
4598 /* Used for analysis window and ICS input window */
4599 Widget MiscCreate(name, text, mutable, callback, lines)
4601 int /*Boolean*/ mutable;
4602 XtCallbackProc callback;
4606 Widget shell, layout, form, edit;
4608 Dimension bw_width, pw_height, ew_height, w, h;
4614 XtSetArg(args[j], XtNresizable, True); j++;
4617 XtCreatePopupShell(name, topLevelShellWidgetClass,
4618 shellWidget, args, j);
4621 XtCreatePopupShell(name, transientShellWidgetClass,
4622 shellWidget, args, j);
4625 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4626 layoutArgs, XtNumber(layoutArgs));
4628 XtCreateManagedWidget("form", formWidgetClass, layout,
4629 formArgs, XtNumber(formArgs));
4633 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4634 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4636 XtSetArg(args[j], XtNstring, text); j++;
4637 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4638 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4639 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4640 XtSetArg(args[j], XtNright, XtChainRight); j++;
4641 XtSetArg(args[j], XtNresizable, True); j++;
4642 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4643 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4644 XtSetArg(args[j], XtNautoFill, True); j++;
4645 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4647 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4649 XtRealizeWidget(shell);
4652 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4653 XtGetValues(boardWidget, args, j);
4656 XtSetArg(args[j], XtNheight, &ew_height); j++;
4657 XtGetValues(edit, args, j);
4660 XtSetArg(args[j], XtNheight, &pw_height); j++;
4661 XtGetValues(shell, args, j);
4662 h = pw_height + (lines - 1) * ew_height;
4665 XSync(xDisplay, False);
4667 /* This code seems to tickle an X bug if it is executed too soon
4668 after xboard starts up. The coordinates get transformed as if
4669 the main window was positioned at (0, 0).
4671 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4673 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4674 RootWindowOfScreen(XtScreen(shellWidget)),
4675 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4679 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4682 XtSetArg(args[j], XtNheight, h); j++;
4683 XtSetArg(args[j], XtNwidth, w); j++;
4684 XtSetArg(args[j], XtNx, x); j++;
4685 XtSetArg(args[j], XtNy, y); j++;
4686 XtSetValues(shell, args, j);
4692 static int savedIndex; /* gross that this is global */
4694 void EditCommentPopUp(index, title, text)
4703 if (text == NULL) text = "";
4705 if (editShell == NULL) {
4707 CommentCreate(title, text, True, EditCommentCallback, 4);
4708 XtRealizeWidget(editShell);
4709 CatchDeleteWindow(editShell, "EditCommentPopDown");
4711 edit = XtNameToWidget(editShell, "*form.text");
4713 XtSetArg(args[j], XtNstring, text); j++;
4714 XtSetValues(edit, args, j);
4716 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4717 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4718 XtSetValues(editShell, args, j);
4721 XtPopup(editShell, XtGrabNone);
4725 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4726 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4730 void EditCommentCallback(w, client_data, call_data)
4732 XtPointer client_data, call_data;
4740 XtSetArg(args[j], XtNlabel, &name); j++;
4741 XtGetValues(w, args, j);
4743 if (strcmp(name, _("ok")) == 0) {
4744 edit = XtNameToWidget(editShell, "*form.text");
4746 XtSetArg(args[j], XtNstring, &val); j++;
4747 XtGetValues(edit, args, j);
4748 ReplaceComment(savedIndex, val);
4749 EditCommentPopDown();
4750 } else if (strcmp(name, _("cancel")) == 0) {
4751 EditCommentPopDown();
4752 } else if (strcmp(name, _("clear")) == 0) {
4753 edit = XtNameToWidget(editShell, "*form.text");
4754 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4755 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4759 void EditCommentPopDown()
4764 if (!editUp) return;
4766 XtSetArg(args[j], XtNx, &commentX); j++;
4767 XtSetArg(args[j], XtNy, &commentY); j++;
4768 XtSetArg(args[j], XtNheight, &commentH); j++;
4769 XtSetArg(args[j], XtNwidth, &commentW); j++;
4770 XtGetValues(editShell, args, j);
4771 XtPopdown(editShell);
4774 XtSetArg(args[j], XtNleftBitmap, None); j++;
4775 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4779 void ICSInputBoxPopUp()
4784 char *title = _("ICS Input");
4787 if (ICSInputShell == NULL) {
4788 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4789 tr = XtParseTranslationTable(ICSInputTranslations);
4790 edit = XtNameToWidget(ICSInputShell, "*form.text");
4791 XtOverrideTranslations(edit, tr);
4792 XtRealizeWidget(ICSInputShell);
4793 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4796 edit = XtNameToWidget(ICSInputShell, "*form.text");
4798 XtSetArg(args[j], XtNstring, ""); j++;
4799 XtSetValues(edit, args, j);
4801 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4802 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4803 XtSetValues(ICSInputShell, args, j);
4806 XtPopup(ICSInputShell, XtGrabNone);
4807 XtSetKeyboardFocus(ICSInputShell, edit);
4809 ICSInputBoxUp = True;
4811 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4812 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4816 void ICSInputSendText()
4823 edit = XtNameToWidget(ICSInputShell, "*form.text");
4825 XtSetArg(args[j], XtNstring, &val); j++;
4826 XtGetValues(edit, args, j);
4827 SendMultiLineToICS(val);
4828 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4829 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4832 void ICSInputBoxPopDown()
4837 if (!ICSInputBoxUp) return;
4839 XtPopdown(ICSInputShell);
4840 ICSInputBoxUp = False;
4842 XtSetArg(args[j], XtNleftBitmap, None); j++;
4843 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4847 void CommentPopUp(title, text)
4854 if (commentShell == NULL) {
4856 CommentCreate(title, text, False, CommentCallback, 4);
4857 XtRealizeWidget(commentShell);
4858 CatchDeleteWindow(commentShell, "CommentPopDown");
4860 edit = XtNameToWidget(commentShell, "*form.text");
4862 XtSetArg(args[j], XtNstring, text); j++;
4863 XtSetValues(edit, args, j);
4865 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4866 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4867 XtSetValues(commentShell, args, j);
4870 XtPopup(commentShell, XtGrabNone);
4871 XSync(xDisplay, False);
4876 void CommentCallback(w, client_data, call_data)
4878 XtPointer client_data, call_data;
4885 XtSetArg(args[j], XtNlabel, &name); j++;
4886 XtGetValues(w, args, j);
4888 if (strcmp(name, _("close")) == 0) {
4890 } else if (strcmp(name, _("edit")) == 0) {
4897 void CommentPopDown()
4902 if (!commentUp) return;
4904 XtSetArg(args[j], XtNx, &commentX); j++;
4905 XtSetArg(args[j], XtNy, &commentY); j++;
4906 XtSetArg(args[j], XtNwidth, &commentW); j++;
4907 XtSetArg(args[j], XtNheight, &commentH); j++;
4908 XtGetValues(commentShell, args, j);
4909 XtPopdown(commentShell);
4910 XSync(xDisplay, False);
4914 void FileNamePopUp(label, def, proc, openMode)
4921 Widget popup, layout, dialog, edit;
4927 fileProc = proc; /* I can't see a way not */
4928 fileOpenMode = openMode; /* to use globals here */
4929 { // [HGM] use file-selector dialog stolen from Ghostview
4931 int index; // this is not supported yet
4933 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
4934 NULL, openMode, NULL, &name))
4935 (void) (*fileProc)(f, index=0, name);
4939 void FileNamePopDown()
4941 if (!filenameUp) return;
4942 XtPopdown(fileNameShell);
4943 XtDestroyWidget(fileNameShell);
4948 void FileNameCallback(w, client_data, call_data)
4950 XtPointer client_data, call_data;
4955 XtSetArg(args[0], XtNlabel, &name);
4956 XtGetValues(w, args, 1);
4958 if (strcmp(name, _("cancel")) == 0) {
4963 FileNameAction(w, NULL, NULL, NULL);
4966 void FileNameAction(w, event, prms, nprms)
4978 name = XawDialogGetValueString(w = XtParent(w));
4980 if ((name != NULL) && (*name != NULLCHAR)) {
4982 XtPopdown(w = XtParent(XtParent(w)));
4986 p = strrchr(buf, ' ');
4993 fullname = ExpandPathName(buf);
4995 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
4998 f = fopen(fullname, fileOpenMode);
5000 DisplayError(_("Failed to open file"), errno);
5002 (void) (*fileProc)(f, index, buf);
5009 XtPopdown(w = XtParent(XtParent(w)));
5015 void PromotionPopUp()
5018 Widget dialog, layout;
5020 Dimension bw_width, pw_width;
5024 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5025 XtGetValues(boardWidget, args, j);
5028 XtSetArg(args[j], XtNresizable, True); j++;
5029 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5031 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5032 shellWidget, args, j);
5034 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5035 layoutArgs, XtNumber(layoutArgs));
5038 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5039 XtSetArg(args[j], XtNborderWidth, 0); j++;
5040 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5043 if(gameInfo.variant != VariantShogi) {
5044 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5045 (XtPointer) dialog);
5046 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5047 (XtPointer) dialog);
5048 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5049 (XtPointer) dialog);
5050 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5051 (XtPointer) dialog);
5052 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5053 gameInfo.variant == VariantGiveaway) {
5054 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5055 (XtPointer) dialog);
5057 if(gameInfo.variant == VariantCapablanca ||
5058 gameInfo.variant == VariantGothic ||
5059 gameInfo.variant == VariantCapaRandom) {
5060 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5061 (XtPointer) dialog);
5062 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5063 (XtPointer) dialog);
5065 } else // [HGM] shogi
5067 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5068 (XtPointer) dialog);
5069 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5070 (XtPointer) dialog);
5072 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5073 (XtPointer) dialog);
5075 XtRealizeWidget(promotionShell);
5076 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5079 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5080 XtGetValues(promotionShell, args, j);
5082 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5083 lineGap + squareSize/3 +
5084 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5085 0 : 6*(squareSize + lineGap)), &x, &y);
5088 XtSetArg(args[j], XtNx, x); j++;
5089 XtSetArg(args[j], XtNy, y); j++;
5090 XtSetValues(promotionShell, args, j);
5092 XtPopup(promotionShell, XtGrabNone);
5097 void PromotionPopDown()
5099 if (!promotionUp) return;
5100 XtPopdown(promotionShell);
5101 XtDestroyWidget(promotionShell);
5102 promotionUp = False;
5105 void PromotionCallback(w, client_data, call_data)
5107 XtPointer client_data, call_data;
5113 XtSetArg(args[0], XtNlabel, &name);
5114 XtGetValues(w, args, 1);
5118 if (fromX == -1) return;
5120 if (strcmp(name, _("cancel")) == 0) {
5124 } else if (strcmp(name, _("Knight")) == 0) {
5126 } else if (strcmp(name, _("Promote")) == 0) {
5128 } else if (strcmp(name, _("Defer")) == 0) {
5131 promoChar = ToLower(name[0]);
5134 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5136 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5137 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5142 void ErrorCallback(w, client_data, call_data)
5144 XtPointer client_data, call_data;
5147 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5149 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5155 if (!errorUp) return;
5157 XtPopdown(errorShell);
5158 XtDestroyWidget(errorShell);
5159 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5162 void ErrorPopUp(title, label, modal)
5163 char *title, *label;
5167 Widget dialog, layout;
5171 Dimension bw_width, pw_width;
5172 Dimension pw_height;
5176 XtSetArg(args[i], XtNresizable, True); i++;
5177 XtSetArg(args[i], XtNtitle, title); i++;
5179 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5180 shellWidget, args, i);
5182 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5183 layoutArgs, XtNumber(layoutArgs));
5186 XtSetArg(args[i], XtNlabel, label); i++;
5187 XtSetArg(args[i], XtNborderWidth, 0); i++;
5188 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5191 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5193 XtRealizeWidget(errorShell);
5194 CatchDeleteWindow(errorShell, "ErrorPopDown");
5197 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5198 XtGetValues(boardWidget, args, i);
5200 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5201 XtSetArg(args[i], XtNheight, &pw_height); i++;
5202 XtGetValues(errorShell, args, i);
5205 /* This code seems to tickle an X bug if it is executed too soon
5206 after xboard starts up. The coordinates get transformed as if
5207 the main window was positioned at (0, 0).
5209 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5210 0 - pw_height + squareSize / 3, &x, &y);
5212 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5213 RootWindowOfScreen(XtScreen(boardWidget)),
5214 (bw_width - pw_width) / 2,
5215 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5219 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5222 XtSetArg(args[i], XtNx, x); i++;
5223 XtSetArg(args[i], XtNy, y); i++;
5224 XtSetValues(errorShell, args, i);
5227 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5230 /* Disable all user input other than deleting the window */
5231 static int frozen = 0;
5235 /* Grab by a widget that doesn't accept input */
5236 XtAddGrab(messageWidget, TRUE, FALSE);
5240 /* Undo a FreezeUI */
5243 if (!frozen) return;
5244 XtRemoveGrab(messageWidget);
5248 char *ModeToWidgetName(mode)
5252 case BeginningOfGame:
5253 if (appData.icsActive)
5254 return "menuMode.ICS Client";
5255 else if (appData.noChessProgram ||
5256 *appData.cmailGameName != NULLCHAR)
5257 return "menuMode.Edit Game";
5259 return "menuMode.Machine Black";
5260 case MachinePlaysBlack:
5261 return "menuMode.Machine Black";
5262 case MachinePlaysWhite:
5263 return "menuMode.Machine White";
5265 return "menuMode.Analysis Mode";
5267 return "menuMode.Analyze File";
5268 case TwoMachinesPlay:
5269 return "menuMode.Two Machines";
5271 return "menuMode.Edit Game";
5272 case PlayFromGameFile:
5273 return "menuFile.Load Game";
5275 return "menuMode.Edit Position";
5277 return "menuMode.Training";
5278 case IcsPlayingWhite:
5279 case IcsPlayingBlack:
5283 return "menuMode.ICS Client";
5290 void ModeHighlight()
5293 static int oldPausing = FALSE;
5294 static GameMode oldmode = (GameMode) -1;
5297 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5299 if (pausing != oldPausing) {
5300 oldPausing = pausing;
5302 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5304 XtSetArg(args[0], XtNleftBitmap, None);
5306 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5309 if (appData.showButtonBar) {
5310 /* Always toggle, don't set. Previous code messes up when
5311 invoked while the button is pressed, as releasing it
5312 toggles the state again. */
5315 XtSetArg(args[0], XtNbackground, &oldbg);
5316 XtSetArg(args[1], XtNforeground, &oldfg);
5317 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5319 XtSetArg(args[0], XtNbackground, oldfg);
5320 XtSetArg(args[1], XtNforeground, oldbg);
5322 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5326 wname = ModeToWidgetName(oldmode);
5327 if (wname != NULL) {
5328 XtSetArg(args[0], XtNleftBitmap, None);
5329 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5331 wname = ModeToWidgetName(gameMode);
5332 if (wname != NULL) {
5333 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5334 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5338 /* Maybe all the enables should be handled here, not just this one */
5339 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5340 gameMode == Training || gameMode == PlayFromGameFile);
5345 * Button/menu procedures
5347 void ResetProc(w, event, prms, nprms)
5356 int LoadGamePopUp(f, gameNumber, title)
5361 cmailMsgLoaded = FALSE;
5362 if (gameNumber == 0) {
5363 int error = GameListBuild(f);
5365 DisplayError(_("Cannot build game list"), error);
5366 } else if (!ListEmpty(&gameList) &&
5367 ((ListGame *) gameList.tailPred)->number > 1) {
5368 GameListPopUp(f, title);
5374 return LoadGame(f, gameNumber, title, FALSE);
5377 void LoadGameProc(w, event, prms, nprms)
5383 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5386 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5389 void LoadNextGameProc(w, event, prms, nprms)
5398 void LoadPrevGameProc(w, event, prms, nprms)
5407 void ReloadGameProc(w, event, prms, nprms)
5416 void LoadNextPositionProc(w, event, prms, nprms)
5425 void LoadPrevPositionProc(w, event, prms, nprms)
5434 void ReloadPositionProc(w, event, prms, nprms)
5443 void LoadPositionProc(w, event, prms, nprms)
5449 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5452 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5455 void SaveGameProc(w, event, prms, nprms)
5461 FileNamePopUp(_("Save game file name?"),
5462 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5466 void SavePositionProc(w, event, prms, nprms)
5472 FileNamePopUp(_("Save position file name?"),
5473 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5477 void ReloadCmailMsgProc(w, event, prms, nprms)
5483 ReloadCmailMsgEvent(FALSE);
5486 void MailMoveProc(w, event, prms, nprms)
5495 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5496 char *selected_fen_position=NULL;
5499 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5500 Atom *type_return, XtPointer *value_return,
5501 unsigned long *length_return, int *format_return)
5503 char *selection_tmp;
5505 if (!selected_fen_position) return False; /* should never happen */
5506 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5507 /* note: since no XtSelectionDoneProc was registered, Xt will
5508 * automatically call XtFree on the value returned. So have to
5509 * make a copy of it allocated with XtMalloc */
5510 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5511 strcpy(selection_tmp, selected_fen_position);
5513 *value_return=selection_tmp;
5514 *length_return=strlen(selection_tmp);
5515 *type_return=*target;
5516 *format_return = 8; /* bits per byte */
5518 } else if (*target == XA_TARGETS(xDisplay)) {
5519 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5520 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5521 targets_tmp[1] = XA_STRING;
5522 *value_return = targets_tmp;
5523 *type_return = XA_ATOM;
5525 *format_return = 8 * sizeof(Atom);
5526 if (*format_return > 32) {
5527 *length_return *= *format_return / 32;
5528 *format_return = 32;
5536 /* note: when called from menu all parameters are NULL, so no clue what the
5537 * Widget which was clicked on was, or what the click event was
5539 void CopyPositionProc(w, event, prms, nprms)
5546 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5547 * have a notion of a position that is selected but not copied.
5548 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5550 if(gameMode == EditPosition) EditPositionDone(TRUE);
5551 if (selected_fen_position) free(selected_fen_position);
5552 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5553 if (!selected_fen_position) return;
5554 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5556 SendPositionSelection,
5557 NULL/* lose_ownership_proc */ ,
5558 NULL/* transfer_done_proc */);
5559 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5561 SendPositionSelection,
5562 NULL/* lose_ownership_proc */ ,
5563 NULL/* transfer_done_proc */);
5566 /* function called when the data to Paste is ready */
5568 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5569 Atom *type, XtPointer value, unsigned long *len, int *format)
5572 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5573 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5574 EditPositionPasteFEN(fenstr);
5578 /* called when Paste Position button is pressed,
5579 * all parameters will be NULL */
5580 void PastePositionProc(w, event, prms, nprms)
5586 XtGetSelectionValue(menuBarWidget,
5587 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5588 /* (XtSelectionCallbackProc) */ PastePositionCB,
5589 NULL, /* client_data passed to PastePositionCB */
5591 /* better to use the time field from the event that triggered the
5592 * call to this function, but that isn't trivial to get
5600 SendGameSelection(Widget w, Atom *selection, Atom *target,
5601 Atom *type_return, XtPointer *value_return,
5602 unsigned long *length_return, int *format_return)
5604 char *selection_tmp;
5606 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5607 FILE* f = fopen(gameCopyFilename, "r");
5610 if (f == NULL) return False;
5614 selection_tmp = XtMalloc(len + 1);
5615 count = fread(selection_tmp, 1, len, f);
5617 XtFree(selection_tmp);
5620 selection_tmp[len] = NULLCHAR;
5621 *value_return = selection_tmp;
5622 *length_return = len;
5623 *type_return = *target;
5624 *format_return = 8; /* bits per byte */
5626 } else if (*target == XA_TARGETS(xDisplay)) {
5627 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5628 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5629 targets_tmp[1] = XA_STRING;
5630 *value_return = targets_tmp;
5631 *type_return = XA_ATOM;
5633 *format_return = 8 * sizeof(Atom);
5634 if (*format_return > 32) {
5635 *length_return *= *format_return / 32;
5636 *format_return = 32;
5644 /* note: when called from menu all parameters are NULL, so no clue what the
5645 * Widget which was clicked on was, or what the click event was
5647 void CopyGameProc(w, event, prms, nprms)
5655 ret = SaveGameToFile(gameCopyFilename, FALSE);
5659 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5660 * have a notion of a game that is selected but not copied.
5661 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5663 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5666 NULL/* lose_ownership_proc */ ,
5667 NULL/* transfer_done_proc */);
5668 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5671 NULL/* lose_ownership_proc */ ,
5672 NULL/* transfer_done_proc */);
5675 /* function called when the data to Paste is ready */
5677 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5678 Atom *type, XtPointer value, unsigned long *len, int *format)
5681 if (value == NULL || *len == 0) {
5682 return; /* nothing had been selected to copy */
5684 f = fopen(gamePasteFilename, "w");
5686 DisplayError(_("Can't open temp file"), errno);
5689 fwrite(value, 1, *len, f);
5692 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5695 /* called when Paste Game button is pressed,
5696 * all parameters will be NULL */
5697 void PasteGameProc(w, event, prms, nprms)
5703 XtGetSelectionValue(menuBarWidget,
5704 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5705 /* (XtSelectionCallbackProc) */ PasteGameCB,
5706 NULL, /* client_data passed to PasteGameCB */
5708 /* better to use the time field from the event that triggered the
5709 * call to this function, but that isn't trivial to get
5719 SaveGameProc(NULL, NULL, NULL, NULL);
5723 void QuitProc(w, event, prms, nprms)
5732 void PauseProc(w, event, prms, nprms)
5742 void MachineBlackProc(w, event, prms, nprms)
5748 MachineBlackEvent();
5751 void MachineWhiteProc(w, event, prms, nprms)
5757 MachineWhiteEvent();
5760 void AnalyzeModeProc(w, event, prms, nprms)
5768 if (!first.analysisSupport) {
5769 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5770 DisplayError(buf, 0);
5773 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5774 if (appData.icsActive) {
5775 if (gameMode != IcsObserving) {
5776 sprintf(buf,_("You are not observing a game"));
5777 DisplayError(buf, 0);
5779 if (appData.icsEngineAnalyze) {
5780 if (appData.debugMode)
5781 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5787 /* if enable, use want disable icsEngineAnalyze */
5788 if (appData.icsEngineAnalyze) {
5793 appData.icsEngineAnalyze = TRUE;
5794 if (appData.debugMode)
5795 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5797 if (!appData.showThinking)
5798 ShowThinkingProc(w,event,prms,nprms);
5803 void AnalyzeFileProc(w, event, prms, nprms)
5809 if (!first.analysisSupport) {
5811 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5812 DisplayError(buf, 0);
5817 if (!appData.showThinking)
5818 ShowThinkingProc(w,event,prms,nprms);
5821 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5822 AnalysisPeriodicEvent(1);
5825 void TwoMachinesProc(w, event, prms, nprms)
5834 void IcsClientProc(w, event, prms, nprms)
5843 void EditGameProc(w, event, prms, nprms)
5852 void EditPositionProc(w, event, prms, nprms)
5858 EditPositionEvent();
5861 void TrainingProc(w, event, prms, nprms)
5870 void EditCommentProc(w, event, prms, nprms)
5877 EditCommentPopDown();
5883 void IcsInputBoxProc(w, event, prms, nprms)
5889 if (ICSInputBoxUp) {
5890 ICSInputBoxPopDown();
5896 void AcceptProc(w, event, prms, nprms)
5905 void DeclineProc(w, event, prms, nprms)
5914 void RematchProc(w, event, prms, nprms)
5923 void CallFlagProc(w, event, prms, nprms)
5932 void DrawProc(w, event, prms, nprms)
5941 void AbortProc(w, event, prms, nprms)
5950 void AdjournProc(w, event, prms, nprms)
5959 void ResignProc(w, event, prms, nprms)
5968 void AdjuWhiteProc(w, event, prms, nprms)
5974 UserAdjudicationEvent(+1);
5977 void AdjuBlackProc(w, event, prms, nprms)
5983 UserAdjudicationEvent(-1);
5986 void AdjuDrawProc(w, event, prms, nprms)
5992 UserAdjudicationEvent(0);
5995 void EnterKeyProc(w, event, prms, nprms)
6001 if (ICSInputBoxUp == True)
6005 void StopObservingProc(w, event, prms, nprms)
6011 StopObservingEvent();
6014 void StopExaminingProc(w, event, prms, nprms)
6020 StopExaminingEvent();
6024 void ForwardProc(w, event, prms, nprms)
6034 void BackwardProc(w, event, prms, nprms)
6043 void ToStartProc(w, event, prms, nprms)
6052 void ToEndProc(w, event, prms, nprms)
6061 void RevertProc(w, event, prms, nprms)
6070 void TruncateGameProc(w, event, prms, nprms)
6076 TruncateGameEvent();
6078 void RetractMoveProc(w, event, prms, nprms)
6087 void MoveNowProc(w, event, prms, nprms)
6097 void AlwaysQueenProc(w, event, prms, nprms)
6105 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6107 if (appData.alwaysPromoteToQueen) {
6108 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6110 XtSetArg(args[0], XtNleftBitmap, None);
6112 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6116 void AnimateDraggingProc(w, event, prms, nprms)
6124 appData.animateDragging = !appData.animateDragging;
6126 if (appData.animateDragging) {
6127 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6130 XtSetArg(args[0], XtNleftBitmap, None);
6132 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6136 void AnimateMovingProc(w, event, prms, nprms)
6144 appData.animate = !appData.animate;
6146 if (appData.animate) {
6147 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6150 XtSetArg(args[0], XtNleftBitmap, None);
6152 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6156 void AutocommProc(w, event, prms, nprms)
6164 appData.autoComment = !appData.autoComment;
6166 if (appData.autoComment) {
6167 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6169 XtSetArg(args[0], XtNleftBitmap, None);
6171 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6176 void AutoflagProc(w, event, prms, nprms)
6184 appData.autoCallFlag = !appData.autoCallFlag;
6186 if (appData.autoCallFlag) {
6187 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6189 XtSetArg(args[0], XtNleftBitmap, None);
6191 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6195 void AutoflipProc(w, event, prms, nprms)
6203 appData.autoFlipView = !appData.autoFlipView;
6205 if (appData.autoFlipView) {
6206 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6208 XtSetArg(args[0], XtNleftBitmap, None);
6210 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6214 void AutobsProc(w, event, prms, nprms)
6222 appData.autoObserve = !appData.autoObserve;
6224 if (appData.autoObserve) {
6225 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6227 XtSetArg(args[0], XtNleftBitmap, None);
6229 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6233 void AutoraiseProc(w, event, prms, nprms)
6241 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6243 if (appData.autoRaiseBoard) {
6244 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6246 XtSetArg(args[0], XtNleftBitmap, None);
6248 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6252 void AutosaveProc(w, event, prms, nprms)
6260 appData.autoSaveGames = !appData.autoSaveGames;
6262 if (appData.autoSaveGames) {
6263 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6265 XtSetArg(args[0], XtNleftBitmap, None);
6267 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6271 void BlindfoldProc(w, event, prms, nprms)
6279 appData.blindfold = !appData.blindfold;
6281 if (appData.blindfold) {
6282 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6284 XtSetArg(args[0], XtNleftBitmap, None);
6286 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6289 DrawPosition(True, NULL);
6292 void TestLegalityProc(w, event, prms, nprms)
6300 appData.testLegality = !appData.testLegality;
6302 if (appData.testLegality) {
6303 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6305 XtSetArg(args[0], XtNleftBitmap, None);
6307 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6312 void FlashMovesProc(w, event, prms, nprms)
6320 if (appData.flashCount == 0) {
6321 appData.flashCount = 3;
6323 appData.flashCount = -appData.flashCount;
6326 if (appData.flashCount > 0) {
6327 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6329 XtSetArg(args[0], XtNleftBitmap, None);
6331 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6335 void FlipViewProc(w, event, prms, nprms)
6341 flipView = !flipView;
6342 DrawPosition(True, NULL);
6345 void GetMoveListProc(w, event, prms, nprms)
6353 appData.getMoveList = !appData.getMoveList;
6355 if (appData.getMoveList) {
6356 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6359 XtSetArg(args[0], XtNleftBitmap, None);
6361 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6366 void HighlightDraggingProc(w, event, prms, nprms)
6374 appData.highlightDragging = !appData.highlightDragging;
6376 if (appData.highlightDragging) {
6377 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6379 XtSetArg(args[0], XtNleftBitmap, None);
6381 XtSetValues(XtNameToWidget(menuBarWidget,
6382 "menuOptions.Highlight Dragging"), args, 1);
6386 void HighlightLastMoveProc(w, event, prms, nprms)
6394 appData.highlightLastMove = !appData.highlightLastMove;
6396 if (appData.highlightLastMove) {
6397 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6399 XtSetArg(args[0], XtNleftBitmap, None);
6401 XtSetValues(XtNameToWidget(menuBarWidget,
6402 "menuOptions.Highlight Last Move"), args, 1);
6405 void IcsAlarmProc(w, event, prms, nprms)
6413 appData.icsAlarm = !appData.icsAlarm;
6415 if (appData.icsAlarm) {
6416 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6418 XtSetArg(args[0], XtNleftBitmap, None);
6420 XtSetValues(XtNameToWidget(menuBarWidget,
6421 "menuOptions.ICS Alarm"), args, 1);
6424 void MoveSoundProc(w, event, prms, nprms)
6432 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6434 if (appData.ringBellAfterMoves) {
6435 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6437 XtSetArg(args[0], XtNleftBitmap, None);
6439 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6444 void OldSaveStyleProc(w, event, prms, nprms)
6452 appData.oldSaveStyle = !appData.oldSaveStyle;
6454 if (appData.oldSaveStyle) {
6455 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6457 XtSetArg(args[0], XtNleftBitmap, None);
6459 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6463 void PeriodicUpdatesProc(w, event, prms, nprms)
6471 PeriodicUpdatesEvent(!appData.periodicUpdates);
6473 if (appData.periodicUpdates) {
6474 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6476 XtSetArg(args[0], XtNleftBitmap, None);
6478 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6482 void PonderNextMoveProc(w, event, prms, nprms)
6490 PonderNextMoveEvent(!appData.ponderNextMove);
6492 if (appData.ponderNextMove) {
6493 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6495 XtSetArg(args[0], XtNleftBitmap, None);
6497 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6501 void PopupExitMessageProc(w, event, prms, nprms)
6509 appData.popupExitMessage = !appData.popupExitMessage;
6511 if (appData.popupExitMessage) {
6512 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6514 XtSetArg(args[0], XtNleftBitmap, None);
6516 XtSetValues(XtNameToWidget(menuBarWidget,
6517 "menuOptions.Popup Exit Message"), args, 1);
6520 void PopupMoveErrorsProc(w, event, prms, nprms)
6528 appData.popupMoveErrors = !appData.popupMoveErrors;
6530 if (appData.popupMoveErrors) {
6531 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6533 XtSetArg(args[0], XtNleftBitmap, None);
6535 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6539 void PremoveProc(w, event, prms, nprms)
6547 appData.premove = !appData.premove;
6549 if (appData.premove) {
6550 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6552 XtSetArg(args[0], XtNleftBitmap, None);
6554 XtSetValues(XtNameToWidget(menuBarWidget,
6555 "menuOptions.Premove"), args, 1);
6558 void QuietPlayProc(w, event, prms, nprms)
6566 appData.quietPlay = !appData.quietPlay;
6568 if (appData.quietPlay) {
6569 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6571 XtSetArg(args[0], XtNleftBitmap, None);
6573 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6577 void ShowCoordsProc(w, event, prms, nprms)
6585 appData.showCoords = !appData.showCoords;
6587 if (appData.showCoords) {
6588 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6590 XtSetArg(args[0], XtNleftBitmap, None);
6592 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6595 DrawPosition(True, NULL);
6598 void ShowThinkingProc(w, event, prms, nprms)
6604 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6605 ShowThinkingEvent();
6608 void HideThinkingProc(w, event, prms, nprms)
6616 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6617 ShowThinkingEvent();
6619 if (appData.hideThinkingFromHuman) {
6620 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6622 XtSetArg(args[0], XtNleftBitmap, None);
6624 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6628 void SaveOnExitProc(w, event, prms, nprms)
6636 saveSettingsOnExit = !saveSettingsOnExit;
6638 if (saveSettingsOnExit) {
6639 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6641 XtSetArg(args[0], XtNleftBitmap, None);
6643 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6647 void SaveSettingsProc(w, event, prms, nprms)
6653 SaveSettings(settingsFileName);
6656 void InfoProc(w, event, prms, nprms)
6663 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6668 void ManProc(w, event, prms, nprms)
6676 if (nprms && *nprms > 0)
6680 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6684 void HintProc(w, event, prms, nprms)
6693 void BookProc(w, event, prms, nprms)
6702 void AboutProc(w, event, prms, nprms)
6710 char *zippy = " (with Zippy code)";
6714 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6715 programVersion, zippy,
6716 "Copyright 1991 Digital Equipment Corporation",
6717 "Enhancements Copyright 1992-2009 Free Software Foundation",
6718 "Enhancements Copyright 2005 Alessandro Scotti",
6719 PACKAGE, " is free software and carries NO WARRANTY;",
6720 "see the file COPYING for more information.");
6721 ErrorPopUp(_("About XBoard"), buf, FALSE);
6724 void DebugProc(w, event, prms, nprms)
6730 appData.debugMode = !appData.debugMode;
6733 void AboutGameProc(w, event, prms, nprms)
6742 void NothingProc(w, event, prms, nprms)
6751 void Iconify(w, event, prms, nprms)
6760 XtSetArg(args[0], XtNiconic, True);
6761 XtSetValues(shellWidget, args, 1);
6764 void DisplayMessage(message, extMessage)
6765 char *message, *extMessage;
6767 /* display a message in the message widget */
6776 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6781 message = extMessage;
6785 /* need to test if messageWidget already exists, since this function
6786 can also be called during the startup, if for example a Xresource
6787 is not set up correctly */
6790 XtSetArg(arg, XtNlabel, message);
6791 XtSetValues(messageWidget, &arg, 1);
6797 void DisplayTitle(text)
6802 char title[MSG_SIZ];
6805 if (text == NULL) text = "";
6807 if (appData.titleInWindow) {
6809 XtSetArg(args[i], XtNlabel, text); i++;
6810 XtSetValues(titleWidget, args, i);
6813 if (*text != NULLCHAR) {
6815 strcpy(title, text);
6816 } else if (appData.icsActive) {
6817 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6818 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6819 } else if (appData.cmailGameName[0] != NULLCHAR) {
6820 snprintf(icon, sizeof(icon), "%s", "CMail");
6821 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6823 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6824 } else if (gameInfo.variant == VariantGothic) {
6825 strcpy(icon, programName);
6826 strcpy(title, GOTHIC);
6829 } else if (gameInfo.variant == VariantFalcon) {
6830 strcpy(icon, programName);
6831 strcpy(title, FALCON);
6833 } else if (appData.noChessProgram) {
6834 strcpy(icon, programName);
6835 strcpy(title, programName);
6837 strcpy(icon, first.tidy);
6838 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6841 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6842 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6843 XtSetValues(shellWidget, args, i);
6847 void DisplayError(message, error)
6854 if (appData.debugMode || appData.matchMode) {
6855 fprintf(stderr, "%s: %s\n", programName, message);
6858 if (appData.debugMode || appData.matchMode) {
6859 fprintf(stderr, "%s: %s: %s\n",
6860 programName, message, strerror(error));
6862 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6865 ErrorPopUp(_("Error"), message, FALSE);
6869 void DisplayMoveError(message)
6874 DrawPosition(FALSE, NULL);
6875 if (appData.debugMode || appData.matchMode) {
6876 fprintf(stderr, "%s: %s\n", programName, message);
6878 if (appData.popupMoveErrors) {
6879 ErrorPopUp(_("Error"), message, FALSE);
6881 DisplayMessage(message, "");
6886 void DisplayFatalError(message, error, status)
6892 errorExitStatus = status;
6894 fprintf(stderr, "%s: %s\n", programName, message);
6896 fprintf(stderr, "%s: %s: %s\n",
6897 programName, message, strerror(error));
6898 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6901 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6902 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6908 void DisplayInformation(message)
6912 ErrorPopUp(_("Information"), message, TRUE);
6915 void DisplayNote(message)
6919 ErrorPopUp(_("Note"), message, FALSE);
6923 NullXErrorCheck(dpy, error_event)
6925 XErrorEvent *error_event;
6930 void DisplayIcsInteractionTitle(message)
6933 if (oldICSInteractionTitle == NULL) {
6934 /* Magic to find the old window title, adapted from vim */
6935 char *wina = getenv("WINDOWID");
6937 Window win = (Window) atoi(wina);
6938 Window root, parent, *children;
6939 unsigned int nchildren;
6940 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6942 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6943 if (!XQueryTree(xDisplay, win, &root, &parent,
6944 &children, &nchildren)) break;
6945 if (children) XFree((void *)children);
6946 if (parent == root || parent == 0) break;
6949 XSetErrorHandler(oldHandler);
6951 if (oldICSInteractionTitle == NULL) {
6952 oldICSInteractionTitle = "xterm";
6955 printf("\033]0;%s\007", message);
6959 char pendingReplyPrefix[MSG_SIZ];
6960 ProcRef pendingReplyPR;
6962 void AskQuestionProc(w, event, prms, nprms)
6969 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6973 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6976 void AskQuestionPopDown()
6978 if (!askQuestionUp) return;
6979 XtPopdown(askQuestionShell);
6980 XtDestroyWidget(askQuestionShell);
6981 askQuestionUp = False;
6984 void AskQuestionReplyAction(w, event, prms, nprms)
6994 reply = XawDialogGetValueString(w = XtParent(w));
6995 strcpy(buf, pendingReplyPrefix);
6996 if (*buf) strcat(buf, " ");
6999 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7000 AskQuestionPopDown();
7002 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7005 void AskQuestionCallback(w, client_data, call_data)
7007 XtPointer client_data, call_data;
7012 XtSetArg(args[0], XtNlabel, &name);
7013 XtGetValues(w, args, 1);
7015 if (strcmp(name, _("cancel")) == 0) {
7016 AskQuestionPopDown();
7018 AskQuestionReplyAction(w, NULL, NULL, NULL);
7022 void AskQuestion(title, question, replyPrefix, pr)
7023 char *title, *question, *replyPrefix;
7027 Widget popup, layout, dialog, edit;
7033 strcpy(pendingReplyPrefix, replyPrefix);
7034 pendingReplyPR = pr;
7037 XtSetArg(args[i], XtNresizable, True); i++;
7038 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7039 askQuestionShell = popup =
7040 XtCreatePopupShell(title, transientShellWidgetClass,
7041 shellWidget, args, i);
7044 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7045 layoutArgs, XtNumber(layoutArgs));
7048 XtSetArg(args[i], XtNlabel, question); i++;
7049 XtSetArg(args[i], XtNvalue, ""); i++;
7050 XtSetArg(args[i], XtNborderWidth, 0); i++;
7051 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7054 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7055 (XtPointer) dialog);
7056 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7057 (XtPointer) dialog);
7059 XtRealizeWidget(popup);
7060 CatchDeleteWindow(popup, "AskQuestionPopDown");
7062 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7063 &x, &y, &win_x, &win_y, &mask);
7065 XtSetArg(args[0], XtNx, x - 10);
7066 XtSetArg(args[1], XtNy, y - 30);
7067 XtSetValues(popup, args, 2);
7069 XtPopup(popup, XtGrabExclusive);
7070 askQuestionUp = True;
7072 edit = XtNameToWidget(dialog, "*value");
7073 XtSetKeyboardFocus(popup, edit);
7081 if (*name == NULLCHAR) {
7083 } else if (strcmp(name, "$") == 0) {
7084 putc(BELLCHAR, stderr);
7087 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7095 PlaySound(appData.soundMove);
7101 PlaySound(appData.soundIcsWin);
7107 PlaySound(appData.soundIcsLoss);
7113 PlaySound(appData.soundIcsDraw);
7117 PlayIcsUnfinishedSound()
7119 PlaySound(appData.soundIcsUnfinished);
7125 PlaySound(appData.soundIcsAlarm);
7131 system("stty echo");
7137 system("stty -echo");
7141 Colorize(cc, continuation)
7146 int count, outCount, error;
7148 if (textColors[(int)cc].bg > 0) {
7149 if (textColors[(int)cc].fg > 0) {
7150 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7151 textColors[(int)cc].fg, textColors[(int)cc].bg);
7153 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7154 textColors[(int)cc].bg);
7157 if (textColors[(int)cc].fg > 0) {
7158 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7159 textColors[(int)cc].fg);
7161 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7164 count = strlen(buf);
7165 outCount = OutputToProcess(NoProc, buf, count, &error);
7166 if (outCount < count) {
7167 DisplayFatalError(_("Error writing to display"), error, 1);
7170 if (continuation) return;
7173 PlaySound(appData.soundShout);
7176 PlaySound(appData.soundSShout);
7179 PlaySound(appData.soundChannel1);
7182 PlaySound(appData.soundChannel);
7185 PlaySound(appData.soundKibitz);
7188 PlaySound(appData.soundTell);
7190 case ColorChallenge:
7191 PlaySound(appData.soundChallenge);
7194 PlaySound(appData.soundRequest);
7197 PlaySound(appData.soundSeek);
7208 return getpwuid(getuid())->pw_name;
7211 static char *ExpandPathName(path)
7214 static char static_buf[2000];
7215 char *d, *s, buf[2000];
7221 while (*s && isspace(*s))
7230 if (*(s+1) == '/') {
7231 strcpy(d, getpwuid(getuid())->pw_dir);
7236 *strchr(buf, '/') = 0;
7237 pwd = getpwnam(buf);
7240 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7244 strcpy(d, pwd->pw_dir);
7245 strcat(d, strchr(s+1, '/'));
7256 static char host_name[MSG_SIZ];
7258 #if HAVE_GETHOSTNAME
7259 gethostname(host_name, MSG_SIZ);
7261 #else /* not HAVE_GETHOSTNAME */
7262 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7263 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7265 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7267 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7268 #endif /* not HAVE_GETHOSTNAME */
7271 XtIntervalId delayedEventTimerXID = 0;
7272 DelayedEventCallback delayedEventCallback = 0;
7277 delayedEventTimerXID = 0;
7278 delayedEventCallback();
7282 ScheduleDelayedEvent(cb, millisec)
7283 DelayedEventCallback cb; long millisec;
7285 if(delayedEventTimerXID && delayedEventCallback == cb)
7286 // [HGM] alive: replace, rather than add or flush identical event
7287 XtRemoveTimeOut(delayedEventTimerXID);
7288 delayedEventCallback = cb;
7289 delayedEventTimerXID =
7290 XtAppAddTimeOut(appContext, millisec,
7291 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7294 DelayedEventCallback
7297 if (delayedEventTimerXID) {
7298 return delayedEventCallback;
7305 CancelDelayedEvent()
7307 if (delayedEventTimerXID) {
7308 XtRemoveTimeOut(delayedEventTimerXID);
7309 delayedEventTimerXID = 0;
7313 XtIntervalId loadGameTimerXID = 0;
7315 int LoadGameTimerRunning()
7317 return loadGameTimerXID != 0;
7320 int StopLoadGameTimer()
7322 if (loadGameTimerXID != 0) {
7323 XtRemoveTimeOut(loadGameTimerXID);
7324 loadGameTimerXID = 0;
7332 LoadGameTimerCallback(arg, id)
7336 loadGameTimerXID = 0;
7341 StartLoadGameTimer(millisec)
7345 XtAppAddTimeOut(appContext, millisec,
7346 (XtTimerCallbackProc) LoadGameTimerCallback,
7350 XtIntervalId analysisClockXID = 0;
7353 AnalysisClockCallback(arg, id)
7357 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7358 || appData.icsEngineAnalyze) { // [DM]
7359 AnalysisPeriodicEvent(0);
7360 StartAnalysisClock();
7365 StartAnalysisClock()
7368 XtAppAddTimeOut(appContext, 2000,
7369 (XtTimerCallbackProc) AnalysisClockCallback,
7373 XtIntervalId clockTimerXID = 0;
7375 int ClockTimerRunning()
7377 return clockTimerXID != 0;
7380 int StopClockTimer()
7382 if (clockTimerXID != 0) {
7383 XtRemoveTimeOut(clockTimerXID);
7392 ClockTimerCallback(arg, id)
7401 StartClockTimer(millisec)
7405 XtAppAddTimeOut(appContext, millisec,
7406 (XtTimerCallbackProc) ClockTimerCallback,
7411 DisplayTimerLabel(w, color, timer, highlight)
7420 /* check for low time warning */
7421 Pixel foregroundOrWarningColor = timerForegroundPixel;
7424 appData.lowTimeWarning &&
7425 (timer / 1000) < appData.icsAlarmTime)
7426 foregroundOrWarningColor = lowTimeWarningColor;
7428 if (appData.clockMode) {
7429 sprintf(buf, "%s: %s", color, TimeString(timer));
7430 XtSetArg(args[0], XtNlabel, buf);
7432 sprintf(buf, "%s ", color);
7433 XtSetArg(args[0], XtNlabel, buf);
7438 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7439 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7441 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7442 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7445 XtSetValues(w, args, 3);
7449 DisplayWhiteClock(timeRemaining, highlight)
7455 if(appData.noGUI) return;
7456 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7457 if (highlight && iconPixmap == bIconPixmap) {
7458 iconPixmap = wIconPixmap;
7459 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7460 XtSetValues(shellWidget, args, 1);
7465 DisplayBlackClock(timeRemaining, highlight)
7471 if(appData.noGUI) return;
7472 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7473 if (highlight && iconPixmap == wIconPixmap) {
7474 iconPixmap = bIconPixmap;
7475 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7476 XtSetValues(shellWidget, args, 1);
7494 int StartChildProcess(cmdLine, dir, pr)
7501 int to_prog[2], from_prog[2];
7505 if (appData.debugMode) {
7506 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7509 /* We do NOT feed the cmdLine to the shell; we just
7510 parse it into blank-separated arguments in the
7511 most simple-minded way possible.
7514 strcpy(buf, cmdLine);
7517 while(*p == ' ') p++;
7519 if(*p == '"' || *p == '\'')
7520 p = strchr(++argv[i-1], *p);
7521 else p = strchr(p, ' ');
7522 if (p == NULL) break;
7527 SetUpChildIO(to_prog, from_prog);
7529 if ((pid = fork()) == 0) {
7531 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7532 close(to_prog[1]); // first close the unused pipe ends
7533 close(from_prog[0]);
7534 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7535 dup2(from_prog[1], 1);
7536 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7537 close(from_prog[1]); // and closing again loses one of the pipes!
7538 if(fileno(stderr) >= 2) // better safe than sorry...
7539 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7541 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7546 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7548 execvp(argv[0], argv);
7550 /* If we get here, exec failed */
7555 /* Parent process */
7557 close(from_prog[1]);
7559 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7562 cp->fdFrom = from_prog[0];
7563 cp->fdTo = to_prog[1];
7568 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7569 static RETSIGTYPE AlarmCallBack(int n)
7575 DestroyChildProcess(pr, signalType)
7579 ChildProc *cp = (ChildProc *) pr;
7581 if (cp->kind != CPReal) return;
7583 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7584 signal(SIGALRM, AlarmCallBack);
7586 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7587 kill(cp->pid, SIGKILL); // kill it forcefully
7588 wait((int *) 0); // and wait again
7592 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7594 /* Process is exiting either because of the kill or because of
7595 a quit command sent by the backend; either way, wait for it to die.
7604 InterruptChildProcess(pr)
7607 ChildProc *cp = (ChildProc *) pr;
7609 if (cp->kind != CPReal) return;
7610 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7613 int OpenTelnet(host, port, pr)
7618 char cmdLine[MSG_SIZ];
7620 if (port[0] == NULLCHAR) {
7621 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7623 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7625 return StartChildProcess(cmdLine, "", pr);
7628 int OpenTCP(host, port, pr)
7634 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7635 #else /* !OMIT_SOCKETS */
7637 struct sockaddr_in sa;
7639 unsigned short uport;
7642 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7646 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7647 sa.sin_family = AF_INET;
7648 sa.sin_addr.s_addr = INADDR_ANY;
7649 uport = (unsigned short) 0;
7650 sa.sin_port = htons(uport);
7651 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7655 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7656 if (!(hp = gethostbyname(host))) {
7658 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7659 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7660 hp->h_addrtype = AF_INET;
7662 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7663 hp->h_addr_list[0] = (char *) malloc(4);
7664 hp->h_addr_list[0][0] = b0;
7665 hp->h_addr_list[0][1] = b1;
7666 hp->h_addr_list[0][2] = b2;
7667 hp->h_addr_list[0][3] = b3;
7672 sa.sin_family = hp->h_addrtype;
7673 uport = (unsigned short) atoi(port);
7674 sa.sin_port = htons(uport);
7675 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7677 if (connect(s, (struct sockaddr *) &sa,
7678 sizeof(struct sockaddr_in)) < 0) {
7682 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7689 #endif /* !OMIT_SOCKETS */
7694 int OpenCommPort(name, pr)
7701 fd = open(name, 2, 0);
7702 if (fd < 0) return errno;
7704 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7714 int OpenLoopback(pr)
7720 SetUpChildIO(to, from);
7722 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7725 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7732 int OpenRcmd(host, user, cmd, pr)
7733 char *host, *user, *cmd;
7736 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7740 #define INPUT_SOURCE_BUF_SIZE 8192
7749 char buf[INPUT_SOURCE_BUF_SIZE];
7754 DoInputCallback(closure, source, xid)
7759 InputSource *is = (InputSource *) closure;
7764 if (is->lineByLine) {
7765 count = read(is->fd, is->unused,
7766 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7768 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7771 is->unused += count;
7773 while (p < is->unused) {
7774 q = memchr(p, '\n', is->unused - p);
7775 if (q == NULL) break;
7777 (is->func)(is, is->closure, p, q - p, 0);
7781 while (p < is->unused) {
7786 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7791 (is->func)(is, is->closure, is->buf, count, error);
7795 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7802 ChildProc *cp = (ChildProc *) pr;
7804 is = (InputSource *) calloc(1, sizeof(InputSource));
7805 is->lineByLine = lineByLine;
7809 is->fd = fileno(stdin);
7811 is->kind = cp->kind;
7812 is->fd = cp->fdFrom;
7815 is->unused = is->buf;
7818 is->xid = XtAppAddInput(appContext, is->fd,
7819 (XtPointer) (XtInputReadMask),
7820 (XtInputCallbackProc) DoInputCallback,
7822 is->closure = closure;
7823 return (InputSourceRef) is;
7827 RemoveInputSource(isr)
7830 InputSource *is = (InputSource *) isr;
7832 if (is->xid == 0) return;
7833 XtRemoveInput(is->xid);
7837 int OutputToProcess(pr, message, count, outError)
7843 static int line = 0;
7844 ChildProc *cp = (ChildProc *) pr;
7849 if (appData.noJoin || !appData.useInternalWrap)
7850 outCount = fwrite(message, 1, count, stdout);
7853 int width = get_term_width();
7854 int len = wrap(NULL, message, count, width, &line);
7855 char *msg = malloc(len);
7859 outCount = fwrite(message, 1, count, stdout);
7862 dbgchk = wrap(msg, message, count, width, &line);
7863 if (dbgchk != len && appData.debugMode)
7864 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7865 outCount = fwrite(msg, 1, dbgchk, stdout);
7871 outCount = write(cp->fdTo, message, count);
7881 /* Output message to process, with "ms" milliseconds of delay
7882 between each character. This is needed when sending the logon
7883 script to ICC, which for some reason doesn't like the
7884 instantaneous send. */
7885 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7892 ChildProc *cp = (ChildProc *) pr;
7897 r = write(cp->fdTo, message++, 1);
7910 /**** Animation code by Hugh Fisher, DCS, ANU.
7912 Known problem: if a window overlapping the board is
7913 moved away while a piece is being animated underneath,
7914 the newly exposed area won't be updated properly.
7915 I can live with this.
7917 Known problem: if you look carefully at the animation
7918 of pieces in mono mode, they are being drawn as solid
7919 shapes without interior detail while moving. Fixing
7920 this would be a major complication for minimal return.
7923 /* Masks for XPM pieces. Black and white pieces can have
7924 different shapes, but in the interest of retaining my
7925 sanity pieces must have the same outline on both light
7926 and dark squares, and all pieces must use the same
7927 background square colors/images. */
7929 static int xpmDone = 0;
7932 CreateAnimMasks (pieceDepth)
7939 unsigned long plane;
7942 /* Need a bitmap just to get a GC with right depth */
7943 buf = XCreatePixmap(xDisplay, xBoardWindow,
7945 values.foreground = 1;
7946 values.background = 0;
7947 /* Don't use XtGetGC, not read only */
7948 maskGC = XCreateGC(xDisplay, buf,
7949 GCForeground | GCBackground, &values);
7950 XFreePixmap(xDisplay, buf);
7952 buf = XCreatePixmap(xDisplay, xBoardWindow,
7953 squareSize, squareSize, pieceDepth);
7954 values.foreground = XBlackPixel(xDisplay, xScreen);
7955 values.background = XWhitePixel(xDisplay, xScreen);
7956 bufGC = XCreateGC(xDisplay, buf,
7957 GCForeground | GCBackground, &values);
7959 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7960 /* Begin with empty mask */
7961 if(!xpmDone) // [HGM] pieces: keep using existing
7962 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7963 squareSize, squareSize, 1);
7964 XSetFunction(xDisplay, maskGC, GXclear);
7965 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7966 0, 0, squareSize, squareSize);
7968 /* Take a copy of the piece */
7973 XSetFunction(xDisplay, bufGC, GXcopy);
7974 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7976 0, 0, squareSize, squareSize, 0, 0);
7978 /* XOR the background (light) over the piece */
7979 XSetFunction(xDisplay, bufGC, GXxor);
7981 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7982 0, 0, squareSize, squareSize, 0, 0);
7984 XSetForeground(xDisplay, bufGC, lightSquareColor);
7985 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7988 /* We now have an inverted piece image with the background
7989 erased. Construct mask by just selecting all the non-zero
7990 pixels - no need to reconstruct the original image. */
7991 XSetFunction(xDisplay, maskGC, GXor);
7993 /* Might be quicker to download an XImage and create bitmap
7994 data from it rather than this N copies per piece, but it
7995 only takes a fraction of a second and there is a much
7996 longer delay for loading the pieces. */
7997 for (n = 0; n < pieceDepth; n ++) {
7998 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7999 0, 0, squareSize, squareSize,
8005 XFreePixmap(xDisplay, buf);
8006 XFreeGC(xDisplay, bufGC);
8007 XFreeGC(xDisplay, maskGC);
8011 InitAnimState (anim, info)
8013 XWindowAttributes * info;
8018 /* Each buffer is square size, same depth as window */
8019 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8020 squareSize, squareSize, info->depth);
8021 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8022 squareSize, squareSize, info->depth);
8024 /* Create a plain GC for blitting */
8025 mask = GCForeground | GCBackground | GCFunction |
8026 GCPlaneMask | GCGraphicsExposures;
8027 values.foreground = XBlackPixel(xDisplay, xScreen);
8028 values.background = XWhitePixel(xDisplay, xScreen);
8029 values.function = GXcopy;
8030 values.plane_mask = AllPlanes;
8031 values.graphics_exposures = False;
8032 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8034 /* Piece will be copied from an existing context at
8035 the start of each new animation/drag. */
8036 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8038 /* Outline will be a read-only copy of an existing */
8039 anim->outlineGC = None;
8045 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8046 XWindowAttributes info;
8048 if (xpmDone && gameInfo.variant == old) return;
8049 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8050 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8052 InitAnimState(&game, &info);
8053 InitAnimState(&player, &info);
8055 /* For XPM pieces, we need bitmaps to use as masks. */
8057 CreateAnimMasks(info.depth);
8063 static Boolean frameWaiting;
8065 static RETSIGTYPE FrameAlarm (sig)
8068 frameWaiting = False;
8069 /* In case System-V style signals. Needed?? */
8070 signal(SIGALRM, FrameAlarm);
8077 struct itimerval delay;
8079 XSync(xDisplay, False);
8082 frameWaiting = True;
8083 signal(SIGALRM, FrameAlarm);
8084 delay.it_interval.tv_sec =
8085 delay.it_value.tv_sec = time / 1000;
8086 delay.it_interval.tv_usec =
8087 delay.it_value.tv_usec = (time % 1000) * 1000;
8088 setitimer(ITIMER_REAL, &delay, NULL);
8089 while (frameWaiting) pause();
8090 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8091 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8092 setitimer(ITIMER_REAL, &delay, NULL);
8102 XSync(xDisplay, False);
8104 usleep(time * 1000);
8109 /* Convert board position to corner of screen rect and color */
8112 ScreenSquare(column, row, pt, color)
8113 int column; int row; XPoint * pt; int * color;
8116 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8117 pt->y = lineGap + row * (squareSize + lineGap);
8119 pt->x = lineGap + column * (squareSize + lineGap);
8120 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8122 *color = SquareColor(row, column);
8125 /* Convert window coords to square */
8128 BoardSquare(x, y, column, row)
8129 int x; int y; int * column; int * row;
8131 *column = EventToSquare(x, BOARD_WIDTH);
8132 if (flipView && *column >= 0)
8133 *column = BOARD_WIDTH - 1 - *column;
8134 *row = EventToSquare(y, BOARD_HEIGHT);
8135 if (!flipView && *row >= 0)
8136 *row = BOARD_HEIGHT - 1 - *row;
8141 #undef Max /* just in case */
8143 #define Max(a, b) ((a) > (b) ? (a) : (b))
8144 #define Min(a, b) ((a) < (b) ? (a) : (b))
8147 SetRect(rect, x, y, width, height)
8148 XRectangle * rect; int x; int y; int width; int height;
8152 rect->width = width;
8153 rect->height = height;
8156 /* Test if two frames overlap. If they do, return
8157 intersection rect within old and location of
8158 that rect within new. */
8161 Intersect(old, new, size, area, pt)
8162 XPoint * old; XPoint * new;
8163 int size; XRectangle * area; XPoint * pt;
8165 if (old->x > new->x + size || new->x > old->x + size ||
8166 old->y > new->y + size || new->y > old->y + size) {
8169 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8170 size - abs(old->x - new->x), size - abs(old->y - new->y));
8171 pt->x = Max(old->x - new->x, 0);
8172 pt->y = Max(old->y - new->y, 0);
8177 /* For two overlapping frames, return the rect(s)
8178 in the old that do not intersect with the new. */
8181 CalcUpdateRects(old, new, size, update, nUpdates)
8182 XPoint * old; XPoint * new; int size;
8183 XRectangle update[]; int * nUpdates;
8187 /* If old = new (shouldn't happen) then nothing to draw */
8188 if (old->x == new->x && old->y == new->y) {
8192 /* Work out what bits overlap. Since we know the rects
8193 are the same size we don't need a full intersect calc. */
8195 /* Top or bottom edge? */
8196 if (new->y > old->y) {
8197 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8199 } else if (old->y > new->y) {
8200 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8201 size, old->y - new->y);
8204 /* Left or right edge - don't overlap any update calculated above. */
8205 if (new->x > old->x) {
8206 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8207 new->x - old->x, size - abs(new->y - old->y));
8209 } else if (old->x > new->x) {
8210 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8211 old->x - new->x, size - abs(new->y - old->y));
8218 /* Generate a series of frame coords from start->mid->finish.
8219 The movement rate doubles until the half way point is
8220 reached, then halves back down to the final destination,
8221 which gives a nice slow in/out effect. The algorithmn
8222 may seem to generate too many intermediates for short
8223 moves, but remember that the purpose is to attract the
8224 viewers attention to the piece about to be moved and
8225 then to where it ends up. Too few frames would be less
8229 Tween(start, mid, finish, factor, frames, nFrames)
8230 XPoint * start; XPoint * mid;
8231 XPoint * finish; int factor;
8232 XPoint frames[]; int * nFrames;
8234 int fraction, n, count;
8238 /* Slow in, stepping 1/16th, then 1/8th, ... */
8240 for (n = 0; n < factor; n++)
8242 for (n = 0; n < factor; n++) {
8243 frames[count].x = start->x + (mid->x - start->x) / fraction;
8244 frames[count].y = start->y + (mid->y - start->y) / fraction;
8246 fraction = fraction / 2;
8250 frames[count] = *mid;
8253 /* Slow out, stepping 1/2, then 1/4, ... */
8255 for (n = 0; n < factor; n++) {
8256 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8257 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8259 fraction = fraction * 2;
8264 /* Draw a piece on the screen without disturbing what's there */
8267 SelectGCMask(piece, clip, outline, mask)
8268 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8272 /* Bitmap for piece being moved. */
8273 if (appData.monoMode) {
8274 *mask = *pieceToSolid(piece);
8275 } else if (useImages) {
8277 *mask = xpmMask[piece];
8279 *mask = ximMaskPm[piece];
8282 *mask = *pieceToSolid(piece);
8285 /* GC for piece being moved. Square color doesn't matter, but
8286 since it gets modified we make a copy of the original. */
8288 if (appData.monoMode)
8293 if (appData.monoMode)
8298 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8300 /* Outline only used in mono mode and is not modified */
8302 *outline = bwPieceGC;
8304 *outline = wbPieceGC;
8308 OverlayPiece(piece, clip, outline, dest)
8309 ChessSquare piece; GC clip; GC outline; Drawable dest;
8314 /* Draw solid rectangle which will be clipped to shape of piece */
8315 XFillRectangle(xDisplay, dest, clip,
8316 0, 0, squareSize, squareSize);
8317 if (appData.monoMode)
8318 /* Also draw outline in contrasting color for black
8319 on black / white on white cases */
8320 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8321 0, 0, squareSize, squareSize, 0, 0, 1);
8323 /* Copy the piece */
8328 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8330 0, 0, squareSize, squareSize,
8335 /* Animate the movement of a single piece */
8338 BeginAnimation(anim, piece, startColor, start)
8346 /* The old buffer is initialised with the start square (empty) */
8347 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8348 anim->prevFrame = *start;
8350 /* The piece will be drawn using its own bitmap as a matte */
8351 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8352 XSetClipMask(xDisplay, anim->pieceGC, mask);
8356 AnimationFrame(anim, frame, piece)
8361 XRectangle updates[4];
8366 /* Save what we are about to draw into the new buffer */
8367 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8368 frame->x, frame->y, squareSize, squareSize,
8371 /* Erase bits of the previous frame */
8372 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8373 /* Where the new frame overlapped the previous,
8374 the contents in newBuf are wrong. */
8375 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8376 overlap.x, overlap.y,
8377 overlap.width, overlap.height,
8379 /* Repaint the areas in the old that don't overlap new */
8380 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8381 for (i = 0; i < count; i++)
8382 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8383 updates[i].x - anim->prevFrame.x,
8384 updates[i].y - anim->prevFrame.y,
8385 updates[i].width, updates[i].height,
8386 updates[i].x, updates[i].y);
8388 /* Easy when no overlap */
8389 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8390 0, 0, squareSize, squareSize,
8391 anim->prevFrame.x, anim->prevFrame.y);
8394 /* Save this frame for next time round */
8395 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8396 0, 0, squareSize, squareSize,
8398 anim->prevFrame = *frame;
8400 /* Draw piece over original screen contents, not current,
8401 and copy entire rect. Wipes out overlapping piece images. */
8402 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8403 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8404 0, 0, squareSize, squareSize,
8405 frame->x, frame->y);
8409 EndAnimation (anim, finish)
8413 XRectangle updates[4];
8418 /* The main code will redraw the final square, so we
8419 only need to erase the bits that don't overlap. */
8420 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8421 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8422 for (i = 0; i < count; i++)
8423 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8424 updates[i].x - anim->prevFrame.x,
8425 updates[i].y - anim->prevFrame.y,
8426 updates[i].width, updates[i].height,
8427 updates[i].x, updates[i].y);
8429 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8430 0, 0, squareSize, squareSize,
8431 anim->prevFrame.x, anim->prevFrame.y);
8436 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8438 ChessSquare piece; int startColor;
8439 XPoint * start; XPoint * finish;
8440 XPoint frames[]; int nFrames;
8444 BeginAnimation(anim, piece, startColor, start);
8445 for (n = 0; n < nFrames; n++) {
8446 AnimationFrame(anim, &(frames[n]), piece);
8447 FrameDelay(appData.animSpeed);
8449 EndAnimation(anim, finish);
8452 /* Main control logic for deciding what to animate and how */
8455 AnimateMove(board, fromX, fromY, toX, toY)
8464 XPoint start, finish, mid;
8465 XPoint frames[kFactor * 2 + 1];
8466 int nFrames, startColor, endColor;
8468 /* Are we animating? */
8469 if (!appData.animate || appData.blindfold)
8472 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8473 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8474 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8476 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8477 piece = board[fromY][fromX];
8478 if (piece >= EmptySquare) return;
8483 hop = (piece == WhiteKnight || piece == BlackKnight);
8486 if (appData.debugMode) {
8487 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8488 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8489 piece, fromX, fromY, toX, toY); }
8491 ScreenSquare(fromX, fromY, &start, &startColor);
8492 ScreenSquare(toX, toY, &finish, &endColor);
8495 /* Knight: make diagonal movement then straight */
8496 if (abs(toY - fromY) < abs(toX - fromX)) {
8497 mid.x = start.x + (finish.x - start.x) / 2;
8501 mid.y = start.y + (finish.y - start.y) / 2;
8504 mid.x = start.x + (finish.x - start.x) / 2;
8505 mid.y = start.y + (finish.y - start.y) / 2;
8508 /* Don't use as many frames for very short moves */
8509 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8510 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8512 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8513 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8515 /* Be sure end square is redrawn */
8516 damage[toY][toX] = True;
8520 DragPieceBegin(x, y)
8523 int boardX, boardY, color;
8526 /* Are we animating? */
8527 if (!appData.animateDragging || appData.blindfold)
8530 /* Figure out which square we start in and the
8531 mouse position relative to top left corner. */
8532 BoardSquare(x, y, &boardX, &boardY);
8533 player.startBoardX = boardX;
8534 player.startBoardY = boardY;
8535 ScreenSquare(boardX, boardY, &corner, &color);
8536 player.startSquare = corner;
8537 player.startColor = color;
8538 /* As soon as we start dragging, the piece will jump slightly to
8539 be centered over the mouse pointer. */
8540 player.mouseDelta.x = squareSize/2;
8541 player.mouseDelta.y = squareSize/2;
8542 /* Initialise animation */
8543 player.dragPiece = PieceForSquare(boardX, boardY);
8545 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8546 player.dragActive = True;
8547 BeginAnimation(&player, player.dragPiece, color, &corner);
8548 /* Mark this square as needing to be redrawn. Note that
8549 we don't remove the piece though, since logically (ie
8550 as seen by opponent) the move hasn't been made yet. */
8551 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8552 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8553 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8554 corner.x, corner.y, squareSize, squareSize,
8555 0, 0); // [HGM] zh: unstack in stead of grab
8556 damage[boardY][boardX] = True;
8558 player.dragActive = False;
8568 /* Are we animating? */
8569 if (!appData.animateDragging || appData.blindfold)
8573 if (! player.dragActive)
8575 /* Move piece, maintaining same relative position
8576 of mouse within square */
8577 corner.x = x - player.mouseDelta.x;
8578 corner.y = y - player.mouseDelta.y;
8579 AnimationFrame(&player, &corner, player.dragPiece);
8581 if (appData.highlightDragging) {
8583 BoardSquare(x, y, &boardX, &boardY);
8584 SetHighlights(fromX, fromY, boardX, boardY);
8593 int boardX, boardY, color;
8596 /* Are we animating? */
8597 if (!appData.animateDragging || appData.blindfold)
8601 if (! player.dragActive)
8603 /* Last frame in sequence is square piece is
8604 placed on, which may not match mouse exactly. */
8605 BoardSquare(x, y, &boardX, &boardY);
8606 ScreenSquare(boardX, boardY, &corner, &color);
8607 EndAnimation(&player, &corner);
8609 /* Be sure end square is redrawn */
8610 damage[boardY][boardX] = True;
8612 /* This prevents weird things happening with fast successive
8613 clicks which on my Sun at least can cause motion events
8614 without corresponding press/release. */
8615 player.dragActive = False;
8618 /* Handle expose event while piece being dragged */
8623 if (!player.dragActive || appData.blindfold)
8626 /* What we're doing: logically, the move hasn't been made yet,
8627 so the piece is still in it's original square. But visually
8628 it's being dragged around the board. So we erase the square
8629 that the piece is on and draw it at the last known drag point. */
8630 BlankSquare(player.startSquare.x, player.startSquare.y,
8631 player.startColor, EmptySquare, xBoardWindow);
8632 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8633 damage[player.startBoardY][player.startBoardX] = TRUE;
8636 #include <sys/ioctl.h>
8637 int get_term_width()
8639 int fd, default_width;
8642 default_width = 79; // this is FICS default anyway...
8644 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8646 if (!ioctl(fd, TIOCGSIZE, &win))
8647 default_width = win.ts_cols;
8648 #elif defined(TIOCGWINSZ)
8650 if (!ioctl(fd, TIOCGWINSZ, &win))
8651 default_width = win.ws_col;
8653 return default_width;
8656 void update_ics_width()
8658 static int old_width = 0;
8659 int new_width = get_term_width();
8661 if (old_width != new_width)
8662 ics_printf("set width %d\n", new_width);
8663 old_width = new_width;
8666 void NotifyFrontendLogin()