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(());
452 * XBoard depends on Xt R4 or higher
454 int xtVersion = XtSpecificationRelease;
459 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
460 jailSquareColor, highlightSquareColor, premoveHighlightColor;
461 Pixel lowTimeWarningColor;
462 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
463 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
464 wjPieceGC, bjPieceGC, prelineGC, countGC;
465 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
466 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
467 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
468 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
469 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
470 ICSInputShell, fileNameShell, askQuestionShell;
471 Widget historyShell, evalGraphShell, gameListShell;
472 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
473 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
474 Font clockFontID, coordFontID, countFontID;
475 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
476 XtAppContext appContext;
478 char *oldICSInteractionTitle;
482 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
484 Position commentX = -1, commentY = -1;
485 Dimension commentW, commentH;
486 typedef unsigned int BoardSize;
488 Boolean chessProgram;
490 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
491 int squareSize, smallLayout = 0, tinyLayout = 0,
492 marginW, marginH, // [HGM] for run-time resizing
493 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
494 ICSInputBoxUp = False, askQuestionUp = False,
495 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
496 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
497 Pixel timerForegroundPixel, timerBackgroundPixel;
498 Pixel buttonForegroundPixel, buttonBackgroundPixel;
499 char *chessDir, *programName, *programVersion,
500 *gameCopyFilename, *gamePasteFilename;
501 Boolean alwaysOnTop = False;
502 Boolean saveSettingsOnExit;
503 char *settingsFileName;
504 char *icsTextMenuString;
506 char *firstChessProgramNames;
507 char *secondChessProgramNames;
509 WindowPlacement wpMain;
510 WindowPlacement wpConsole;
511 WindowPlacement wpComment;
512 WindowPlacement wpMoveHistory;
513 WindowPlacement wpEvalGraph;
514 WindowPlacement wpEngineOutput;
515 WindowPlacement wpGameList;
516 WindowPlacement wpTags;
520 Pixmap pieceBitmap[2][(int)BlackPawn];
521 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
522 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
523 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
524 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
525 int useImages, useImageSqs;
526 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
527 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
528 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
529 XImage *ximLightSquare, *ximDarkSquare;
532 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
533 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
535 #define White(piece) ((int)(piece) < (int)BlackPawn)
537 /* Variables for doing smooth animation. This whole thing
538 would be much easier if the board was double-buffered,
539 but that would require a fairly major rewrite. */
544 GC blitGC, pieceGC, outlineGC;
545 XPoint startSquare, prevFrame, mouseDelta;
549 int startBoardX, startBoardY;
552 /* There can be two pieces being animated at once: a player
553 can begin dragging a piece before the remote opponent has moved. */
555 static AnimState game, player;
557 /* Bitmaps for use as masks when drawing XPM pieces.
558 Need one for each black and white piece. */
559 static Pixmap xpmMask[BlackKing + 1];
561 /* This magic number is the number of intermediate frames used
562 in each half of the animation. For short moves it's reduced
563 by 1. The total number of frames will be factor * 2 + 1. */
566 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
568 MenuItem fileMenu[] = {
569 {N_("New Game"), ResetProc},
570 {N_("New Shuffle Game ..."), ShuffleMenuProc},
571 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
572 {"----", NothingProc},
573 {N_("Load Game"), LoadGameProc},
574 {N_("Load Next Game"), LoadNextGameProc},
575 {N_("Load Previous Game"), LoadPrevGameProc},
576 {N_("Reload Same Game"), ReloadGameProc},
577 {N_("Save Game"), SaveGameProc},
578 {"----", NothingProc},
579 {N_("Copy Game"), CopyGameProc},
580 {N_("Paste Game"), PasteGameProc},
581 {"----", NothingProc},
582 {N_("Load Position"), LoadPositionProc},
583 {N_("Load Next Position"), LoadNextPositionProc},
584 {N_("Load Previous Position"), LoadPrevPositionProc},
585 {N_("Reload Same Position"), ReloadPositionProc},
586 {N_("Save Position"), SavePositionProc},
587 {"----", NothingProc},
588 {N_("Copy Position"), CopyPositionProc},
589 {N_("Paste Position"), PastePositionProc},
590 {"----", NothingProc},
591 {N_("Mail Move"), MailMoveProc},
592 {N_("Reload CMail Message"), ReloadCmailMsgProc},
593 {"----", NothingProc},
594 {N_("Exit"), QuitProc},
598 MenuItem modeMenu[] = {
599 {N_("Machine White"), MachineWhiteProc},
600 {N_("Machine Black"), MachineBlackProc},
601 {N_("Two Machines"), TwoMachinesProc},
602 {N_("Analysis Mode"), AnalyzeModeProc},
603 {N_("Analyze File"), AnalyzeFileProc },
604 {N_("ICS Client"), IcsClientProc},
605 {N_("Edit Game"), EditGameProc},
606 {N_("Edit Position"), EditPositionProc},
607 {N_("Training"), TrainingProc},
608 {"----", NothingProc},
609 {N_("Show Engine Output"), EngineOutputProc},
610 {N_("Show Evaluation Graph"), EvalGraphProc},
611 {N_("Show Game List"), ShowGameListProc},
612 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
613 {"----", NothingProc},
614 {N_("Edit Tags"), EditTagsProc},
615 {N_("Edit Comment"), EditCommentProc},
616 {N_("ICS Input Box"), IcsInputBoxProc},
617 {N_("Pause"), PauseProc},
621 MenuItem actionMenu[] = {
622 {N_("Accept"), AcceptProc},
623 {N_("Decline"), DeclineProc},
624 {N_("Rematch"), RematchProc},
625 {"----", NothingProc},
626 {N_("Call Flag"), CallFlagProc},
627 {N_("Draw"), DrawProc},
628 {N_("Adjourn"), AdjournProc},
629 {N_("Abort"), AbortProc},
630 {N_("Resign"), ResignProc},
631 {"----", NothingProc},
632 {N_("Stop Observing"), StopObservingProc},
633 {N_("Stop Examining"), StopExaminingProc},
634 {"----", NothingProc},
635 {N_("Adjudicate to White"), AdjuWhiteProc},
636 {N_("Adjudicate to Black"), AdjuBlackProc},
637 {N_("Adjudicate Draw"), AdjuDrawProc},
641 MenuItem stepMenu[] = {
642 {N_("Backward"), BackwardProc},
643 {N_("Forward"), ForwardProc},
644 {N_("Back to Start"), ToStartProc},
645 {N_("Forward to End"), ToEndProc},
646 {N_("Revert"), RevertProc},
647 {N_("Truncate Game"), TruncateGameProc},
648 {"----", NothingProc},
649 {N_("Move Now"), MoveNowProc},
650 {N_("Retract Move"), RetractMoveProc},
654 MenuItem optionsMenu[] = {
655 {N_("Flip View"), FlipViewProc},
656 {"----", NothingProc},
657 {N_("Adjudications ..."), EngineMenuProc},
658 {N_("General Settings ..."), UciMenuProc},
659 {N_("Engine #1 Settings ..."), FirstSettingsProc},
660 {N_("Engine #2 Settings ..."), SecondSettingsProc},
661 {N_("Time Control ..."), TimeControlProc},
662 {"----", NothingProc},
663 {N_("Always Queen"), AlwaysQueenProc},
664 {N_("Animate Dragging"), AnimateDraggingProc},
665 {N_("Animate Moving"), AnimateMovingProc},
666 {N_("Auto Comment"), AutocommProc},
667 {N_("Auto Flag"), AutoflagProc},
668 {N_("Auto Flip View"), AutoflipProc},
669 {N_("Auto Observe"), AutobsProc},
670 {N_("Auto Raise Board"), AutoraiseProc},
671 {N_("Auto Save"), AutosaveProc},
672 {N_("Blindfold"), BlindfoldProc},
673 {N_("Flash Moves"), FlashMovesProc},
674 {N_("Get Move List"), GetMoveListProc},
676 {N_("Highlight Dragging"), HighlightDraggingProc},
678 {N_("Highlight Last Move"), HighlightLastMoveProc},
679 {N_("Move Sound"), MoveSoundProc},
680 {N_("ICS Alarm"), IcsAlarmProc},
681 {N_("Old Save Style"), OldSaveStyleProc},
682 {N_("Periodic Updates"), PeriodicUpdatesProc},
683 {N_("Ponder Next Move"), PonderNextMoveProc},
684 {N_("Popup Exit Message"), PopupExitMessageProc},
685 {N_("Popup Move Errors"), PopupMoveErrorsProc},
686 {N_("Premove"), PremoveProc},
687 {N_("Quiet Play"), QuietPlayProc},
688 {N_("Show Coords"), ShowCoordsProc},
689 {N_("Hide Thinking"), HideThinkingProc},
690 {N_("Test Legality"), TestLegalityProc},
691 {"----", NothingProc},
692 {N_("Save Settings Now"), SaveSettingsProc},
693 {N_("Save Settings on Exit"), SaveOnExitProc},
697 MenuItem helpMenu[] = {
698 {N_("Info XBoard"), InfoProc},
699 {N_("Man XBoard"), ManProc},
700 {"----", NothingProc},
701 {N_("Hint"), HintProc},
702 {N_("Book"), BookProc},
703 {"----", NothingProc},
704 {N_("About XBoard"), AboutProc},
709 {N_("File"), fileMenu},
710 {N_("Mode"), modeMenu},
711 {N_("Action"), actionMenu},
712 {N_("Step"), stepMenu},
713 {N_("Options"), optionsMenu},
714 {N_("Help"), helpMenu},
718 #define PAUSE_BUTTON N_("P")
719 MenuItem buttonBar[] = {
722 {PAUSE_BUTTON, PauseProc},
728 #define PIECE_MENU_SIZE 18
729 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
730 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
731 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
732 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
733 N_("Empty square"), N_("Clear board") },
734 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
735 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
736 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
737 N_("Empty square"), N_("Clear board") }
739 /* must be in same order as PieceMenuStrings! */
740 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
741 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
742 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
743 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
744 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
745 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
746 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
747 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
748 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
751 #define DROP_MENU_SIZE 6
752 String dropMenuStrings[DROP_MENU_SIZE] = {
753 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
755 /* must be in same order as PieceMenuStrings! */
756 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
757 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
758 WhiteRook, WhiteQueen
766 DropMenuEnables dmEnables[] = {
784 { XtNborderWidth, 0 },
785 { XtNdefaultDistance, 0 },
789 { XtNborderWidth, 0 },
790 { XtNresizable, (XtArgVal) True },
794 { XtNborderWidth, 0 },
800 { XtNjustify, (XtArgVal) XtJustifyRight },
801 { XtNlabel, (XtArgVal) "..." },
802 { XtNresizable, (XtArgVal) True },
803 { XtNresize, (XtArgVal) False }
806 Arg messageArgs[] = {
807 { XtNjustify, (XtArgVal) XtJustifyLeft },
808 { XtNlabel, (XtArgVal) "..." },
809 { XtNresizable, (XtArgVal) True },
810 { XtNresize, (XtArgVal) False }
814 { XtNborderWidth, 0 },
815 { XtNjustify, (XtArgVal) XtJustifyLeft }
818 XtResource clientResources[] = {
819 { "flashCount", "flashCount", XtRInt, sizeof(int),
820 XtOffset(AppDataPtr, flashCount), XtRImmediate,
821 (XtPointer) FLASH_COUNT },
824 XrmOptionDescRec shellOptions[] = {
825 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
826 { "-flash", "flashCount", XrmoptionNoArg, "3" },
827 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
830 XtActionsRec boardActions[] = {
831 { "DrawPosition", DrawPositionProc },
832 { "HandleUserMove", HandleUserMove },
833 { "AnimateUserMove", AnimateUserMove },
834 { "FileNameAction", FileNameAction },
835 { "AskQuestionProc", AskQuestionProc },
836 { "AskQuestionReplyAction", AskQuestionReplyAction },
837 { "PieceMenuPopup", PieceMenuPopup },
838 { "WhiteClock", WhiteClock },
839 { "BlackClock", BlackClock },
840 { "Iconify", Iconify },
841 { "ResetProc", ResetProc },
842 { "LoadGameProc", LoadGameProc },
843 { "LoadNextGameProc", LoadNextGameProc },
844 { "LoadPrevGameProc", LoadPrevGameProc },
845 { "LoadSelectedProc", LoadSelectedProc },
846 { "ReloadGameProc", ReloadGameProc },
847 { "LoadPositionProc", LoadPositionProc },
848 { "LoadNextPositionProc", LoadNextPositionProc },
849 { "LoadPrevPositionProc", LoadPrevPositionProc },
850 { "ReloadPositionProc", ReloadPositionProc },
851 { "CopyPositionProc", CopyPositionProc },
852 { "PastePositionProc", PastePositionProc },
853 { "CopyGameProc", CopyGameProc },
854 { "PasteGameProc", PasteGameProc },
855 { "SaveGameProc", SaveGameProc },
856 { "SavePositionProc", SavePositionProc },
857 { "MailMoveProc", MailMoveProc },
858 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
859 { "QuitProc", QuitProc },
860 { "MachineWhiteProc", MachineWhiteProc },
861 { "MachineBlackProc", MachineBlackProc },
862 { "AnalysisModeProc", AnalyzeModeProc },
863 { "AnalyzeFileProc", AnalyzeFileProc },
864 { "TwoMachinesProc", TwoMachinesProc },
865 { "IcsClientProc", IcsClientProc },
866 { "EditGameProc", EditGameProc },
867 { "EditPositionProc", EditPositionProc },
868 { "TrainingProc", EditPositionProc },
869 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
870 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
871 { "ShowGameListProc", ShowGameListProc },
872 { "ShowMoveListProc", HistoryShowProc},
873 { "EditTagsProc", EditCommentProc },
874 { "EditCommentProc", EditCommentProc },
875 { "IcsAlarmProc", IcsAlarmProc },
876 { "IcsInputBoxProc", IcsInputBoxProc },
877 { "PauseProc", PauseProc },
878 { "AcceptProc", AcceptProc },
879 { "DeclineProc", DeclineProc },
880 { "RematchProc", RematchProc },
881 { "CallFlagProc", CallFlagProc },
882 { "DrawProc", DrawProc },
883 { "AdjournProc", AdjournProc },
884 { "AbortProc", AbortProc },
885 { "ResignProc", ResignProc },
886 { "AdjuWhiteProc", AdjuWhiteProc },
887 { "AdjuBlackProc", AdjuBlackProc },
888 { "AdjuDrawProc", AdjuDrawProc },
889 { "EnterKeyProc", EnterKeyProc },
890 { "StopObservingProc", StopObservingProc },
891 { "StopExaminingProc", StopExaminingProc },
892 { "BackwardProc", BackwardProc },
893 { "ForwardProc", ForwardProc },
894 { "ToStartProc", ToStartProc },
895 { "ToEndProc", ToEndProc },
896 { "RevertProc", RevertProc },
897 { "TruncateGameProc", TruncateGameProc },
898 { "MoveNowProc", MoveNowProc },
899 { "RetractMoveProc", RetractMoveProc },
900 { "AlwaysQueenProc", AlwaysQueenProc },
901 { "AnimateDraggingProc", AnimateDraggingProc },
902 { "AnimateMovingProc", AnimateMovingProc },
903 { "AutoflagProc", AutoflagProc },
904 { "AutoflipProc", AutoflipProc },
905 { "AutobsProc", AutobsProc },
906 { "AutoraiseProc", AutoraiseProc },
907 { "AutosaveProc", AutosaveProc },
908 { "BlindfoldProc", BlindfoldProc },
909 { "FlashMovesProc", FlashMovesProc },
910 { "FlipViewProc", FlipViewProc },
911 { "GetMoveListProc", GetMoveListProc },
913 { "HighlightDraggingProc", HighlightDraggingProc },
915 { "HighlightLastMoveProc", HighlightLastMoveProc },
916 { "IcsAlarmProc", IcsAlarmProc },
917 { "MoveSoundProc", MoveSoundProc },
918 { "OldSaveStyleProc", OldSaveStyleProc },
919 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
920 { "PonderNextMoveProc", PonderNextMoveProc },
921 { "PopupExitMessageProc", PopupExitMessageProc },
922 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
923 { "PremoveProc", PremoveProc },
924 { "QuietPlayProc", QuietPlayProc },
925 { "ShowCoordsProc", ShowCoordsProc },
926 { "ShowThinkingProc", ShowThinkingProc },
927 { "HideThinkingProc", HideThinkingProc },
928 { "TestLegalityProc", TestLegalityProc },
929 { "SaveSettingsProc", SaveSettingsProc },
930 { "SaveOnExitProc", SaveOnExitProc },
931 { "InfoProc", InfoProc },
932 { "ManProc", ManProc },
933 { "HintProc", HintProc },
934 { "BookProc", BookProc },
935 { "AboutGameProc", AboutGameProc },
936 { "AboutProc", AboutProc },
937 { "DebugProc", DebugProc },
938 { "NothingProc", NothingProc },
939 { "CommentPopDown", (XtActionProc) CommentPopDown },
940 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
941 { "TagsPopDown", (XtActionProc) TagsPopDown },
942 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
943 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
944 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
945 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
946 { "GameListPopDown", (XtActionProc) GameListPopDown },
947 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
948 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
949 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
950 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
951 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
952 { "EnginePopDown", (XtActionProc) EnginePopDown },
953 { "UciPopDown", (XtActionProc) UciPopDown },
954 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
955 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
956 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
959 char globalTranslations[] =
960 ":<Key>R: ResignProc() \n \
961 :<Key>r: ResetProc() \n \
962 :<Key>g: LoadGameProc() \n \
963 :<Key>N: LoadNextGameProc() \n \
964 :<Key>P: LoadPrevGameProc() \n \
965 :<Key>Q: QuitProc() \n \
966 :<Key>F: ToEndProc() \n \
967 :<Key>f: ForwardProc() \n \
968 :<Key>B: ToStartProc() \n \
969 :<Key>b: BackwardProc() \n \
970 :<Key>p: PauseProc() \n \
971 :<Key>d: DrawProc() \n \
972 :<Key>t: CallFlagProc() \n \
973 :<Key>i: Iconify() \n \
974 :<Key>c: Iconify() \n \
975 :<Key>v: FlipViewProc() \n \
976 <KeyDown>Control_L: BackwardProc() \n \
977 <KeyUp>Control_L: ForwardProc() \n \
978 <KeyDown>Control_R: BackwardProc() \n \
979 <KeyUp>Control_R: ForwardProc() \n \
980 Shift<Key>1: AskQuestionProc(\"Direct command\",\
981 \"Send to chess program:\",,1) \n \
982 Shift<Key>2: AskQuestionProc(\"Direct command\",\
983 \"Send to second chess program:\",,2) \n";
985 char boardTranslations[] =
986 "<Btn1Down>: HandleUserMove() \n \
987 <Btn1Up>: HandleUserMove() \n \
988 <Btn1Motion>: AnimateUserMove() \n \
989 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
990 PieceMenuPopup(menuB) \n \
991 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
992 PieceMenuPopup(menuW) \n \
993 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
994 PieceMenuPopup(menuW) \n \
995 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
996 PieceMenuPopup(menuB) \n";
998 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
999 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1001 char ICSInputTranslations[] =
1002 "<Key>Return: EnterKeyProc() \n";
1004 String xboardResources[] = {
1005 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1006 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1007 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1012 /* Max possible square size */
1013 #define MAXSQSIZE 256
1015 static int xpm_avail[MAXSQSIZE];
1017 #ifdef HAVE_DIR_STRUCT
1019 /* Extract piece size from filename */
1021 xpm_getsize(name, len, ext)
1032 if ((p=strchr(name, '.')) == NULL ||
1033 StrCaseCmp(p+1, ext) != 0)
1039 while (*p && isdigit(*p))
1046 /* Setup xpm_avail */
1048 xpm_getavail(dirname, ext)
1056 for (i=0; i<MAXSQSIZE; ++i)
1059 if (appData.debugMode)
1060 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1062 dir = opendir(dirname);
1065 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1066 programName, dirname);
1070 while ((ent=readdir(dir)) != NULL) {
1071 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1072 if (i > 0 && i < MAXSQSIZE)
1082 xpm_print_avail(fp, ext)
1088 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1089 for (i=1; i<MAXSQSIZE; ++i) {
1095 /* Return XPM piecesize closest to size */
1097 xpm_closest_to(dirname, size, ext)
1103 int sm_diff = MAXSQSIZE;
1107 xpm_getavail(dirname, ext);
1109 if (appData.debugMode)
1110 xpm_print_avail(stderr, ext);
1112 for (i=1; i<MAXSQSIZE; ++i) {
1115 diff = (diff<0) ? -diff : diff;
1116 if (diff < sm_diff) {
1124 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1130 #else /* !HAVE_DIR_STRUCT */
1131 /* If we are on a system without a DIR struct, we can't
1132 read the directory, so we can't collect a list of
1133 filenames, etc., so we can't do any size-fitting. */
1135 xpm_closest_to(dirname, size, ext)
1140 fprintf(stderr, _("\
1141 Warning: No DIR structure found on this system --\n\
1142 Unable to autosize for XPM/XIM pieces.\n\
1143 Please report this error to frankm@hiwaay.net.\n\
1144 Include system type & operating system in message.\n"));
1147 #endif /* HAVE_DIR_STRUCT */
1149 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1150 "magenta", "cyan", "white" };
1154 TextColors textColors[(int)NColorClasses];
1156 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1158 parse_color(str, which)
1162 char *p, buf[100], *d;
1165 if (strlen(str) > 99) /* watch bounds on buf */
1170 for (i=0; i<which; ++i) {
1177 /* Could be looking at something like:
1179 .. in which case we want to stop on a comma also */
1180 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1184 return -1; /* Use default for empty field */
1187 if (which == 2 || isdigit(*p))
1190 while (*p && isalpha(*p))
1195 for (i=0; i<8; ++i) {
1196 if (!StrCaseCmp(buf, cnames[i]))
1197 return which? (i+40) : (i+30);
1199 if (!StrCaseCmp(buf, "default")) return -1;
1201 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1206 parse_cpair(cc, str)
1210 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1211 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1216 /* bg and attr are optional */
1217 textColors[(int)cc].bg = parse_color(str, 1);
1218 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1219 textColors[(int)cc].attr = 0;
1225 /* Arrange to catch delete-window events */
1226 Atom wm_delete_window;
1228 CatchDeleteWindow(Widget w, String procname)
1231 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1232 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1233 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1240 XtSetArg(args[0], XtNiconic, False);
1241 XtSetValues(shellWidget, args, 1);
1243 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1246 //---------------------------------------------------------------------------------------------------------
1247 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1250 #define CW_USEDEFAULT (1<<31)
1251 #define ICS_TEXT_MENU_SIZE 90
1252 #define SetCurrentDirectory chdir
1253 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1257 // these two must some day move to frontend.h, when they are implemented
1258 Boolean MoveHistoryIsUp();
1259 Boolean GameListIsUp();
1261 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1264 // front-end part of option handling
1266 // [HGM] This platform-dependent table provides the location for storing the color info
1267 extern char *crWhite, * crBlack;
1271 &appData.whitePieceColor,
1272 &appData.blackPieceColor,
1273 &appData.lightSquareColor,
1274 &appData.darkSquareColor,
1275 &appData.highlightSquareColor,
1276 &appData.premoveHighlightColor,
1289 ParseFont(char *name, int number)
1290 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1292 case 0: // CLOCK_FONT
1293 appData.clockFont = strdup(name);
1295 case 1: // MESSAGE_FONT
1296 appData.font = strdup(name);
1298 case 2: // COORD_FONT
1299 appData.coordFont = strdup(name);
1308 { // only 2 fonts currently
1309 appData.clockFont = CLOCK_FONT_NAME;
1310 appData.coordFont = COORD_FONT_NAME;
1311 appData.font = DEFAULT_FONT_NAME;
1316 { // no-op, until we identify the code for this already in XBoard and move it here
1320 ParseColor(int n, char *name)
1321 { // in XBoard, just copy the color-name string
1322 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1326 ParseTextAttribs(ColorClass cc, char *s)
1328 (&appData.colorShout)[cc] = strdup(s);
1332 ParseBoardSize(void *addr, char *name)
1334 appData.boardSize = strdup(name);
1339 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1343 SetCommPortDefaults()
1344 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1347 // [HGM] args: these three cases taken out to stay in front-end
1349 SaveFontArg(FILE *f, ArgDescriptor *ad)
1352 switch((int)ad->argLoc) {
1353 case 0: // CLOCK_FONT
1354 name = appData.clockFont;
1356 case 1: // MESSAGE_FONT
1357 name = appData.font;
1359 case 2: // COORD_FONT
1360 name = appData.coordFont;
1365 // Do not save fonts for now, as the saved font would be board-size specific
1366 // and not suitable for a re-start at another board size
1367 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1372 { // nothing to do, as the sounds are at all times represented by their text-string names already
1376 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1377 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1378 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1382 SaveColor(FILE *f, ArgDescriptor *ad)
1383 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1384 if(colorVariable[(int)ad->argLoc])
1385 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1389 SaveBoardSize(FILE *f, char *name, void *addr)
1390 { // wrapper to shield back-end from BoardSize & sizeInfo
1391 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1395 ParseCommPortSettings(char *s)
1396 { // no such option in XBoard (yet)
1399 extern Widget engineOutputShell;
1400 extern Widget tagsShell, editTagsShell;
1402 GetActualPlacement(Widget wg, WindowPlacement *wp)
1412 XtSetArg(args[i], XtNx, &x); i++;
1413 XtSetArg(args[i], XtNy, &y); i++;
1414 XtSetArg(args[i], XtNwidth, &w); i++;
1415 XtSetArg(args[i], XtNheight, &h); i++;
1416 XtGetValues(wg, args, i);
1425 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1426 // In XBoard this will have to wait until awareness of window parameters is implemented
1427 GetActualPlacement(shellWidget, &wpMain);
1428 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1429 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1430 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1431 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1432 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1433 else GetActualPlacement(editShell, &wpComment);
1434 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1435 else GetActualPlacement(editTagsShell, &wpTags);
1439 PrintCommPortSettings(FILE *f, char *name)
1440 { // This option does not exist in XBoard
1444 MySearchPath(char *installDir, char *name, char *fullname)
1445 { // just append installDir and name. Perhaps ExpandPath should be used here?
1446 name = ExpandPathName(name);
1447 if(name && name[0] == '/') strcpy(fullname, name); else {
1448 sprintf(fullname, "%s%c%s", installDir, '/', name);
1454 MyGetFullPathName(char *name, char *fullname)
1455 { // should use ExpandPath?
1456 name = ExpandPathName(name);
1457 strcpy(fullname, name);
1462 EnsureOnScreen(int *x, int *y, int minX, int minY)
1469 { // [HGM] args: allows testing if main window is realized from back-end
1470 return xBoardWindow != 0;
1474 PopUpStartupDialog()
1475 { // start menu not implemented in XBoard
1478 ConvertToLine(int argc, char **argv)
1480 static char line[128*1024], buf[1024];
1484 for(i=1; i<argc; i++) {
1485 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1486 && argv[i][0] != '{' )
1487 sprintf(buf, "{%s} ", argv[i]);
1488 else sprintf(buf, "%s ", argv[i]);
1491 line[strlen(line)-1] = NULLCHAR;
1495 //--------------------------------------------------------------------------------------------
1498 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1500 #define BoardSize int
1501 void InitDrawingSizes(BoardSize boardSize, int flags)
1502 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1503 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1505 XtGeometryResult gres;
1508 if(!formWidget) return;
1511 * Enable shell resizing.
1513 shellArgs[0].value = (XtArgVal) &w;
1514 shellArgs[1].value = (XtArgVal) &h;
1515 XtGetValues(shellWidget, shellArgs, 2);
1517 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1518 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1519 XtSetValues(shellWidget, &shellArgs[2], 4);
1521 XtSetArg(args[0], XtNdefaultDistance, &sep);
1522 XtGetValues(formWidget, args, 1);
1524 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1525 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1528 XtSetArg(args[0], XtNwidth, boardWidth);
1529 XtSetArg(args[1], XtNheight, boardHeight);
1530 XtSetValues(boardWidget, args, 2);
1532 timerWidth = (boardWidth - sep) / 2;
1533 XtSetArg(args[0], XtNwidth, timerWidth);
1534 XtSetValues(whiteTimerWidget, args, 1);
1535 XtSetValues(blackTimerWidget, args, 1);
1537 XawFormDoLayout(formWidget, False);
1539 if (appData.titleInWindow) {
1541 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1542 XtSetArg(args[i], XtNheight, &h); i++;
1543 XtGetValues(titleWidget, args, i);
1545 w = boardWidth - 2*bor;
1547 XtSetArg(args[0], XtNwidth, &w);
1548 XtGetValues(menuBarWidget, args, 1);
1549 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1552 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1553 if (gres != XtGeometryYes && appData.debugMode) {
1555 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1556 programName, gres, w, h, wr, hr);
1560 XawFormDoLayout(formWidget, True);
1563 * Inhibit shell resizing.
1565 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1566 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1567 shellArgs[4].value = shellArgs[2].value = w;
1568 shellArgs[5].value = shellArgs[3].value = h;
1569 XtSetValues(shellWidget, &shellArgs[0], 6);
1571 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1574 for(i=0; i<4; i++) {
1576 for(p=0; p<=(int)WhiteKing; p++)
1577 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1578 if(gameInfo.variant == VariantShogi) {
1579 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1580 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1581 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1582 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1583 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1586 if(gameInfo.variant == VariantGothic) {
1587 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1591 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1592 for(p=0; p<=(int)WhiteKing; p++)
1593 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1594 if(gameInfo.variant == VariantShogi) {
1595 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1596 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1597 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1598 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1599 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1602 if(gameInfo.variant == VariantGothic) {
1603 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1609 for(i=0; i<2; i++) {
1611 for(p=0; p<=(int)WhiteKing; p++)
1612 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1613 if(gameInfo.variant == VariantShogi) {
1614 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1615 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1616 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1617 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1618 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1621 if(gameInfo.variant == VariantGothic) {
1622 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1633 void EscapeExpand(char *p, char *q)
1634 { // [HGM] initstring: routine to shape up string arguments
1635 while(*p++ = *q++) if(p[-1] == '\\')
1637 case 'n': p[-1] = '\n'; break;
1638 case 'r': p[-1] = '\r'; break;
1639 case 't': p[-1] = '\t'; break;
1640 case '\\': p[-1] = '\\'; break;
1641 case 0: *p = 0; return;
1642 default: p[-1] = q[-1]; break;
1651 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1652 XSetWindowAttributes window_attributes;
1654 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1655 XrmValue vFrom, vTo;
1656 XtGeometryResult gres;
1659 int forceMono = False;
1660 //define INDIRECTION
1662 // [HGM] before anything else, expand any indirection files amongst options
1663 char *argvCopy[1000]; // 1000 seems enough
1664 char newArgs[10000]; // holds actual characters
1667 srandom(time(0)); // [HGM] book: make random truly random
1670 for(i=0; i<argc; i++) {
1671 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1672 //fprintf(stderr, "arg %s\n", argv[i]);
1673 if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
1675 FILE *f = fopen(argv[i]+1, "rb");
1676 if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing
1677 argvCopy[j++] = newArgs + k; // get ready for first argument from file
1678 while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
1680 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1681 newArgs[k++] = 0; // terminate current arg
1682 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1683 argvCopy[j++] = newArgs + k; // get ready for next
1685 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1699 setbuf(stdout, NULL);
1700 setbuf(stderr, NULL);
1703 programName = strrchr(argv[0], '/');
1704 if (programName == NULL)
1705 programName = argv[0];
1710 XtSetLanguageProc(NULL, NULL, NULL);
1711 bindtextdomain(PACKAGE, LOCALEDIR);
1712 textdomain(PACKAGE);
1716 XtAppInitialize(&appContext, "XBoard", shellOptions,
1717 XtNumber(shellOptions),
1718 &argc, argv, xboardResources, NULL, 0);
1719 appData.boardSize = "";
1720 InitAppData(ConvertToLine(argc, argv));
1722 if (p == NULL) p = "/tmp";
1723 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1724 gameCopyFilename = (char*) malloc(i);
1725 gamePasteFilename = (char*) malloc(i);
1726 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1727 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1729 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1730 clientResources, XtNumber(clientResources),
1733 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1734 static char buf[MSG_SIZ];
1735 EscapeExpand(buf, appData.initString);
1736 appData.initString = strdup(buf);
1737 EscapeExpand(buf, appData.secondInitString);
1738 appData.secondInitString = strdup(buf);
1739 EscapeExpand(buf, appData.firstComputerString);
1740 appData.firstComputerString = strdup(buf);
1741 EscapeExpand(buf, appData.secondComputerString);
1742 appData.secondComputerString = strdup(buf);
1745 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1748 if (chdir(chessDir) != 0) {
1749 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1755 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1756 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1757 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1758 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1761 setbuf(debugFP, NULL);
1764 /* [HGM,HR] make sure board size is acceptable */
1765 if(appData.NrFiles > BOARD_FILES ||
1766 appData.NrRanks > BOARD_RANKS )
1767 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1770 /* This feature does not work; animation needs a rewrite */
1771 appData.highlightDragging = FALSE;
1775 xDisplay = XtDisplay(shellWidget);
1776 xScreen = DefaultScreen(xDisplay);
1777 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1779 gameInfo.variant = StringToVariant(appData.variant);
1780 InitPosition(FALSE);
1783 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1785 if (isdigit(appData.boardSize[0])) {
1786 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1787 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1788 &fontPxlSize, &smallLayout, &tinyLayout);
1790 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1791 programName, appData.boardSize);
1795 /* Find some defaults; use the nearest known size */
1796 SizeDefaults *szd, *nearest;
1797 int distance = 99999;
1798 nearest = szd = sizeDefaults;
1799 while (szd->name != NULL) {
1800 if (abs(szd->squareSize - squareSize) < distance) {
1802 distance = abs(szd->squareSize - squareSize);
1803 if (distance == 0) break;
1807 if (i < 2) lineGap = nearest->lineGap;
1808 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1809 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1810 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1811 if (i < 6) smallLayout = nearest->smallLayout;
1812 if (i < 7) tinyLayout = nearest->tinyLayout;
1815 SizeDefaults *szd = sizeDefaults;
1816 if (*appData.boardSize == NULLCHAR) {
1817 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1818 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1821 if (szd->name == NULL) szd--;
1822 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1824 while (szd->name != NULL &&
1825 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1826 if (szd->name == NULL) {
1827 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1828 programName, appData.boardSize);
1832 squareSize = szd->squareSize;
1833 lineGap = szd->lineGap;
1834 clockFontPxlSize = szd->clockFontPxlSize;
1835 coordFontPxlSize = szd->coordFontPxlSize;
1836 fontPxlSize = szd->fontPxlSize;
1837 smallLayout = szd->smallLayout;
1838 tinyLayout = szd->tinyLayout;
1841 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1842 if (strlen(appData.pixmapDirectory) > 0) {
1843 p = ExpandPathName(appData.pixmapDirectory);
1845 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1846 appData.pixmapDirectory);
1849 if (appData.debugMode) {
1850 fprintf(stderr, _("\
1851 XBoard square size (hint): %d\n\
1852 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1854 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1855 if (appData.debugMode) {
1856 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1860 /* [HR] height treated separately (hacked) */
1861 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1862 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1863 if (appData.showJail == 1) {
1864 /* Jail on top and bottom */
1865 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1866 XtSetArg(boardArgs[2], XtNheight,
1867 boardHeight + 2*(lineGap + squareSize));
1868 } else if (appData.showJail == 2) {
1870 XtSetArg(boardArgs[1], XtNwidth,
1871 boardWidth + 2*(lineGap + squareSize));
1872 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1875 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1876 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1880 * Determine what fonts to use.
1882 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1883 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1884 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1885 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1886 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1887 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1888 appData.font = FindFont(appData.font, fontPxlSize);
1889 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1890 countFontStruct = XQueryFont(xDisplay, countFontID);
1891 // appData.font = FindFont(appData.font, fontPxlSize);
1893 xdb = XtDatabase(xDisplay);
1894 XrmPutStringResource(&xdb, "*font", appData.font);
1897 * Detect if there are not enough colors available and adapt.
1899 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1900 appData.monoMode = True;
1903 if (!appData.monoMode) {
1904 vFrom.addr = (caddr_t) appData.lightSquareColor;
1905 vFrom.size = strlen(appData.lightSquareColor);
1906 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1907 if (vTo.addr == NULL) {
1908 appData.monoMode = True;
1911 lightSquareColor = *(Pixel *) vTo.addr;
1914 if (!appData.monoMode) {
1915 vFrom.addr = (caddr_t) appData.darkSquareColor;
1916 vFrom.size = strlen(appData.darkSquareColor);
1917 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1918 if (vTo.addr == NULL) {
1919 appData.monoMode = True;
1922 darkSquareColor = *(Pixel *) vTo.addr;
1925 if (!appData.monoMode) {
1926 vFrom.addr = (caddr_t) appData.whitePieceColor;
1927 vFrom.size = strlen(appData.whitePieceColor);
1928 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1929 if (vTo.addr == NULL) {
1930 appData.monoMode = True;
1933 whitePieceColor = *(Pixel *) vTo.addr;
1936 if (!appData.monoMode) {
1937 vFrom.addr = (caddr_t) appData.blackPieceColor;
1938 vFrom.size = strlen(appData.blackPieceColor);
1939 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1940 if (vTo.addr == NULL) {
1941 appData.monoMode = True;
1944 blackPieceColor = *(Pixel *) vTo.addr;
1948 if (!appData.monoMode) {
1949 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1950 vFrom.size = strlen(appData.highlightSquareColor);
1951 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1952 if (vTo.addr == NULL) {
1953 appData.monoMode = True;
1956 highlightSquareColor = *(Pixel *) vTo.addr;
1960 if (!appData.monoMode) {
1961 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1962 vFrom.size = strlen(appData.premoveHighlightColor);
1963 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1964 if (vTo.addr == NULL) {
1965 appData.monoMode = True;
1968 premoveHighlightColor = *(Pixel *) vTo.addr;
1973 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1976 if (appData.bitmapDirectory == NULL ||
1977 appData.bitmapDirectory[0] == NULLCHAR)
1978 appData.bitmapDirectory = DEF_BITMAP_DIR;
1981 if (appData.lowTimeWarning && !appData.monoMode) {
1982 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1983 vFrom.size = strlen(appData.lowTimeWarningColor);
1984 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1985 if (vTo.addr == NULL)
1986 appData.monoMode = True;
1988 lowTimeWarningColor = *(Pixel *) vTo.addr;
1991 if (appData.monoMode && appData.debugMode) {
1992 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1993 (unsigned long) XWhitePixel(xDisplay, xScreen),
1994 (unsigned long) XBlackPixel(xDisplay, xScreen));
1997 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1998 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1999 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2000 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2001 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2002 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2003 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2004 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2005 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2006 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2008 if (appData.colorize) {
2010 _("%s: can't parse color names; disabling colorization\n"),
2013 appData.colorize = FALSE;
2015 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2016 textColors[ColorNone].attr = 0;
2018 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2024 layoutName = "tinyLayout";
2025 } else if (smallLayout) {
2026 layoutName = "smallLayout";
2028 layoutName = "normalLayout";
2030 /* Outer layoutWidget is there only to provide a name for use in
2031 resources that depend on the layout style */
2033 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2034 layoutArgs, XtNumber(layoutArgs));
2036 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2037 formArgs, XtNumber(formArgs));
2038 XtSetArg(args[0], XtNdefaultDistance, &sep);
2039 XtGetValues(formWidget, args, 1);
2042 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2043 XtSetArg(args[0], XtNtop, XtChainTop);
2044 XtSetArg(args[1], XtNbottom, XtChainTop);
2045 XtSetArg(args[2], XtNright, XtChainLeft);
2046 XtSetValues(menuBarWidget, args, 3);
2048 widgetList[j++] = whiteTimerWidget =
2049 XtCreateWidget("whiteTime", labelWidgetClass,
2050 formWidget, timerArgs, XtNumber(timerArgs));
2051 XtSetArg(args[0], XtNfont, clockFontStruct);
2052 XtSetArg(args[1], XtNtop, XtChainTop);
2053 XtSetArg(args[2], XtNbottom, XtChainTop);
2054 XtSetValues(whiteTimerWidget, args, 3);
2056 widgetList[j++] = blackTimerWidget =
2057 XtCreateWidget("blackTime", labelWidgetClass,
2058 formWidget, timerArgs, XtNumber(timerArgs));
2059 XtSetArg(args[0], XtNfont, clockFontStruct);
2060 XtSetArg(args[1], XtNtop, XtChainTop);
2061 XtSetArg(args[2], XtNbottom, XtChainTop);
2062 XtSetValues(blackTimerWidget, args, 3);
2064 if (appData.titleInWindow) {
2065 widgetList[j++] = titleWidget =
2066 XtCreateWidget("title", labelWidgetClass, formWidget,
2067 titleArgs, XtNumber(titleArgs));
2068 XtSetArg(args[0], XtNtop, XtChainTop);
2069 XtSetArg(args[1], XtNbottom, XtChainTop);
2070 XtSetValues(titleWidget, args, 2);
2073 if (appData.showButtonBar) {
2074 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2075 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2076 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2077 XtSetArg(args[2], XtNtop, XtChainTop);
2078 XtSetArg(args[3], XtNbottom, XtChainTop);
2079 XtSetValues(buttonBarWidget, args, 4);
2082 widgetList[j++] = messageWidget =
2083 XtCreateWidget("message", labelWidgetClass, formWidget,
2084 messageArgs, XtNumber(messageArgs));
2085 XtSetArg(args[0], XtNtop, XtChainTop);
2086 XtSetArg(args[1], XtNbottom, XtChainTop);
2087 XtSetValues(messageWidget, args, 2);
2089 widgetList[j++] = boardWidget =
2090 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2091 XtNumber(boardArgs));
2093 XtManageChildren(widgetList, j);
2095 timerWidth = (boardWidth - sep) / 2;
2096 XtSetArg(args[0], XtNwidth, timerWidth);
2097 XtSetValues(whiteTimerWidget, args, 1);
2098 XtSetValues(blackTimerWidget, args, 1);
2100 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2101 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2102 XtGetValues(whiteTimerWidget, args, 2);
2104 if (appData.showButtonBar) {
2105 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2106 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2107 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2111 * formWidget uses these constraints but they are stored
2115 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2116 XtSetValues(menuBarWidget, args, i);
2117 if (appData.titleInWindow) {
2120 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2121 XtSetValues(whiteTimerWidget, args, i);
2123 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2124 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2125 XtSetValues(blackTimerWidget, args, i);
2127 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2128 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2129 XtSetValues(titleWidget, args, i);
2131 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2132 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2133 XtSetValues(messageWidget, args, i);
2134 if (appData.showButtonBar) {
2136 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2137 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2138 XtSetValues(buttonBarWidget, args, i);
2142 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2143 XtSetValues(whiteTimerWidget, args, i);
2145 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2146 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2147 XtSetValues(blackTimerWidget, args, i);
2149 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2150 XtSetValues(titleWidget, args, i);
2152 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2153 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2154 XtSetValues(messageWidget, args, i);
2155 if (appData.showButtonBar) {
2157 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2158 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2159 XtSetValues(buttonBarWidget, args, i);
2164 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2165 XtSetValues(whiteTimerWidget, args, i);
2167 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2168 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2169 XtSetValues(blackTimerWidget, args, i);
2171 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2172 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2173 XtSetValues(messageWidget, args, i);
2174 if (appData.showButtonBar) {
2176 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2177 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2178 XtSetValues(buttonBarWidget, args, i);
2182 XtSetArg(args[0], XtNfromVert, messageWidget);
2183 XtSetArg(args[1], XtNtop, XtChainTop);
2184 XtSetArg(args[2], XtNbottom, XtChainBottom);
2185 XtSetArg(args[3], XtNleft, XtChainLeft);
2186 XtSetArg(args[4], XtNright, XtChainRight);
2187 XtSetValues(boardWidget, args, 5);
2189 XtRealizeWidget(shellWidget);
2192 XtSetArg(args[0], XtNx, wpMain.x);
2193 XtSetArg(args[1], XtNy, wpMain.y);
2194 XtSetValues(shellWidget, args, 2);
2198 * Correct the width of the message and title widgets.
2199 * It is not known why some systems need the extra fudge term.
2200 * The value "2" is probably larger than needed.
2202 XawFormDoLayout(formWidget, False);
2204 #define WIDTH_FUDGE 2
2206 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2207 XtSetArg(args[i], XtNheight, &h); i++;
2208 XtGetValues(messageWidget, args, i);
2209 if (appData.showButtonBar) {
2211 XtSetArg(args[i], XtNwidth, &w); i++;
2212 XtGetValues(buttonBarWidget, args, i);
2213 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2215 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2218 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2219 if (gres != XtGeometryYes && appData.debugMode) {
2220 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2221 programName, gres, w, h, wr, hr);
2224 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2225 /* The size used for the child widget in layout lags one resize behind
2226 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2228 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2229 if (gres != XtGeometryYes && appData.debugMode) {
2230 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2231 programName, gres, w, h, wr, hr);
2234 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2235 XtSetArg(args[1], XtNright, XtChainRight);
2236 XtSetValues(messageWidget, args, 2);
2238 if (appData.titleInWindow) {
2240 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2241 XtSetArg(args[i], XtNheight, &h); i++;
2242 XtGetValues(titleWidget, args, i);
2244 w = boardWidth - 2*bor;
2246 XtSetArg(args[0], XtNwidth, &w);
2247 XtGetValues(menuBarWidget, args, 1);
2248 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2251 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2252 if (gres != XtGeometryYes && appData.debugMode) {
2254 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2255 programName, gres, w, h, wr, hr);
2258 XawFormDoLayout(formWidget, True);
2260 xBoardWindow = XtWindow(boardWidget);
2262 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2263 // not need to go into InitDrawingSizes().
2267 * Create X checkmark bitmap and initialize option menu checks.
2269 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2270 checkmark_bits, checkmark_width, checkmark_height);
2271 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2272 if (appData.alwaysPromoteToQueen) {
2273 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2276 if (appData.animateDragging) {
2277 XtSetValues(XtNameToWidget(menuBarWidget,
2278 "menuOptions.Animate Dragging"),
2281 if (appData.animate) {
2282 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2285 if (appData.autoComment) {
2286 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2289 if (appData.autoCallFlag) {
2290 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2293 if (appData.autoFlipView) {
2294 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2297 if (appData.autoObserve) {
2298 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2301 if (appData.autoRaiseBoard) {
2302 XtSetValues(XtNameToWidget(menuBarWidget,
2303 "menuOptions.Auto Raise Board"), args, 1);
2305 if (appData.autoSaveGames) {
2306 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2309 if (appData.saveGameFile[0] != NULLCHAR) {
2310 /* Can't turn this off from menu */
2311 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2313 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2317 if (appData.blindfold) {
2318 XtSetValues(XtNameToWidget(menuBarWidget,
2319 "menuOptions.Blindfold"), args, 1);
2321 if (appData.flashCount > 0) {
2322 XtSetValues(XtNameToWidget(menuBarWidget,
2323 "menuOptions.Flash Moves"),
2326 if (appData.getMoveList) {
2327 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2331 if (appData.highlightDragging) {
2332 XtSetValues(XtNameToWidget(menuBarWidget,
2333 "menuOptions.Highlight Dragging"),
2337 if (appData.highlightLastMove) {
2338 XtSetValues(XtNameToWidget(menuBarWidget,
2339 "menuOptions.Highlight Last Move"),
2342 if (appData.icsAlarm) {
2343 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2346 if (appData.ringBellAfterMoves) {
2347 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2350 if (appData.oldSaveStyle) {
2351 XtSetValues(XtNameToWidget(menuBarWidget,
2352 "menuOptions.Old Save Style"), args, 1);
2354 if (appData.periodicUpdates) {
2355 XtSetValues(XtNameToWidget(menuBarWidget,
2356 "menuOptions.Periodic Updates"), args, 1);
2358 if (appData.ponderNextMove) {
2359 XtSetValues(XtNameToWidget(menuBarWidget,
2360 "menuOptions.Ponder Next Move"), args, 1);
2362 if (appData.popupExitMessage) {
2363 XtSetValues(XtNameToWidget(menuBarWidget,
2364 "menuOptions.Popup Exit Message"), args, 1);
2366 if (appData.popupMoveErrors) {
2367 XtSetValues(XtNameToWidget(menuBarWidget,
2368 "menuOptions.Popup Move Errors"), args, 1);
2370 if (appData.premove) {
2371 XtSetValues(XtNameToWidget(menuBarWidget,
2372 "menuOptions.Premove"), args, 1);
2374 if (appData.quietPlay) {
2375 XtSetValues(XtNameToWidget(menuBarWidget,
2376 "menuOptions.Quiet Play"), args, 1);
2378 if (appData.showCoords) {
2379 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2382 if (appData.hideThinkingFromHuman) {
2383 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2386 if (appData.testLegality) {
2387 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2390 if (saveSettingsOnExit) {
2391 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2398 ReadBitmap(&wIconPixmap, "icon_white.bm",
2399 icon_white_bits, icon_white_width, icon_white_height);
2400 ReadBitmap(&bIconPixmap, "icon_black.bm",
2401 icon_black_bits, icon_black_width, icon_black_height);
2402 iconPixmap = wIconPixmap;
2404 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2405 XtSetValues(shellWidget, args, i);
2408 * Create a cursor for the board widget.
2410 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2411 XChangeWindowAttributes(xDisplay, xBoardWindow,
2412 CWCursor, &window_attributes);
2415 * Inhibit shell resizing.
2417 shellArgs[0].value = (XtArgVal) &w;
2418 shellArgs[1].value = (XtArgVal) &h;
2419 XtGetValues(shellWidget, shellArgs, 2);
2420 shellArgs[4].value = shellArgs[2].value = w;
2421 shellArgs[5].value = shellArgs[3].value = h;
2422 XtSetValues(shellWidget, &shellArgs[2], 4);
2423 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2424 marginH = h - boardHeight;
2426 CatchDeleteWindow(shellWidget, "QuitProc");
2431 if (appData.bitmapDirectory[0] != NULLCHAR) {
2438 /* Create regular pieces */
2439 if (!useImages) CreatePieces();
2444 if (appData.animate || appData.animateDragging)
2447 XtAugmentTranslations(formWidget,
2448 XtParseTranslationTable(globalTranslations));
2449 XtAugmentTranslations(boardWidget,
2450 XtParseTranslationTable(boardTranslations));
2451 XtAugmentTranslations(whiteTimerWidget,
2452 XtParseTranslationTable(whiteTranslations));
2453 XtAugmentTranslations(blackTimerWidget,
2454 XtParseTranslationTable(blackTranslations));
2456 /* Why is the following needed on some versions of X instead
2457 * of a translation? */
2458 XtAddEventHandler(boardWidget, ExposureMask, False,
2459 (XtEventHandler) EventProc, NULL);
2462 /* [AS] Restore layout */
2463 if( wpMoveHistory.visible ) {
2467 if( wpEvalGraph.visible )
2472 if( wpEngineOutput.visible ) {
2473 EngineOutputPopUp();
2478 if (errorExitStatus == -1) {
2479 if (appData.icsActive) {
2480 /* We now wait until we see "login:" from the ICS before
2481 sending the logon script (problems with timestamp otherwise) */
2482 /*ICSInitScript();*/
2483 if (appData.icsInputBox) ICSInputBoxPopUp();
2487 signal(SIGWINCH, TermSizeSigHandler);
2489 signal(SIGINT, IntSigHandler);
2490 signal(SIGTERM, IntSigHandler);
2491 if (*appData.cmailGameName != NULLCHAR) {
2492 signal(SIGUSR1, CmailSigHandler);
2495 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2498 XtAppMainLoop(appContext);
2499 if (appData.debugMode) fclose(debugFP); // [DM] debug
2506 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2507 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2509 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2510 unlink(gameCopyFilename);
2511 unlink(gamePasteFilename);
2514 RETSIGTYPE TermSizeSigHandler(int sig)
2527 CmailSigHandler(sig)
2533 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2535 /* Activate call-back function CmailSigHandlerCallBack() */
2536 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2538 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2542 CmailSigHandlerCallBack(isr, closure, message, count, error)
2550 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2552 /**** end signal code ****/
2562 f = fopen(appData.icsLogon, "r");
2568 strcat(buf, appData.icsLogon);
2569 f = fopen(buf, "r");
2573 ProcessICSInitScript(f);
2580 EditCommentPopDown();
2595 if (!menuBarWidget) return;
2596 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2598 DisplayError("menuStep.Revert", 0);
2600 XtSetSensitive(w, !grey);
2605 SetMenuEnables(enab)
2609 if (!menuBarWidget) return;
2610 while (enab->name != NULL) {
2611 w = XtNameToWidget(menuBarWidget, enab->name);
2613 DisplayError(enab->name, 0);
2615 XtSetSensitive(w, enab->value);
2621 Enables icsEnables[] = {
2622 { "menuFile.Mail Move", False },
2623 { "menuFile.Reload CMail Message", False },
2624 { "menuMode.Machine Black", False },
2625 { "menuMode.Machine White", False },
2626 { "menuMode.Analysis Mode", False },
2627 { "menuMode.Analyze File", False },
2628 { "menuMode.Two Machines", False },
2630 { "menuHelp.Hint", False },
2631 { "menuHelp.Book", False },
2632 { "menuStep.Move Now", False },
2633 { "menuOptions.Periodic Updates", False },
2634 { "menuOptions.Hide Thinking", False },
2635 { "menuOptions.Ponder Next Move", False },
2640 Enables ncpEnables[] = {
2641 { "menuFile.Mail Move", False },
2642 { "menuFile.Reload CMail Message", False },
2643 { "menuMode.Machine White", False },
2644 { "menuMode.Machine Black", False },
2645 { "menuMode.Analysis Mode", False },
2646 { "menuMode.Analyze File", False },
2647 { "menuMode.Two Machines", False },
2648 { "menuMode.ICS Client", False },
2649 { "menuMode.ICS Input Box", False },
2650 { "Action", False },
2651 { "menuStep.Revert", False },
2652 { "menuStep.Move Now", False },
2653 { "menuStep.Retract Move", False },
2654 { "menuOptions.Auto Comment", False },
2655 { "menuOptions.Auto Flag", False },
2656 { "menuOptions.Auto Flip View", False },
2657 { "menuOptions.Auto Observe", False },
2658 { "menuOptions.Auto Raise Board", False },
2659 { "menuOptions.Get Move List", False },
2660 { "menuOptions.ICS Alarm", False },
2661 { "menuOptions.Move Sound", False },
2662 { "menuOptions.Quiet Play", False },
2663 { "menuOptions.Hide Thinking", False },
2664 { "menuOptions.Periodic Updates", False },
2665 { "menuOptions.Ponder Next Move", False },
2666 { "menuHelp.Hint", False },
2667 { "menuHelp.Book", False },
2671 Enables gnuEnables[] = {
2672 { "menuMode.ICS Client", False },
2673 { "menuMode.ICS Input Box", False },
2674 { "menuAction.Accept", False },
2675 { "menuAction.Decline", False },
2676 { "menuAction.Rematch", False },
2677 { "menuAction.Adjourn", False },
2678 { "menuAction.Stop Examining", False },
2679 { "menuAction.Stop Observing", False },
2680 { "menuStep.Revert", False },
2681 { "menuOptions.Auto Comment", False },
2682 { "menuOptions.Auto Observe", False },
2683 { "menuOptions.Auto Raise Board", False },
2684 { "menuOptions.Get Move List", False },
2685 { "menuOptions.Premove", False },
2686 { "menuOptions.Quiet Play", False },
2688 /* The next two options rely on SetCmailMode being called *after* */
2689 /* SetGNUMode so that when GNU is being used to give hints these */
2690 /* menu options are still available */
2692 { "menuFile.Mail Move", False },
2693 { "menuFile.Reload CMail Message", False },
2697 Enables cmailEnables[] = {
2699 { "menuAction.Call Flag", False },
2700 { "menuAction.Draw", True },
2701 { "menuAction.Adjourn", False },
2702 { "menuAction.Abort", False },
2703 { "menuAction.Stop Observing", False },
2704 { "menuAction.Stop Examining", False },
2705 { "menuFile.Mail Move", True },
2706 { "menuFile.Reload CMail Message", True },
2710 Enables trainingOnEnables[] = {
2711 { "menuMode.Edit Comment", False },
2712 { "menuMode.Pause", False },
2713 { "menuStep.Forward", False },
2714 { "menuStep.Backward", False },
2715 { "menuStep.Forward to End", False },
2716 { "menuStep.Back to Start", False },
2717 { "menuStep.Move Now", False },
2718 { "menuStep.Truncate Game", False },
2722 Enables trainingOffEnables[] = {
2723 { "menuMode.Edit Comment", True },
2724 { "menuMode.Pause", True },
2725 { "menuStep.Forward", True },
2726 { "menuStep.Backward", True },
2727 { "menuStep.Forward to End", True },
2728 { "menuStep.Back to Start", True },
2729 { "menuStep.Move Now", True },
2730 { "menuStep.Truncate Game", True },
2734 Enables machineThinkingEnables[] = {
2735 { "menuFile.Load Game", False },
2736 { "menuFile.Load Next Game", False },
2737 { "menuFile.Load Previous Game", False },
2738 { "menuFile.Reload Same Game", False },
2739 { "menuFile.Paste Game", False },
2740 { "menuFile.Load Position", False },
2741 { "menuFile.Load Next Position", False },
2742 { "menuFile.Load Previous Position", False },
2743 { "menuFile.Reload Same Position", False },
2744 { "menuFile.Paste Position", False },
2745 { "menuMode.Machine White", False },
2746 { "menuMode.Machine Black", False },
2747 { "menuMode.Two Machines", False },
2748 { "menuStep.Retract Move", False },
2752 Enables userThinkingEnables[] = {
2753 { "menuFile.Load Game", True },
2754 { "menuFile.Load Next Game", True },
2755 { "menuFile.Load Previous Game", True },
2756 { "menuFile.Reload Same Game", True },
2757 { "menuFile.Paste Game", True },
2758 { "menuFile.Load Position", True },
2759 { "menuFile.Load Next Position", True },
2760 { "menuFile.Load Previous Position", True },
2761 { "menuFile.Reload Same Position", True },
2762 { "menuFile.Paste Position", True },
2763 { "menuMode.Machine White", True },
2764 { "menuMode.Machine Black", True },
2765 { "menuMode.Two Machines", True },
2766 { "menuStep.Retract Move", True },
2772 SetMenuEnables(icsEnables);
2775 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2776 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2783 SetMenuEnables(ncpEnables);
2789 SetMenuEnables(gnuEnables);
2795 SetMenuEnables(cmailEnables);
2801 SetMenuEnables(trainingOnEnables);
2802 if (appData.showButtonBar) {
2803 XtSetSensitive(buttonBarWidget, False);
2809 SetTrainingModeOff()
2811 SetMenuEnables(trainingOffEnables);
2812 if (appData.showButtonBar) {
2813 XtSetSensitive(buttonBarWidget, True);
2818 SetUserThinkingEnables()
2820 if (appData.noChessProgram) return;
2821 SetMenuEnables(userThinkingEnables);
2825 SetMachineThinkingEnables()
2827 if (appData.noChessProgram) return;
2828 SetMenuEnables(machineThinkingEnables);
2830 case MachinePlaysBlack:
2831 case MachinePlaysWhite:
2832 case TwoMachinesPlay:
2833 XtSetSensitive(XtNameToWidget(menuBarWidget,
2834 ModeToWidgetName(gameMode)), True);
2841 #define Abs(n) ((n)<0 ? -(n) : (n))
2844 * Find a font that matches "pattern" that is as close as
2845 * possible to the targetPxlSize. Prefer fonts that are k
2846 * pixels smaller to fonts that are k pixels larger. The
2847 * pattern must be in the X Consortium standard format,
2848 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2849 * The return value should be freed with XtFree when no
2852 char *FindFont(pattern, targetPxlSize)
2856 char **fonts, *p, *best, *scalable, *scalableTail;
2857 int i, j, nfonts, minerr, err, pxlSize;
2860 char **missing_list;
2862 char *def_string, *base_fnt_lst, strInt[3];
2864 XFontStruct **fnt_list;
2866 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2867 sprintf(strInt, "%d", targetPxlSize);
2868 p = strstr(pattern, "--");
2869 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2870 strcat(base_fnt_lst, strInt);
2871 strcat(base_fnt_lst, strchr(p + 2, '-'));
2873 if ((fntSet = XCreateFontSet(xDisplay,
2877 &def_string)) == NULL) {
2879 fprintf(stderr, _("Unable to create font set.\n"));
2883 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2885 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2887 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2888 programName, pattern);
2896 for (i=0; i<nfonts; i++) {
2899 if (*p != '-') continue;
2901 if (*p == NULLCHAR) break;
2902 if (*p++ == '-') j++;
2904 if (j < 7) continue;
2907 scalable = fonts[i];
2910 err = pxlSize - targetPxlSize;
2911 if (Abs(err) < Abs(minerr) ||
2912 (minerr > 0 && err < 0 && -err == minerr)) {
2918 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2919 /* If the error is too big and there is a scalable font,
2920 use the scalable font. */
2921 int headlen = scalableTail - scalable;
2922 p = (char *) XtMalloc(strlen(scalable) + 10);
2923 while (isdigit(*scalableTail)) scalableTail++;
2924 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2926 p = (char *) XtMalloc(strlen(best) + 1);
2929 if (appData.debugMode) {
2930 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2931 pattern, targetPxlSize, p);
2934 if (missing_count > 0)
2935 XFreeStringList(missing_list);
2936 XFreeFontSet(xDisplay, fntSet);
2938 XFreeFontNames(fonts);
2945 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2946 | GCBackground | GCFunction | GCPlaneMask;
2947 XGCValues gc_values;
2950 gc_values.plane_mask = AllPlanes;
2951 gc_values.line_width = lineGap;
2952 gc_values.line_style = LineSolid;
2953 gc_values.function = GXcopy;
2955 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2956 gc_values.background = XBlackPixel(xDisplay, xScreen);
2957 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2959 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2960 gc_values.background = XWhitePixel(xDisplay, xScreen);
2961 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2962 XSetFont(xDisplay, coordGC, coordFontID);
2964 // [HGM] make font for holdings counts (white on black0
2965 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2966 gc_values.background = XBlackPixel(xDisplay, xScreen);
2967 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2968 XSetFont(xDisplay, countGC, countFontID);
2970 if (appData.monoMode) {
2971 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2972 gc_values.background = XWhitePixel(xDisplay, xScreen);
2973 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2975 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2976 gc_values.background = XBlackPixel(xDisplay, xScreen);
2977 lightSquareGC = wbPieceGC
2978 = XtGetGC(shellWidget, value_mask, &gc_values);
2980 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2981 gc_values.background = XWhitePixel(xDisplay, xScreen);
2982 darkSquareGC = bwPieceGC
2983 = XtGetGC(shellWidget, value_mask, &gc_values);
2985 if (DefaultDepth(xDisplay, xScreen) == 1) {
2986 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2987 gc_values.function = GXcopyInverted;
2988 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2989 gc_values.function = GXcopy;
2990 if (XBlackPixel(xDisplay, xScreen) == 1) {
2991 bwPieceGC = darkSquareGC;
2992 wbPieceGC = copyInvertedGC;
2994 bwPieceGC = copyInvertedGC;
2995 wbPieceGC = lightSquareGC;
2999 gc_values.foreground = highlightSquareColor;
3000 gc_values.background = highlightSquareColor;
3001 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3003 gc_values.foreground = premoveHighlightColor;
3004 gc_values.background = premoveHighlightColor;
3005 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3007 gc_values.foreground = lightSquareColor;
3008 gc_values.background = darkSquareColor;
3009 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3011 gc_values.foreground = darkSquareColor;
3012 gc_values.background = lightSquareColor;
3013 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3015 gc_values.foreground = jailSquareColor;
3016 gc_values.background = jailSquareColor;
3017 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3019 gc_values.foreground = whitePieceColor;
3020 gc_values.background = darkSquareColor;
3021 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3023 gc_values.foreground = whitePieceColor;
3024 gc_values.background = lightSquareColor;
3025 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3027 gc_values.foreground = whitePieceColor;
3028 gc_values.background = jailSquareColor;
3029 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3031 gc_values.foreground = blackPieceColor;
3032 gc_values.background = darkSquareColor;
3033 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3035 gc_values.foreground = blackPieceColor;
3036 gc_values.background = lightSquareColor;
3037 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3039 gc_values.foreground = blackPieceColor;
3040 gc_values.background = jailSquareColor;
3041 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3045 void loadXIM(xim, xmask, filename, dest, mask)
3058 fp = fopen(filename, "rb");
3060 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3067 for (y=0; y<h; ++y) {
3068 for (x=0; x<h; ++x) {
3073 XPutPixel(xim, x, y, blackPieceColor);
3075 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3078 XPutPixel(xim, x, y, darkSquareColor);
3080 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3083 XPutPixel(xim, x, y, whitePieceColor);
3085 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3088 XPutPixel(xim, x, y, lightSquareColor);
3090 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3096 /* create Pixmap of piece */
3097 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3099 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3102 /* create Pixmap of clipmask
3103 Note: We assume the white/black pieces have the same
3104 outline, so we make only 6 masks. This is okay
3105 since the XPM clipmask routines do the same. */
3107 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3109 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3112 /* now create the 1-bit version */
3113 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3116 values.foreground = 1;
3117 values.background = 0;
3119 /* Don't use XtGetGC, not read only */
3120 maskGC = XCreateGC(xDisplay, *mask,
3121 GCForeground | GCBackground, &values);
3122 XCopyPlane(xDisplay, temp, *mask, maskGC,
3123 0, 0, squareSize, squareSize, 0, 0, 1);
3124 XFreePixmap(xDisplay, temp);
3129 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3131 void CreateXIMPieces()
3136 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3141 /* The XSynchronize calls were copied from CreatePieces.
3142 Not sure if needed, but can't hurt */
3143 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3146 /* temp needed by loadXIM() */
3147 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3148 0, 0, ss, ss, AllPlanes, XYPixmap);
3150 if (strlen(appData.pixmapDirectory) == 0) {
3154 if (appData.monoMode) {
3155 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3159 fprintf(stderr, _("\nLoading XIMs...\n"));
3161 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3162 fprintf(stderr, "%d", piece+1);
3163 for (kind=0; kind<4; kind++) {
3164 fprintf(stderr, ".");
3165 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3166 ExpandPathName(appData.pixmapDirectory),
3167 piece <= (int) WhiteKing ? "" : "w",
3168 pieceBitmapNames[piece],
3170 ximPieceBitmap[kind][piece] =
3171 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3172 0, 0, ss, ss, AllPlanes, XYPixmap);
3173 if (appData.debugMode)
3174 fprintf(stderr, _("(File:%s:) "), buf);
3175 loadXIM(ximPieceBitmap[kind][piece],
3177 &(xpmPieceBitmap2[kind][piece]),
3178 &(ximMaskPm2[piece]));
3179 if(piece <= (int)WhiteKing)
3180 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3182 fprintf(stderr," ");
3184 /* Load light and dark squares */
3185 /* If the LSQ and DSQ pieces don't exist, we will
3186 draw them with solid squares. */
3187 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3188 if (access(buf, 0) != 0) {
3192 fprintf(stderr, _("light square "));
3194 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3195 0, 0, ss, ss, AllPlanes, XYPixmap);
3196 if (appData.debugMode)
3197 fprintf(stderr, _("(File:%s:) "), buf);
3199 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3200 fprintf(stderr, _("dark square "));
3201 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3202 ExpandPathName(appData.pixmapDirectory), ss);
3203 if (appData.debugMode)
3204 fprintf(stderr, _("(File:%s:) "), buf);
3206 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3207 0, 0, ss, ss, AllPlanes, XYPixmap);
3208 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3209 xpmJailSquare = xpmLightSquare;
3211 fprintf(stderr, _("Done.\n"));
3213 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3217 void CreateXPMPieces()
3221 u_int ss = squareSize;
3223 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3224 XpmColorSymbol symbols[4];
3226 /* The XSynchronize calls were copied from CreatePieces.
3227 Not sure if needed, but can't hurt */
3228 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3230 /* Setup translations so piece colors match square colors */
3231 symbols[0].name = "light_piece";
3232 symbols[0].value = appData.whitePieceColor;
3233 symbols[1].name = "dark_piece";
3234 symbols[1].value = appData.blackPieceColor;
3235 symbols[2].name = "light_square";
3236 symbols[2].value = appData.lightSquareColor;
3237 symbols[3].name = "dark_square";
3238 symbols[3].value = appData.darkSquareColor;
3240 attr.valuemask = XpmColorSymbols;
3241 attr.colorsymbols = symbols;
3242 attr.numsymbols = 4;
3244 if (appData.monoMode) {
3245 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3249 if (strlen(appData.pixmapDirectory) == 0) {
3250 XpmPieces* pieces = builtInXpms;
3253 while (pieces->size != squareSize && pieces->size) pieces++;
3254 if (!pieces->size) {
3255 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3258 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3259 for (kind=0; kind<4; kind++) {
3261 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3262 pieces->xpm[piece][kind],
3263 &(xpmPieceBitmap2[kind][piece]),
3264 NULL, &attr)) != 0) {
3265 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3269 if(piece <= (int) WhiteKing)
3270 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3274 xpmJailSquare = xpmLightSquare;
3278 fprintf(stderr, _("\nLoading XPMs...\n"));
3281 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3282 fprintf(stderr, "%d ", piece+1);
3283 for (kind=0; kind<4; kind++) {
3284 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3285 ExpandPathName(appData.pixmapDirectory),
3286 piece > (int) WhiteKing ? "w" : "",
3287 pieceBitmapNames[piece],
3289 if (appData.debugMode) {
3290 fprintf(stderr, _("(File:%s:) "), buf);
3292 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3293 &(xpmPieceBitmap2[kind][piece]),
3294 NULL, &attr)) != 0) {
3295 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3296 // [HGM] missing: read of unorthodox piece failed; substitute King.
3297 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3298 ExpandPathName(appData.pixmapDirectory),
3300 if (appData.debugMode) {
3301 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3303 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3304 &(xpmPieceBitmap2[kind][piece]),
3308 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3313 if(piece <= (int) WhiteKing)
3314 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3317 /* Load light and dark squares */
3318 /* If the LSQ and DSQ pieces don't exist, we will
3319 draw them with solid squares. */
3320 fprintf(stderr, _("light square "));
3321 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3322 if (access(buf, 0) != 0) {
3326 if (appData.debugMode)
3327 fprintf(stderr, _("(File:%s:) "), buf);
3329 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3330 &xpmLightSquare, NULL, &attr)) != 0) {
3331 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3334 fprintf(stderr, _("dark square "));
3335 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3336 ExpandPathName(appData.pixmapDirectory), ss);
3337 if (appData.debugMode) {
3338 fprintf(stderr, _("(File:%s:) "), buf);
3340 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3341 &xpmDarkSquare, NULL, &attr)) != 0) {
3342 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3346 xpmJailSquare = xpmLightSquare;
3347 fprintf(stderr, _("Done.\n"));
3349 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3352 #endif /* HAVE_LIBXPM */
3355 /* No built-in bitmaps */
3360 u_int ss = squareSize;
3362 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3365 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3366 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3367 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3368 pieceBitmapNames[piece],
3369 ss, kind == SOLID ? 's' : 'o');
3370 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3371 if(piece <= (int)WhiteKing)
3372 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3376 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3380 /* With built-in bitmaps */
3383 BuiltInBits* bib = builtInBits;
3386 u_int ss = squareSize;
3388 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3391 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3393 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3394 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3395 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3396 pieceBitmapNames[piece],
3397 ss, kind == SOLID ? 's' : 'o');
3398 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3399 bib->bits[kind][piece], ss, ss);
3400 if(piece <= (int)WhiteKing)
3401 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3405 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3410 void ReadBitmap(pm, name, bits, wreq, hreq)
3413 unsigned char bits[];
3419 char msg[MSG_SIZ], fullname[MSG_SIZ];
3421 if (*appData.bitmapDirectory != NULLCHAR) {
3422 strcpy(fullname, appData.bitmapDirectory);
3423 strcat(fullname, "/");
3424 strcat(fullname, name);
3425 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3426 &w, &h, pm, &x_hot, &y_hot);
3427 fprintf(stderr, "load %s\n", name);
3428 if (errcode != BitmapSuccess) {
3430 case BitmapOpenFailed:
3431 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3433 case BitmapFileInvalid:
3434 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3436 case BitmapNoMemory:
3437 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3441 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3445 fprintf(stderr, _("%s: %s...using built-in\n"),
3447 } else if (w != wreq || h != hreq) {
3449 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3450 programName, fullname, w, h, wreq, hreq);
3456 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3465 if (lineGap == 0) return;
3467 /* [HR] Split this into 2 loops for non-square boards. */
3469 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3470 gridSegments[i].x1 = 0;
3471 gridSegments[i].x2 =
3472 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3473 gridSegments[i].y1 = gridSegments[i].y2
3474 = lineGap / 2 + (i * (squareSize + lineGap));
3477 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3478 gridSegments[j + i].y1 = 0;
3479 gridSegments[j + i].y2 =
3480 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3481 gridSegments[j + i].x1 = gridSegments[j + i].x2
3482 = lineGap / 2 + (j * (squareSize + lineGap));
3486 static void MenuBarSelect(w, addr, index)
3491 XtActionProc proc = (XtActionProc) addr;
3493 (proc)(NULL, NULL, NULL, NULL);
3496 void CreateMenuBarPopup(parent, name, mb)
3506 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3509 XtSetArg(args[j], XtNleftMargin, 20); j++;
3510 XtSetArg(args[j], XtNrightMargin, 20); j++;
3512 while (mi->string != NULL) {
3513 if (strcmp(mi->string, "----") == 0) {
3514 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3517 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3518 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3520 XtAddCallback(entry, XtNcallback,
3521 (XtCallbackProc) MenuBarSelect,
3522 (caddr_t) mi->proc);
3528 Widget CreateMenuBar(mb)
3532 Widget anchor, menuBar;
3534 char menuName[MSG_SIZ];
3537 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3538 XtSetArg(args[j], XtNvSpace, 0); j++;
3539 XtSetArg(args[j], XtNborderWidth, 0); j++;
3540 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3541 formWidget, args, j);
3543 while (mb->name != NULL) {
3544 strcpy(menuName, "menu");
3545 strcat(menuName, mb->name);
3547 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3550 shortName[0] = _(mb->name)[0];
3551 shortName[1] = NULLCHAR;
3552 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3555 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3558 XtSetArg(args[j], XtNborderWidth, 0); j++;
3559 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3561 CreateMenuBarPopup(menuBar, menuName, mb);
3567 Widget CreateButtonBar(mi)
3571 Widget button, buttonBar;
3575 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3577 XtSetArg(args[j], XtNhSpace, 0); j++;
3579 XtSetArg(args[j], XtNborderWidth, 0); j++;
3580 XtSetArg(args[j], XtNvSpace, 0); j++;
3581 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3582 formWidget, args, j);
3584 while (mi->string != NULL) {
3587 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3588 XtSetArg(args[j], XtNborderWidth, 0); j++;
3590 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3591 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3592 buttonBar, args, j);
3593 XtAddCallback(button, XtNcallback,
3594 (XtCallbackProc) MenuBarSelect,
3595 (caddr_t) mi->proc);
3602 CreatePieceMenu(name, color)
3609 ChessSquare selection;
3611 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3612 boardWidget, args, 0);
3614 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3615 String item = pieceMenuStrings[color][i];
3617 if (strcmp(item, "----") == 0) {
3618 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3621 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3622 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3624 selection = pieceMenuTranslation[color][i];
3625 XtAddCallback(entry, XtNcallback,
3626 (XtCallbackProc) PieceMenuSelect,
3627 (caddr_t) selection);
3628 if (selection == WhitePawn || selection == BlackPawn) {
3629 XtSetArg(args[0], XtNpopupOnEntry, entry);
3630 XtSetValues(menu, args, 1);
3643 ChessSquare selection;
3645 whitePieceMenu = CreatePieceMenu("menuW", 0);
3646 blackPieceMenu = CreatePieceMenu("menuB", 1);
3648 XtRegisterGrabAction(PieceMenuPopup, True,
3649 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3650 GrabModeAsync, GrabModeAsync);
3652 XtSetArg(args[0], XtNlabel, _("Drop"));
3653 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3654 boardWidget, args, 1);
3655 for (i = 0; i < DROP_MENU_SIZE; i++) {
3656 String item = dropMenuStrings[i];
3658 if (strcmp(item, "----") == 0) {
3659 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3662 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3663 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3665 selection = dropMenuTranslation[i];
3666 XtAddCallback(entry, XtNcallback,
3667 (XtCallbackProc) DropMenuSelect,
3668 (caddr_t) selection);
3673 void SetupDropMenu()
3681 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3682 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3683 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3684 dmEnables[i].piece);
3685 XtSetSensitive(entry, p != NULL || !appData.testLegality
3686 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3687 && !appData.icsActive));
3689 while (p && *p++ == dmEnables[i].piece) count++;
3690 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3692 XtSetArg(args[j], XtNlabel, label); j++;
3693 XtSetValues(entry, args, j);
3697 void PieceMenuPopup(w, event, params, num_params)
3701 Cardinal *num_params;
3704 if (event->type != ButtonPress) return;
3705 if (errorUp) ErrorPopDown();
3709 whichMenu = params[0];
3711 case IcsPlayingWhite:
3712 case IcsPlayingBlack:
3714 case MachinePlaysWhite:
3715 case MachinePlaysBlack:
3716 if (appData.testLegality &&
3717 gameInfo.variant != VariantBughouse &&
3718 gameInfo.variant != VariantCrazyhouse) return;
3720 whichMenu = "menuD";
3726 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3727 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3728 pmFromX = pmFromY = -1;
3732 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3734 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3736 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3739 static void PieceMenuSelect(w, piece, junk)
3744 if (pmFromX < 0 || pmFromY < 0) return;
3745 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3748 static void DropMenuSelect(w, piece, junk)
3753 if (pmFromX < 0 || pmFromY < 0) return;
3754 DropMenuEvent(piece, pmFromX, pmFromY);
3757 void WhiteClock(w, event, prms, nprms)
3763 if (gameMode == EditPosition || gameMode == IcsExamining) {
3764 SetWhiteToPlayEvent();
3765 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3770 void BlackClock(w, event, prms, nprms)
3776 if (gameMode == EditPosition || gameMode == IcsExamining) {
3777 SetBlackToPlayEvent();
3778 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3785 * If the user selects on a border boundary, return -1; if off the board,
3786 * return -2. Otherwise map the event coordinate to the square.
3788 int EventToSquare(x, limit)
3796 if ((x % (squareSize + lineGap)) >= squareSize)
3798 x /= (squareSize + lineGap);
3804 static void do_flash_delay(msec)
3810 static void drawHighlight(file, rank, gc)
3816 if (lineGap == 0 || appData.blindfold) return;
3819 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3820 (squareSize + lineGap);
3821 y = lineGap/2 + rank * (squareSize + lineGap);
3823 x = lineGap/2 + file * (squareSize + lineGap);
3824 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3825 (squareSize + lineGap);
3828 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3829 squareSize+lineGap, squareSize+lineGap);
3832 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3833 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3836 SetHighlights(fromX, fromY, toX, toY)
3837 int fromX, fromY, toX, toY;
3839 if (hi1X != fromX || hi1Y != fromY) {
3840 if (hi1X >= 0 && hi1Y >= 0) {
3841 drawHighlight(hi1X, hi1Y, lineGC);
3843 if (fromX >= 0 && fromY >= 0) {
3844 drawHighlight(fromX, fromY, highlineGC);
3847 if (hi2X != toX || hi2Y != toY) {
3848 if (hi2X >= 0 && hi2Y >= 0) {
3849 drawHighlight(hi2X, hi2Y, lineGC);
3851 if (toX >= 0 && toY >= 0) {
3852 drawHighlight(toX, toY, highlineGC);
3864 SetHighlights(-1, -1, -1, -1);
3869 SetPremoveHighlights(fromX, fromY, toX, toY)
3870 int fromX, fromY, toX, toY;
3872 if (pm1X != fromX || pm1Y != fromY) {
3873 if (pm1X >= 0 && pm1Y >= 0) {
3874 drawHighlight(pm1X, pm1Y, lineGC);
3876 if (fromX >= 0 && fromY >= 0) {
3877 drawHighlight(fromX, fromY, prelineGC);
3880 if (pm2X != toX || pm2Y != toY) {
3881 if (pm2X >= 0 && pm2Y >= 0) {
3882 drawHighlight(pm2X, pm2Y, lineGC);
3884 if (toX >= 0 && toY >= 0) {
3885 drawHighlight(toX, toY, prelineGC);
3895 ClearPremoveHighlights()
3897 SetPremoveHighlights(-1, -1, -1, -1);
3900 static void BlankSquare(x, y, color, piece, dest)
3905 if (useImages && useImageSqs) {
3909 pm = xpmLightSquare;
3914 case 2: /* neutral */
3919 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3920 squareSize, squareSize, x, y);
3930 case 2: /* neutral */
3935 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3940 I split out the routines to draw a piece so that I could
3941 make a generic flash routine.
3943 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3945 int square_color, x, y;
3948 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3949 switch (square_color) {
3951 case 2: /* neutral */
3953 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3954 ? *pieceToOutline(piece)
3955 : *pieceToSolid(piece),
3956 dest, bwPieceGC, 0, 0,
3957 squareSize, squareSize, x, y);
3960 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3961 ? *pieceToSolid(piece)
3962 : *pieceToOutline(piece),
3963 dest, wbPieceGC, 0, 0,
3964 squareSize, squareSize, x, y);
3969 static void monoDrawPiece(piece, square_color, x, y, dest)
3971 int square_color, x, y;
3974 switch (square_color) {
3976 case 2: /* neutral */
3978 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3979 ? *pieceToOutline(piece)
3980 : *pieceToSolid(piece),
3981 dest, bwPieceGC, 0, 0,
3982 squareSize, squareSize, x, y, 1);
3985 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3986 ? *pieceToSolid(piece)
3987 : *pieceToOutline(piece),
3988 dest, wbPieceGC, 0, 0,
3989 squareSize, squareSize, x, y, 1);
3994 static void colorDrawPiece(piece, square_color, x, y, dest)
3996 int square_color, x, y;
3999 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4000 switch (square_color) {
4002 XCopyPlane(xDisplay, *pieceToSolid(piece),
4003 dest, (int) piece < (int) BlackPawn
4004 ? wlPieceGC : blPieceGC, 0, 0,
4005 squareSize, squareSize, x, y, 1);
4008 XCopyPlane(xDisplay, *pieceToSolid(piece),
4009 dest, (int) piece < (int) BlackPawn
4010 ? wdPieceGC : bdPieceGC, 0, 0,
4011 squareSize, squareSize, x, y, 1);
4013 case 2: /* neutral */
4015 XCopyPlane(xDisplay, *pieceToSolid(piece),
4016 dest, (int) piece < (int) BlackPawn
4017 ? wjPieceGC : bjPieceGC, 0, 0,
4018 squareSize, squareSize, x, y, 1);
4023 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4025 int square_color, x, y;
4030 switch (square_color) {
4032 case 2: /* neutral */
4034 if ((int)piece < (int) BlackPawn) {
4042 if ((int)piece < (int) BlackPawn) {
4050 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4051 dest, wlPieceGC, 0, 0,
4052 squareSize, squareSize, x, y);
4055 typedef void (*DrawFunc)();
4057 DrawFunc ChooseDrawFunc()
4059 if (appData.monoMode) {
4060 if (DefaultDepth(xDisplay, xScreen) == 1) {
4061 return monoDrawPiece_1bit;
4063 return monoDrawPiece;
4067 return colorDrawPieceImage;
4069 return colorDrawPiece;
4073 /* [HR] determine square color depending on chess variant. */
4074 static int SquareColor(row, column)
4079 if (gameInfo.variant == VariantXiangqi) {
4080 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4082 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4084 } else if (row <= 4) {
4090 square_color = ((column + row) % 2) == 1;
4093 /* [hgm] holdings: next line makes all holdings squares light */
4094 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4096 return square_color;
4099 void DrawSquare(row, column, piece, do_flash)
4100 int row, column, do_flash;
4103 int square_color, x, y, direction, font_ascent, font_descent;
4106 XCharStruct overall;
4110 /* Calculate delay in milliseconds (2-delays per complete flash) */
4111 flash_delay = 500 / appData.flashRate;
4114 x = lineGap + ((BOARD_WIDTH-1)-column) *
4115 (squareSize + lineGap);
4116 y = lineGap + row * (squareSize + lineGap);
4118 x = lineGap + column * (squareSize + lineGap);
4119 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4120 (squareSize + lineGap);
4123 square_color = SquareColor(row, column);
4125 if ( // [HGM] holdings: blank out area between board and holdings
4126 column == BOARD_LEFT-1 || column == BOARD_RGHT
4127 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4128 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4129 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4131 // [HGM] print piece counts next to holdings
4132 string[1] = NULLCHAR;
4133 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4134 string[0] = '0' + piece;
4135 XTextExtents(countFontStruct, string, 1, &direction,
4136 &font_ascent, &font_descent, &overall);
4137 if (appData.monoMode) {
4138 XDrawImageString(xDisplay, xBoardWindow, countGC,
4139 x + squareSize - overall.width - 2,
4140 y + font_ascent + 1, string, 1);
4142 XDrawString(xDisplay, xBoardWindow, countGC,
4143 x + squareSize - overall.width - 2,
4144 y + font_ascent + 1, string, 1);
4147 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4148 string[0] = '0' + piece;
4149 XTextExtents(countFontStruct, string, 1, &direction,
4150 &font_ascent, &font_descent, &overall);
4151 if (appData.monoMode) {
4152 XDrawImageString(xDisplay, xBoardWindow, countGC,
4153 x + 2, y + font_ascent + 1, string, 1);
4155 XDrawString(xDisplay, xBoardWindow, countGC,
4156 x + 2, y + font_ascent + 1, string, 1);
4160 if (piece == EmptySquare || appData.blindfold) {
4161 BlankSquare(x, y, square_color, piece, xBoardWindow);
4163 drawfunc = ChooseDrawFunc();
4164 if (do_flash && appData.flashCount > 0) {
4165 for (i=0; i<appData.flashCount; ++i) {
4167 drawfunc(piece, square_color, x, y, xBoardWindow);
4168 XSync(xDisplay, False);
4169 do_flash_delay(flash_delay);
4171 BlankSquare(x, y, square_color, piece, xBoardWindow);
4172 XSync(xDisplay, False);
4173 do_flash_delay(flash_delay);
4176 drawfunc(piece, square_color, x, y, xBoardWindow);
4180 string[1] = NULLCHAR;
4181 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4182 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4183 string[0] = 'a' + column - BOARD_LEFT;
4184 XTextExtents(coordFontStruct, string, 1, &direction,
4185 &font_ascent, &font_descent, &overall);
4186 if (appData.monoMode) {
4187 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4188 x + squareSize - overall.width - 2,
4189 y + squareSize - font_descent - 1, string, 1);
4191 XDrawString(xDisplay, xBoardWindow, coordGC,
4192 x + squareSize - overall.width - 2,
4193 y + squareSize - font_descent - 1, string, 1);
4196 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4197 string[0] = ONE + row;
4198 XTextExtents(coordFontStruct, string, 1, &direction,
4199 &font_ascent, &font_descent, &overall);
4200 if (appData.monoMode) {
4201 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4202 x + 2, y + font_ascent + 1, string, 1);
4204 XDrawString(xDisplay, xBoardWindow, coordGC,
4205 x + 2, y + font_ascent + 1, string, 1);
4211 /* Why is this needed on some versions of X? */
4212 void EventProc(widget, unused, event)
4217 if (!XtIsRealized(widget))
4220 switch (event->type) {
4222 if (event->xexpose.count > 0) return; /* no clipping is done */
4223 XDrawPosition(widget, True, NULL);
4231 void DrawPosition(fullRedraw, board)
4232 /*Boolean*/int fullRedraw;
4235 XDrawPosition(boardWidget, fullRedraw, board);
4238 /* Returns 1 if there are "too many" differences between b1 and b2
4239 (i.e. more than 1 move was made) */
4240 static int too_many_diffs(b1, b2)
4246 for (i=0; i<BOARD_HEIGHT; ++i) {
4247 for (j=0; j<BOARD_WIDTH; ++j) {
4248 if (b1[i][j] != b2[i][j]) {
4249 if (++c > 4) /* Castling causes 4 diffs */
4258 /* Matrix describing castling maneuvers */
4259 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4260 static int castling_matrix[4][5] = {
4261 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4262 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4263 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4264 { 7, 7, 4, 5, 6 } /* 0-0, black */
4267 /* Checks whether castling occurred. If it did, *rrow and *rcol
4268 are set to the destination (row,col) of the rook that moved.
4270 Returns 1 if castling occurred, 0 if not.
4272 Note: Only handles a max of 1 castling move, so be sure
4273 to call too_many_diffs() first.
4275 static int check_castle_draw(newb, oldb, rrow, rcol)
4282 /* For each type of castling... */
4283 for (i=0; i<4; ++i) {
4284 r = castling_matrix[i];
4286 /* Check the 4 squares involved in the castling move */
4288 for (j=1; j<=4; ++j) {
4289 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4296 /* All 4 changed, so it must be a castling move */
4305 static int damage[BOARD_RANKS][BOARD_FILES];
4308 * event handler for redrawing the board
4310 void XDrawPosition(w, repaint, board)
4312 /*Boolean*/int repaint;
4316 static int lastFlipView = 0;
4317 static int lastBoardValid = 0;
4318 static Board lastBoard;
4322 if (board == NULL) {
4323 if (!lastBoardValid) return;
4326 if (!lastBoardValid || lastFlipView != flipView) {
4327 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4328 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4333 * It would be simpler to clear the window with XClearWindow()
4334 * but this causes a very distracting flicker.
4337 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4339 /* If too much changes (begin observing new game, etc.), don't
4341 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4343 /* Special check for castling so we don't flash both the king
4344 and the rook (just flash the king). */
4346 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4347 /* Draw rook with NO flashing. King will be drawn flashing later */
4348 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4349 lastBoard[rrow][rcol] = board[rrow][rcol];
4353 /* First pass -- Draw (newly) empty squares and repair damage.
4354 This prevents you from having a piece show up twice while it
4355 is flashing on its new square */
4356 for (i = 0; i < BOARD_HEIGHT; i++)
4357 for (j = 0; j < BOARD_WIDTH; j++)
4358 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4360 DrawSquare(i, j, board[i][j], 0);
4361 damage[i][j] = False;
4364 /* Second pass -- Draw piece(s) in new position and flash them */
4365 for (i = 0; i < BOARD_HEIGHT; i++)
4366 for (j = 0; j < BOARD_WIDTH; j++)
4367 if (board[i][j] != lastBoard[i][j]) {
4368 DrawSquare(i, j, board[i][j], do_flash);
4372 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4373 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4375 for (i = 0; i < BOARD_HEIGHT; i++)
4376 for (j = 0; j < BOARD_WIDTH; j++) {
4377 DrawSquare(i, j, board[i][j], 0);
4378 damage[i][j] = False;
4382 CopyBoard(lastBoard, board);
4384 lastFlipView = flipView;
4386 /* Draw highlights */
4387 if (pm1X >= 0 && pm1Y >= 0) {
4388 drawHighlight(pm1X, pm1Y, prelineGC);
4390 if (pm2X >= 0 && pm2Y >= 0) {
4391 drawHighlight(pm2X, pm2Y, prelineGC);
4393 if (hi1X >= 0 && hi1Y >= 0) {
4394 drawHighlight(hi1X, hi1Y, highlineGC);
4396 if (hi2X >= 0 && hi2Y >= 0) {
4397 drawHighlight(hi2X, hi2Y, highlineGC);
4400 /* If piece being dragged around board, must redraw that too */
4403 XSync(xDisplay, False);
4408 * event handler for redrawing the board
4410 void DrawPositionProc(w, event, prms, nprms)
4416 XDrawPosition(w, True, NULL);
4421 * event handler for parsing user moves
4423 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4424 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4425 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4426 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4427 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4428 // and at the end FinishMove() to perform the move after optional promotion popups.
4429 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4430 void HandleUserMove(w, event, prms, nprms)
4436 if (w != boardWidget || errorExitStatus != -1) return;
4439 if (event->type == ButtonPress) {
4440 XtPopdown(promotionShell);
4441 XtDestroyWidget(promotionShell);
4442 promotionUp = False;
4450 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4451 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4452 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4455 void AnimateUserMove (Widget w, XEvent * event,
4456 String * params, Cardinal * nParams)
4458 DragPieceMove(event->xmotion.x, event->xmotion.y);
4461 Widget CommentCreate(name, text, mutable, callback, lines)
4463 int /*Boolean*/ mutable;
4464 XtCallbackProc callback;
4468 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4473 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4474 XtGetValues(boardWidget, args, j);
4477 XtSetArg(args[j], XtNresizable, True); j++;
4480 XtCreatePopupShell(name, topLevelShellWidgetClass,
4481 shellWidget, args, j);
4484 XtCreatePopupShell(name, transientShellWidgetClass,
4485 shellWidget, args, j);
4488 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4489 layoutArgs, XtNumber(layoutArgs));
4491 XtCreateManagedWidget("form", formWidgetClass, layout,
4492 formArgs, XtNumber(formArgs));
4496 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4497 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4499 XtSetArg(args[j], XtNstring, text); j++;
4500 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4501 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4502 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4503 XtSetArg(args[j], XtNright, XtChainRight); j++;
4504 XtSetArg(args[j], XtNresizable, True); j++;
4505 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4506 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4507 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4508 XtSetArg(args[j], XtNautoFill, True); j++;
4509 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4511 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4515 XtSetArg(args[j], XtNfromVert, edit); j++;
4516 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4517 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4518 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4519 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4521 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4522 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4525 XtSetArg(args[j], XtNfromVert, edit); j++;
4526 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4527 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4528 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4529 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4530 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4532 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4533 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4536 XtSetArg(args[j], XtNfromVert, edit); j++;
4537 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4538 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4539 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4540 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4541 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4543 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4544 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4547 XtSetArg(args[j], XtNfromVert, edit); j++;
4548 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4549 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4550 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4551 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4553 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4554 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4557 XtSetArg(args[j], XtNfromVert, edit); j++;
4558 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4559 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4560 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4561 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4562 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4564 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4565 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4568 XtRealizeWidget(shell);
4570 if (commentX == -1) {
4573 Dimension pw_height;
4574 Dimension ew_height;
4577 XtSetArg(args[j], XtNheight, &ew_height); j++;
4578 XtGetValues(edit, args, j);
4581 XtSetArg(args[j], XtNheight, &pw_height); j++;
4582 XtGetValues(shell, args, j);
4583 commentH = pw_height + (lines - 1) * ew_height;
4584 commentW = bw_width - 16;
4586 XSync(xDisplay, False);
4588 /* This code seems to tickle an X bug if it is executed too soon
4589 after xboard starts up. The coordinates get transformed as if
4590 the main window was positioned at (0, 0).
4592 XtTranslateCoords(shellWidget,
4593 (bw_width - commentW) / 2, 0 - commentH / 2,
4594 &commentX, &commentY);
4596 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4597 RootWindowOfScreen(XtScreen(shellWidget)),
4598 (bw_width - commentW) / 2, 0 - commentH / 2,
4603 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4606 if(wpComment.width > 0) {
4607 commentX = wpComment.x;
4608 commentY = wpComment.y;
4609 commentW = wpComment.width;
4610 commentH = wpComment.height;
4614 XtSetArg(args[j], XtNheight, commentH); j++;
4615 XtSetArg(args[j], XtNwidth, commentW); j++;
4616 XtSetArg(args[j], XtNx, commentX); j++;
4617 XtSetArg(args[j], XtNy, commentY); j++;
4618 XtSetValues(shell, args, j);
4619 XtSetKeyboardFocus(shell, edit);
4624 /* Used for analysis window and ICS input window */
4625 Widget MiscCreate(name, text, mutable, callback, lines)
4627 int /*Boolean*/ mutable;
4628 XtCallbackProc callback;
4632 Widget shell, layout, form, edit;
4634 Dimension bw_width, pw_height, ew_height, w, h;
4640 XtSetArg(args[j], XtNresizable, True); j++;
4643 XtCreatePopupShell(name, topLevelShellWidgetClass,
4644 shellWidget, args, j);
4647 XtCreatePopupShell(name, transientShellWidgetClass,
4648 shellWidget, args, j);
4651 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4652 layoutArgs, XtNumber(layoutArgs));
4654 XtCreateManagedWidget("form", formWidgetClass, layout,
4655 formArgs, XtNumber(formArgs));
4659 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4660 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4662 XtSetArg(args[j], XtNstring, text); j++;
4663 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4664 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4665 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4666 XtSetArg(args[j], XtNright, XtChainRight); j++;
4667 XtSetArg(args[j], XtNresizable, True); j++;
4668 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4669 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4670 XtSetArg(args[j], XtNautoFill, True); j++;
4671 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4673 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4675 XtRealizeWidget(shell);
4678 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4679 XtGetValues(boardWidget, args, j);
4682 XtSetArg(args[j], XtNheight, &ew_height); j++;
4683 XtGetValues(edit, args, j);
4686 XtSetArg(args[j], XtNheight, &pw_height); j++;
4687 XtGetValues(shell, args, j);
4688 h = pw_height + (lines - 1) * ew_height;
4691 XSync(xDisplay, False);
4693 /* This code seems to tickle an X bug if it is executed too soon
4694 after xboard starts up. The coordinates get transformed as if
4695 the main window was positioned at (0, 0).
4697 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4699 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4700 RootWindowOfScreen(XtScreen(shellWidget)),
4701 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4705 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4708 XtSetArg(args[j], XtNheight, h); j++;
4709 XtSetArg(args[j], XtNwidth, w); j++;
4710 XtSetArg(args[j], XtNx, x); j++;
4711 XtSetArg(args[j], XtNy, y); j++;
4712 XtSetValues(shell, args, j);
4718 static int savedIndex; /* gross that this is global */
4720 void EditCommentPopUp(index, title, text)
4729 if (text == NULL) text = "";
4731 if (editShell == NULL) {
4733 CommentCreate(title, text, True, EditCommentCallback, 4);
4734 XtRealizeWidget(editShell);
4735 CatchDeleteWindow(editShell, "EditCommentPopDown");
4737 edit = XtNameToWidget(editShell, "*form.text");
4739 XtSetArg(args[j], XtNstring, text); j++;
4740 XtSetValues(edit, args, j);
4742 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4743 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4744 XtSetValues(editShell, args, j);
4747 XtPopup(editShell, XtGrabNone);
4751 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4752 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4756 void EditCommentCallback(w, client_data, call_data)
4758 XtPointer client_data, call_data;
4766 XtSetArg(args[j], XtNlabel, &name); j++;
4767 XtGetValues(w, args, j);
4769 if (strcmp(name, _("ok")) == 0) {
4770 edit = XtNameToWidget(editShell, "*form.text");
4772 XtSetArg(args[j], XtNstring, &val); j++;
4773 XtGetValues(edit, args, j);
4774 ReplaceComment(savedIndex, val);
4775 EditCommentPopDown();
4776 } else if (strcmp(name, _("cancel")) == 0) {
4777 EditCommentPopDown();
4778 } else if (strcmp(name, _("clear")) == 0) {
4779 edit = XtNameToWidget(editShell, "*form.text");
4780 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4781 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4785 void EditCommentPopDown()
4790 if (!editUp) return;
4792 XtSetArg(args[j], XtNx, &commentX); j++;
4793 XtSetArg(args[j], XtNy, &commentY); j++;
4794 XtSetArg(args[j], XtNheight, &commentH); j++;
4795 XtSetArg(args[j], XtNwidth, &commentW); j++;
4796 XtGetValues(editShell, args, j);
4797 XtPopdown(editShell);
4800 XtSetArg(args[j], XtNleftBitmap, None); j++;
4801 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4805 void ICSInputBoxPopUp()
4810 char *title = _("ICS Input");
4813 if (ICSInputShell == NULL) {
4814 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4815 tr = XtParseTranslationTable(ICSInputTranslations);
4816 edit = XtNameToWidget(ICSInputShell, "*form.text");
4817 XtOverrideTranslations(edit, tr);
4818 XtRealizeWidget(ICSInputShell);
4819 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4822 edit = XtNameToWidget(ICSInputShell, "*form.text");
4824 XtSetArg(args[j], XtNstring, ""); j++;
4825 XtSetValues(edit, args, j);
4827 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4828 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4829 XtSetValues(ICSInputShell, args, j);
4832 XtPopup(ICSInputShell, XtGrabNone);
4833 XtSetKeyboardFocus(ICSInputShell, edit);
4835 ICSInputBoxUp = True;
4837 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4838 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4842 void ICSInputSendText()
4849 edit = XtNameToWidget(ICSInputShell, "*form.text");
4851 XtSetArg(args[j], XtNstring, &val); j++;
4852 XtGetValues(edit, args, j);
4853 SendMultiLineToICS(val);
4854 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4855 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4858 void ICSInputBoxPopDown()
4863 if (!ICSInputBoxUp) return;
4865 XtPopdown(ICSInputShell);
4866 ICSInputBoxUp = False;
4868 XtSetArg(args[j], XtNleftBitmap, None); j++;
4869 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4873 void CommentPopUp(title, text)
4880 if (commentShell == NULL) {
4882 CommentCreate(title, text, False, CommentCallback, 4);
4883 XtRealizeWidget(commentShell);
4884 CatchDeleteWindow(commentShell, "CommentPopDown");
4886 edit = XtNameToWidget(commentShell, "*form.text");
4888 XtSetArg(args[j], XtNstring, text); j++;
4889 XtSetValues(edit, args, j);
4891 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4892 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4893 XtSetValues(commentShell, args, j);
4896 XtPopup(commentShell, XtGrabNone);
4897 XSync(xDisplay, False);
4902 void CommentCallback(w, client_data, call_data)
4904 XtPointer client_data, call_data;
4911 XtSetArg(args[j], XtNlabel, &name); j++;
4912 XtGetValues(w, args, j);
4914 if (strcmp(name, _("close")) == 0) {
4916 } else if (strcmp(name, _("edit")) == 0) {
4923 void CommentPopDown()
4928 if (!commentUp) return;
4930 XtSetArg(args[j], XtNx, &commentX); j++;
4931 XtSetArg(args[j], XtNy, &commentY); j++;
4932 XtSetArg(args[j], XtNwidth, &commentW); j++;
4933 XtSetArg(args[j], XtNheight, &commentH); j++;
4934 XtGetValues(commentShell, args, j);
4935 XtPopdown(commentShell);
4936 XSync(xDisplay, False);
4940 void FileNamePopUp(label, def, proc, openMode)
4947 Widget popup, layout, dialog, edit;
4953 fileProc = proc; /* I can't see a way not */
4954 fileOpenMode = openMode; /* to use globals here */
4957 XtSetArg(args[i], XtNresizable, True); i++;
4958 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4959 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4960 fileNameShell = popup =
4961 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4962 shellWidget, args, i);
4965 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4966 layoutArgs, XtNumber(layoutArgs));
4969 XtSetArg(args[i], XtNlabel, label); i++;
4970 XtSetArg(args[i], XtNvalue, def); i++;
4971 XtSetArg(args[i], XtNborderWidth, 0); i++;
4972 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4975 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4976 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4977 (XtPointer) dialog);
4979 XtRealizeWidget(popup);
4980 CatchDeleteWindow(popup, "FileNamePopDown");
4982 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4983 &x, &y, &win_x, &win_y, &mask);
4985 XtSetArg(args[0], XtNx, x - 10);
4986 XtSetArg(args[1], XtNy, y - 30);
4987 XtSetValues(popup, args, 2);
4989 XtPopup(popup, XtGrabExclusive);
4992 edit = XtNameToWidget(dialog, "*value");
4993 XtSetKeyboardFocus(popup, edit);
4996 void FileNamePopDown()
4998 if (!filenameUp) return;
4999 XtPopdown(fileNameShell);
5000 XtDestroyWidget(fileNameShell);
5005 void FileNameCallback(w, client_data, call_data)
5007 XtPointer client_data, call_data;
5012 XtSetArg(args[0], XtNlabel, &name);
5013 XtGetValues(w, args, 1);
5015 if (strcmp(name, _("cancel")) == 0) {
5020 FileNameAction(w, NULL, NULL, NULL);
5023 void FileNameAction(w, event, prms, nprms)
5035 name = XawDialogGetValueString(w = XtParent(w));
5037 if ((name != NULL) && (*name != NULLCHAR)) {
5039 XtPopdown(w = XtParent(XtParent(w)));
5043 p = strrchr(buf, ' ');
5050 fullname = ExpandPathName(buf);
5052 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5055 f = fopen(fullname, fileOpenMode);
5057 DisplayError(_("Failed to open file"), errno);
5059 (void) (*fileProc)(f, index, buf);
5066 XtPopdown(w = XtParent(XtParent(w)));
5072 void PromotionPopUp()
5075 Widget dialog, layout;
5077 Dimension bw_width, pw_width;
5081 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5082 XtGetValues(boardWidget, args, j);
5085 XtSetArg(args[j], XtNresizable, True); j++;
5086 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5088 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5089 shellWidget, args, j);
5091 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5092 layoutArgs, XtNumber(layoutArgs));
5095 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5096 XtSetArg(args[j], XtNborderWidth, 0); j++;
5097 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5100 if(gameInfo.variant != VariantShogi) {
5101 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5102 (XtPointer) dialog);
5103 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5104 (XtPointer) dialog);
5105 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5106 (XtPointer) dialog);
5107 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5108 (XtPointer) dialog);
5109 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5110 gameInfo.variant == VariantGiveaway) {
5111 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5112 (XtPointer) dialog);
5114 if(gameInfo.variant == VariantCapablanca ||
5115 gameInfo.variant == VariantGothic ||
5116 gameInfo.variant == VariantCapaRandom) {
5117 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5118 (XtPointer) dialog);
5119 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5120 (XtPointer) dialog);
5122 } else // [HGM] shogi
5124 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5125 (XtPointer) dialog);
5126 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5127 (XtPointer) dialog);
5129 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5130 (XtPointer) dialog);
5132 XtRealizeWidget(promotionShell);
5133 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5136 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5137 XtGetValues(promotionShell, args, j);
5139 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5140 lineGap + squareSize/3 +
5141 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5142 0 : 6*(squareSize + lineGap)), &x, &y);
5145 XtSetArg(args[j], XtNx, x); j++;
5146 XtSetArg(args[j], XtNy, y); j++;
5147 XtSetValues(promotionShell, args, j);
5149 XtPopup(promotionShell, XtGrabNone);
5154 void PromotionPopDown()
5156 if (!promotionUp) return;
5157 XtPopdown(promotionShell);
5158 XtDestroyWidget(promotionShell);
5159 promotionUp = False;
5162 void PromotionCallback(w, client_data, call_data)
5164 XtPointer client_data, call_data;
5170 XtSetArg(args[0], XtNlabel, &name);
5171 XtGetValues(w, args, 1);
5175 if (fromX == -1) return;
5177 if (strcmp(name, _("cancel")) == 0) {
5181 } else if (strcmp(name, _("Knight")) == 0) {
5183 } else if (strcmp(name, _("Promote")) == 0) {
5185 } else if (strcmp(name, _("Defer")) == 0) {
5188 promoChar = ToLower(name[0]);
5191 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5193 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5194 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5199 void ErrorCallback(w, client_data, call_data)
5201 XtPointer client_data, call_data;
5204 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5206 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5212 if (!errorUp) return;
5214 XtPopdown(errorShell);
5215 XtDestroyWidget(errorShell);
5216 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5219 void ErrorPopUp(title, label, modal)
5220 char *title, *label;
5224 Widget dialog, layout;
5228 Dimension bw_width, pw_width;
5229 Dimension pw_height;
5233 XtSetArg(args[i], XtNresizable, True); i++;
5234 XtSetArg(args[i], XtNtitle, title); i++;
5236 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5237 shellWidget, args, i);
5239 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5240 layoutArgs, XtNumber(layoutArgs));
5243 XtSetArg(args[i], XtNlabel, label); i++;
5244 XtSetArg(args[i], XtNborderWidth, 0); i++;
5245 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5248 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5250 XtRealizeWidget(errorShell);
5251 CatchDeleteWindow(errorShell, "ErrorPopDown");
5254 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5255 XtGetValues(boardWidget, args, i);
5257 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5258 XtSetArg(args[i], XtNheight, &pw_height); i++;
5259 XtGetValues(errorShell, args, i);
5262 /* This code seems to tickle an X bug if it is executed too soon
5263 after xboard starts up. The coordinates get transformed as if
5264 the main window was positioned at (0, 0).
5266 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5267 0 - pw_height + squareSize / 3, &x, &y);
5269 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5270 RootWindowOfScreen(XtScreen(boardWidget)),
5271 (bw_width - pw_width) / 2,
5272 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5276 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5279 XtSetArg(args[i], XtNx, x); i++;
5280 XtSetArg(args[i], XtNy, y); i++;
5281 XtSetValues(errorShell, args, i);
5284 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5287 /* Disable all user input other than deleting the window */
5288 static int frozen = 0;
5292 /* Grab by a widget that doesn't accept input */
5293 XtAddGrab(messageWidget, TRUE, FALSE);
5297 /* Undo a FreezeUI */
5300 if (!frozen) return;
5301 XtRemoveGrab(messageWidget);
5305 char *ModeToWidgetName(mode)
5309 case BeginningOfGame:
5310 if (appData.icsActive)
5311 return "menuMode.ICS Client";
5312 else if (appData.noChessProgram ||
5313 *appData.cmailGameName != NULLCHAR)
5314 return "menuMode.Edit Game";
5316 return "menuMode.Machine Black";
5317 case MachinePlaysBlack:
5318 return "menuMode.Machine Black";
5319 case MachinePlaysWhite:
5320 return "menuMode.Machine White";
5322 return "menuMode.Analysis Mode";
5324 return "menuMode.Analyze File";
5325 case TwoMachinesPlay:
5326 return "menuMode.Two Machines";
5328 return "menuMode.Edit Game";
5329 case PlayFromGameFile:
5330 return "menuFile.Load Game";
5332 return "menuMode.Edit Position";
5334 return "menuMode.Training";
5335 case IcsPlayingWhite:
5336 case IcsPlayingBlack:
5340 return "menuMode.ICS Client";
5347 void ModeHighlight()
5350 static int oldPausing = FALSE;
5351 static GameMode oldmode = (GameMode) -1;
5354 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5356 if (pausing != oldPausing) {
5357 oldPausing = pausing;
5359 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5361 XtSetArg(args[0], XtNleftBitmap, None);
5363 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5366 if (appData.showButtonBar) {
5367 /* Always toggle, don't set. Previous code messes up when
5368 invoked while the button is pressed, as releasing it
5369 toggles the state again. */
5372 XtSetArg(args[0], XtNbackground, &oldbg);
5373 XtSetArg(args[1], XtNforeground, &oldfg);
5374 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5376 XtSetArg(args[0], XtNbackground, oldfg);
5377 XtSetArg(args[1], XtNforeground, oldbg);
5379 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5383 wname = ModeToWidgetName(oldmode);
5384 if (wname != NULL) {
5385 XtSetArg(args[0], XtNleftBitmap, None);
5386 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5388 wname = ModeToWidgetName(gameMode);
5389 if (wname != NULL) {
5390 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5391 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5395 /* Maybe all the enables should be handled here, not just this one */
5396 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5397 gameMode == Training || gameMode == PlayFromGameFile);
5402 * Button/menu procedures
5404 void ResetProc(w, event, prms, nprms)
5413 int LoadGamePopUp(f, gameNumber, title)
5418 cmailMsgLoaded = FALSE;
5419 if (gameNumber == 0) {
5420 int error = GameListBuild(f);
5422 DisplayError(_("Cannot build game list"), error);
5423 } else if (!ListEmpty(&gameList) &&
5424 ((ListGame *) gameList.tailPred)->number > 1) {
5425 GameListPopUp(f, title);
5431 return LoadGame(f, gameNumber, title, FALSE);
5434 void LoadGameProc(w, event, prms, nprms)
5440 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5443 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5446 void LoadNextGameProc(w, event, prms, nprms)
5455 void LoadPrevGameProc(w, event, prms, nprms)
5464 void ReloadGameProc(w, event, prms, nprms)
5473 void LoadNextPositionProc(w, event, prms, nprms)
5482 void LoadPrevPositionProc(w, event, prms, nprms)
5491 void ReloadPositionProc(w, event, prms, nprms)
5500 void LoadPositionProc(w, event, prms, nprms)
5506 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5509 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5512 void SaveGameProc(w, event, prms, nprms)
5518 FileNamePopUp(_("Save game file name?"),
5519 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5523 void SavePositionProc(w, event, prms, nprms)
5529 FileNamePopUp(_("Save position file name?"),
5530 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5534 void ReloadCmailMsgProc(w, event, prms, nprms)
5540 ReloadCmailMsgEvent(FALSE);
5543 void MailMoveProc(w, event, prms, nprms)
5552 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5553 static char *selected_fen_position=NULL;
5556 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5557 Atom *type_return, XtPointer *value_return,
5558 unsigned long *length_return, int *format_return)
5560 char *selection_tmp;
5562 if (!selected_fen_position) return False; /* should never happen */
5563 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5564 /* note: since no XtSelectionDoneProc was registered, Xt will
5565 * automatically call XtFree on the value returned. So have to
5566 * make a copy of it allocated with XtMalloc */
5567 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5568 strcpy(selection_tmp, selected_fen_position);
5570 *value_return=selection_tmp;
5571 *length_return=strlen(selection_tmp);
5572 *type_return=*target;
5573 *format_return = 8; /* bits per byte */
5575 } else if (*target == XA_TARGETS(xDisplay)) {
5576 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5577 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5578 targets_tmp[1] = XA_STRING;
5579 *value_return = targets_tmp;
5580 *type_return = XA_ATOM;
5582 *format_return = 8 * sizeof(Atom);
5583 if (*format_return > 32) {
5584 *length_return *= *format_return / 32;
5585 *format_return = 32;
5593 /* note: when called from menu all parameters are NULL, so no clue what the
5594 * Widget which was clicked on was, or what the click event was
5596 void CopyPositionProc(w, event, prms, nprms)
5603 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5604 * have a notion of a position that is selected but not copied.
5605 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5607 if(gameMode == EditPosition) EditPositionDone(TRUE);
5608 if (selected_fen_position) free(selected_fen_position);
5609 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5610 if (!selected_fen_position) return;
5611 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5613 SendPositionSelection,
5614 NULL/* lose_ownership_proc */ ,
5615 NULL/* transfer_done_proc */);
5616 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5618 SendPositionSelection,
5619 NULL/* lose_ownership_proc */ ,
5620 NULL/* transfer_done_proc */);
5623 /* function called when the data to Paste is ready */
5625 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5626 Atom *type, XtPointer value, unsigned long *len, int *format)
5629 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5630 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5631 EditPositionPasteFEN(fenstr);
5635 /* called when Paste Position button is pressed,
5636 * all parameters will be NULL */
5637 void PastePositionProc(w, event, prms, nprms)
5643 XtGetSelectionValue(menuBarWidget,
5644 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5645 /* (XtSelectionCallbackProc) */ PastePositionCB,
5646 NULL, /* client_data passed to PastePositionCB */
5648 /* better to use the time field from the event that triggered the
5649 * call to this function, but that isn't trivial to get
5657 SendGameSelection(Widget w, Atom *selection, Atom *target,
5658 Atom *type_return, XtPointer *value_return,
5659 unsigned long *length_return, int *format_return)
5661 char *selection_tmp;
5663 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5664 FILE* f = fopen(gameCopyFilename, "r");
5667 if (f == NULL) return False;
5671 selection_tmp = XtMalloc(len + 1);
5672 count = fread(selection_tmp, 1, len, f);
5674 XtFree(selection_tmp);
5677 selection_tmp[len] = NULLCHAR;
5678 *value_return = selection_tmp;
5679 *length_return = len;
5680 *type_return = *target;
5681 *format_return = 8; /* bits per byte */
5683 } else if (*target == XA_TARGETS(xDisplay)) {
5684 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5685 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5686 targets_tmp[1] = XA_STRING;
5687 *value_return = targets_tmp;
5688 *type_return = XA_ATOM;
5690 *format_return = 8 * sizeof(Atom);
5691 if (*format_return > 32) {
5692 *length_return *= *format_return / 32;
5693 *format_return = 32;
5701 /* note: when called from menu all parameters are NULL, so no clue what the
5702 * Widget which was clicked on was, or what the click event was
5704 void CopyGameProc(w, event, prms, nprms)
5712 ret = SaveGameToFile(gameCopyFilename, FALSE);
5716 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5717 * have a notion of a game that is selected but not copied.
5718 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5720 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5723 NULL/* lose_ownership_proc */ ,
5724 NULL/* transfer_done_proc */);
5725 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5728 NULL/* lose_ownership_proc */ ,
5729 NULL/* transfer_done_proc */);
5732 /* function called when the data to Paste is ready */
5734 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5735 Atom *type, XtPointer value, unsigned long *len, int *format)
5738 if (value == NULL || *len == 0) {
5739 return; /* nothing had been selected to copy */
5741 f = fopen(gamePasteFilename, "w");
5743 DisplayError(_("Can't open temp file"), errno);
5746 fwrite(value, 1, *len, f);
5749 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5752 /* called when Paste Game button is pressed,
5753 * all parameters will be NULL */
5754 void PasteGameProc(w, event, prms, nprms)
5760 XtGetSelectionValue(menuBarWidget,
5761 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5762 /* (XtSelectionCallbackProc) */ PasteGameCB,
5763 NULL, /* client_data passed to PasteGameCB */
5765 /* better to use the time field from the event that triggered the
5766 * call to this function, but that isn't trivial to get
5776 SaveGameProc(NULL, NULL, NULL, NULL);
5780 void QuitProc(w, event, prms, nprms)
5789 void PauseProc(w, event, prms, nprms)
5799 void MachineBlackProc(w, event, prms, nprms)
5805 MachineBlackEvent();
5808 void MachineWhiteProc(w, event, prms, nprms)
5814 MachineWhiteEvent();
5817 void AnalyzeModeProc(w, event, prms, nprms)
5825 if (!first.analysisSupport) {
5826 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5827 DisplayError(buf, 0);
5830 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5831 if (appData.icsActive) {
5832 if (gameMode != IcsObserving) {
5833 sprintf(buf,_("You are not observing a game"));
5834 DisplayError(buf, 0);
5836 if (appData.icsEngineAnalyze) {
5837 if (appData.debugMode)
5838 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5844 /* if enable, use want disable icsEngineAnalyze */
5845 if (appData.icsEngineAnalyze) {
5850 appData.icsEngineAnalyze = TRUE;
5851 if (appData.debugMode)
5852 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5854 if (!appData.showThinking)
5855 ShowThinkingProc(w,event,prms,nprms);
5860 void AnalyzeFileProc(w, event, prms, nprms)
5866 if (!first.analysisSupport) {
5868 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5869 DisplayError(buf, 0);
5874 if (!appData.showThinking)
5875 ShowThinkingProc(w,event,prms,nprms);
5878 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5879 AnalysisPeriodicEvent(1);
5882 void TwoMachinesProc(w, event, prms, nprms)
5891 void IcsClientProc(w, event, prms, nprms)
5900 void EditGameProc(w, event, prms, nprms)
5909 void EditPositionProc(w, event, prms, nprms)
5915 EditPositionEvent();
5918 void TrainingProc(w, event, prms, nprms)
5927 void EditCommentProc(w, event, prms, nprms)
5934 EditCommentPopDown();
5940 void IcsInputBoxProc(w, event, prms, nprms)
5946 if (ICSInputBoxUp) {
5947 ICSInputBoxPopDown();
5953 void AcceptProc(w, event, prms, nprms)
5962 void DeclineProc(w, event, prms, nprms)
5971 void RematchProc(w, event, prms, nprms)
5980 void CallFlagProc(w, event, prms, nprms)
5989 void DrawProc(w, event, prms, nprms)
5998 void AbortProc(w, event, prms, nprms)
6007 void AdjournProc(w, event, prms, nprms)
6016 void ResignProc(w, event, prms, nprms)
6025 void AdjuWhiteProc(w, event, prms, nprms)
6031 UserAdjudicationEvent(+1);
6034 void AdjuBlackProc(w, event, prms, nprms)
6040 UserAdjudicationEvent(-1);
6043 void AdjuDrawProc(w, event, prms, nprms)
6049 UserAdjudicationEvent(0);
6052 void EnterKeyProc(w, event, prms, nprms)
6058 if (ICSInputBoxUp == True)
6062 void StopObservingProc(w, event, prms, nprms)
6068 StopObservingEvent();
6071 void StopExaminingProc(w, event, prms, nprms)
6077 StopExaminingEvent();
6081 void ForwardProc(w, event, prms, nprms)
6091 void BackwardProc(w, event, prms, nprms)
6100 void ToStartProc(w, event, prms, nprms)
6109 void ToEndProc(w, event, prms, nprms)
6118 void RevertProc(w, event, prms, nprms)
6127 void TruncateGameProc(w, event, prms, nprms)
6133 TruncateGameEvent();
6135 void RetractMoveProc(w, event, prms, nprms)
6144 void MoveNowProc(w, event, prms, nprms)
6154 void AlwaysQueenProc(w, event, prms, nprms)
6162 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6164 if (appData.alwaysPromoteToQueen) {
6165 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6167 XtSetArg(args[0], XtNleftBitmap, None);
6169 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6173 void AnimateDraggingProc(w, event, prms, nprms)
6181 appData.animateDragging = !appData.animateDragging;
6183 if (appData.animateDragging) {
6184 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6187 XtSetArg(args[0], XtNleftBitmap, None);
6189 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6193 void AnimateMovingProc(w, event, prms, nprms)
6201 appData.animate = !appData.animate;
6203 if (appData.animate) {
6204 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6207 XtSetArg(args[0], XtNleftBitmap, None);
6209 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6213 void AutocommProc(w, event, prms, nprms)
6221 appData.autoComment = !appData.autoComment;
6223 if (appData.autoComment) {
6224 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6226 XtSetArg(args[0], XtNleftBitmap, None);
6228 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6233 void AutoflagProc(w, event, prms, nprms)
6241 appData.autoCallFlag = !appData.autoCallFlag;
6243 if (appData.autoCallFlag) {
6244 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6246 XtSetArg(args[0], XtNleftBitmap, None);
6248 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6252 void AutoflipProc(w, event, prms, nprms)
6260 appData.autoFlipView = !appData.autoFlipView;
6262 if (appData.autoFlipView) {
6263 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6265 XtSetArg(args[0], XtNleftBitmap, None);
6267 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6271 void AutobsProc(w, event, prms, nprms)
6279 appData.autoObserve = !appData.autoObserve;
6281 if (appData.autoObserve) {
6282 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6284 XtSetArg(args[0], XtNleftBitmap, None);
6286 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6290 void AutoraiseProc(w, event, prms, nprms)
6298 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6300 if (appData.autoRaiseBoard) {
6301 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6303 XtSetArg(args[0], XtNleftBitmap, None);
6305 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6309 void AutosaveProc(w, event, prms, nprms)
6317 appData.autoSaveGames = !appData.autoSaveGames;
6319 if (appData.autoSaveGames) {
6320 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6322 XtSetArg(args[0], XtNleftBitmap, None);
6324 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6328 void BlindfoldProc(w, event, prms, nprms)
6336 appData.blindfold = !appData.blindfold;
6338 if (appData.blindfold) {
6339 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6341 XtSetArg(args[0], XtNleftBitmap, None);
6343 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6346 DrawPosition(True, NULL);
6349 void TestLegalityProc(w, event, prms, nprms)
6357 appData.testLegality = !appData.testLegality;
6359 if (appData.testLegality) {
6360 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6362 XtSetArg(args[0], XtNleftBitmap, None);
6364 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6369 void FlashMovesProc(w, event, prms, nprms)
6377 if (appData.flashCount == 0) {
6378 appData.flashCount = 3;
6380 appData.flashCount = -appData.flashCount;
6383 if (appData.flashCount > 0) {
6384 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6386 XtSetArg(args[0], XtNleftBitmap, None);
6388 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6392 void FlipViewProc(w, event, prms, nprms)
6398 flipView = !flipView;
6399 DrawPosition(True, NULL);
6402 void GetMoveListProc(w, event, prms, nprms)
6410 appData.getMoveList = !appData.getMoveList;
6412 if (appData.getMoveList) {
6413 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6416 XtSetArg(args[0], XtNleftBitmap, None);
6418 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6423 void HighlightDraggingProc(w, event, prms, nprms)
6431 appData.highlightDragging = !appData.highlightDragging;
6433 if (appData.highlightDragging) {
6434 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6436 XtSetArg(args[0], XtNleftBitmap, None);
6438 XtSetValues(XtNameToWidget(menuBarWidget,
6439 "menuOptions.Highlight Dragging"), args, 1);
6443 void HighlightLastMoveProc(w, event, prms, nprms)
6451 appData.highlightLastMove = !appData.highlightLastMove;
6453 if (appData.highlightLastMove) {
6454 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6456 XtSetArg(args[0], XtNleftBitmap, None);
6458 XtSetValues(XtNameToWidget(menuBarWidget,
6459 "menuOptions.Highlight Last Move"), args, 1);
6462 void IcsAlarmProc(w, event, prms, nprms)
6470 appData.icsAlarm = !appData.icsAlarm;
6472 if (appData.icsAlarm) {
6473 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6475 XtSetArg(args[0], XtNleftBitmap, None);
6477 XtSetValues(XtNameToWidget(menuBarWidget,
6478 "menuOptions.ICS Alarm"), args, 1);
6481 void MoveSoundProc(w, event, prms, nprms)
6489 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6491 if (appData.ringBellAfterMoves) {
6492 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6494 XtSetArg(args[0], XtNleftBitmap, None);
6496 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6501 void OldSaveStyleProc(w, event, prms, nprms)
6509 appData.oldSaveStyle = !appData.oldSaveStyle;
6511 if (appData.oldSaveStyle) {
6512 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6514 XtSetArg(args[0], XtNleftBitmap, None);
6516 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6520 void PeriodicUpdatesProc(w, event, prms, nprms)
6528 PeriodicUpdatesEvent(!appData.periodicUpdates);
6530 if (appData.periodicUpdates) {
6531 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6533 XtSetArg(args[0], XtNleftBitmap, None);
6535 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6539 void PonderNextMoveProc(w, event, prms, nprms)
6547 PonderNextMoveEvent(!appData.ponderNextMove);
6549 if (appData.ponderNextMove) {
6550 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6552 XtSetArg(args[0], XtNleftBitmap, None);
6554 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6558 void PopupExitMessageProc(w, event, prms, nprms)
6566 appData.popupExitMessage = !appData.popupExitMessage;
6568 if (appData.popupExitMessage) {
6569 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6571 XtSetArg(args[0], XtNleftBitmap, None);
6573 XtSetValues(XtNameToWidget(menuBarWidget,
6574 "menuOptions.Popup Exit Message"), args, 1);
6577 void PopupMoveErrorsProc(w, event, prms, nprms)
6585 appData.popupMoveErrors = !appData.popupMoveErrors;
6587 if (appData.popupMoveErrors) {
6588 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6590 XtSetArg(args[0], XtNleftBitmap, None);
6592 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6596 void PremoveProc(w, event, prms, nprms)
6604 appData.premove = !appData.premove;
6606 if (appData.premove) {
6607 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6609 XtSetArg(args[0], XtNleftBitmap, None);
6611 XtSetValues(XtNameToWidget(menuBarWidget,
6612 "menuOptions.Premove"), args, 1);
6615 void QuietPlayProc(w, event, prms, nprms)
6623 appData.quietPlay = !appData.quietPlay;
6625 if (appData.quietPlay) {
6626 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6628 XtSetArg(args[0], XtNleftBitmap, None);
6630 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6634 void ShowCoordsProc(w, event, prms, nprms)
6642 appData.showCoords = !appData.showCoords;
6644 if (appData.showCoords) {
6645 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6647 XtSetArg(args[0], XtNleftBitmap, None);
6649 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6652 DrawPosition(True, NULL);
6655 void ShowThinkingProc(w, event, prms, nprms)
6661 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6662 ShowThinkingEvent();
6665 void HideThinkingProc(w, event, prms, nprms)
6673 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6674 ShowThinkingEvent();
6676 if (appData.hideThinkingFromHuman) {
6677 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6679 XtSetArg(args[0], XtNleftBitmap, None);
6681 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6685 void SaveOnExitProc(w, event, prms, nprms)
6693 saveSettingsOnExit = !saveSettingsOnExit;
6695 if (saveSettingsOnExit) {
6696 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6698 XtSetArg(args[0], XtNleftBitmap, None);
6700 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6704 void SaveSettingsProc(w, event, prms, nprms)
6710 SaveSettings(settingsFileName);
6713 void InfoProc(w, event, prms, nprms)
6720 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6725 void ManProc(w, event, prms, nprms)
6733 if (nprms && *nprms > 0)
6737 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6741 void HintProc(w, event, prms, nprms)
6750 void BookProc(w, event, prms, nprms)
6759 void AboutProc(w, event, prms, nprms)
6767 char *zippy = " (with Zippy code)";
6771 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6772 programVersion, zippy,
6773 "Copyright 1991 Digital Equipment Corporation",
6774 "Enhancements Copyright 1992-2009 Free Software Foundation",
6775 "Enhancements Copyright 2005 Alessandro Scotti",
6776 PACKAGE, " is free software and carries NO WARRANTY;",
6777 "see the file COPYING for more information.");
6778 ErrorPopUp(_("About XBoard"), buf, FALSE);
6781 void DebugProc(w, event, prms, nprms)
6787 appData.debugMode = !appData.debugMode;
6790 void AboutGameProc(w, event, prms, nprms)
6799 void NothingProc(w, event, prms, nprms)
6808 void Iconify(w, event, prms, nprms)
6817 XtSetArg(args[0], XtNiconic, True);
6818 XtSetValues(shellWidget, args, 1);
6821 void DisplayMessage(message, extMessage)
6822 char *message, *extMessage;
6824 /* display a message in the message widget */
6833 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6838 message = extMessage;
6842 /* need to test if messageWidget already exists, since this function
6843 can also be called during the startup, if for example a Xresource
6844 is not set up correctly */
6847 XtSetArg(arg, XtNlabel, message);
6848 XtSetValues(messageWidget, &arg, 1);
6854 void DisplayTitle(text)
6859 char title[MSG_SIZ];
6862 if (text == NULL) text = "";
6864 if (appData.titleInWindow) {
6866 XtSetArg(args[i], XtNlabel, text); i++;
6867 XtSetValues(titleWidget, args, i);
6870 if (*text != NULLCHAR) {
6872 strcpy(title, text);
6873 } else if (appData.icsActive) {
6874 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6875 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6876 } else if (appData.cmailGameName[0] != NULLCHAR) {
6877 snprintf(icon, sizeof(icon), "%s", "CMail");
6878 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6880 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6881 } else if (gameInfo.variant == VariantGothic) {
6882 strcpy(icon, programName);
6883 strcpy(title, GOTHIC);
6886 } else if (gameInfo.variant == VariantFalcon) {
6887 strcpy(icon, programName);
6888 strcpy(title, FALCON);
6890 } else if (appData.noChessProgram) {
6891 strcpy(icon, programName);
6892 strcpy(title, programName);
6894 strcpy(icon, first.tidy);
6895 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6898 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6899 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6900 XtSetValues(shellWidget, args, i);
6904 void DisplayError(message, error)
6911 if (appData.debugMode || appData.matchMode) {
6912 fprintf(stderr, "%s: %s\n", programName, message);
6915 if (appData.debugMode || appData.matchMode) {
6916 fprintf(stderr, "%s: %s: %s\n",
6917 programName, message, strerror(error));
6919 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6922 ErrorPopUp(_("Error"), message, FALSE);
6926 void DisplayMoveError(message)
6931 DrawPosition(FALSE, NULL);
6932 if (appData.debugMode || appData.matchMode) {
6933 fprintf(stderr, "%s: %s\n", programName, message);
6935 if (appData.popupMoveErrors) {
6936 ErrorPopUp(_("Error"), message, FALSE);
6938 DisplayMessage(message, "");
6943 void DisplayFatalError(message, error, status)
6949 errorExitStatus = status;
6951 fprintf(stderr, "%s: %s\n", programName, message);
6953 fprintf(stderr, "%s: %s: %s\n",
6954 programName, message, strerror(error));
6955 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6958 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6959 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6965 void DisplayInformation(message)
6969 ErrorPopUp(_("Information"), message, TRUE);
6972 void DisplayNote(message)
6976 ErrorPopUp(_("Note"), message, FALSE);
6980 NullXErrorCheck(dpy, error_event)
6982 XErrorEvent *error_event;
6987 void DisplayIcsInteractionTitle(message)
6990 if (oldICSInteractionTitle == NULL) {
6991 /* Magic to find the old window title, adapted from vim */
6992 char *wina = getenv("WINDOWID");
6994 Window win = (Window) atoi(wina);
6995 Window root, parent, *children;
6996 unsigned int nchildren;
6997 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6999 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7000 if (!XQueryTree(xDisplay, win, &root, &parent,
7001 &children, &nchildren)) break;
7002 if (children) XFree((void *)children);
7003 if (parent == root || parent == 0) break;
7006 XSetErrorHandler(oldHandler);
7008 if (oldICSInteractionTitle == NULL) {
7009 oldICSInteractionTitle = "xterm";
7012 printf("\033]0;%s\007", message);
7016 char pendingReplyPrefix[MSG_SIZ];
7017 ProcRef pendingReplyPR;
7019 void AskQuestionProc(w, event, prms, nprms)
7026 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7030 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7033 void AskQuestionPopDown()
7035 if (!askQuestionUp) return;
7036 XtPopdown(askQuestionShell);
7037 XtDestroyWidget(askQuestionShell);
7038 askQuestionUp = False;
7041 void AskQuestionReplyAction(w, event, prms, nprms)
7051 reply = XawDialogGetValueString(w = XtParent(w));
7052 strcpy(buf, pendingReplyPrefix);
7053 if (*buf) strcat(buf, " ");
7056 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7057 AskQuestionPopDown();
7059 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7062 void AskQuestionCallback(w, client_data, call_data)
7064 XtPointer client_data, call_data;
7069 XtSetArg(args[0], XtNlabel, &name);
7070 XtGetValues(w, args, 1);
7072 if (strcmp(name, _("cancel")) == 0) {
7073 AskQuestionPopDown();
7075 AskQuestionReplyAction(w, NULL, NULL, NULL);
7079 void AskQuestion(title, question, replyPrefix, pr)
7080 char *title, *question, *replyPrefix;
7084 Widget popup, layout, dialog, edit;
7090 strcpy(pendingReplyPrefix, replyPrefix);
7091 pendingReplyPR = pr;
7094 XtSetArg(args[i], XtNresizable, True); i++;
7095 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7096 askQuestionShell = popup =
7097 XtCreatePopupShell(title, transientShellWidgetClass,
7098 shellWidget, args, i);
7101 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7102 layoutArgs, XtNumber(layoutArgs));
7105 XtSetArg(args[i], XtNlabel, question); i++;
7106 XtSetArg(args[i], XtNvalue, ""); i++;
7107 XtSetArg(args[i], XtNborderWidth, 0); i++;
7108 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7111 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7112 (XtPointer) dialog);
7113 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7114 (XtPointer) dialog);
7116 XtRealizeWidget(popup);
7117 CatchDeleteWindow(popup, "AskQuestionPopDown");
7119 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7120 &x, &y, &win_x, &win_y, &mask);
7122 XtSetArg(args[0], XtNx, x - 10);
7123 XtSetArg(args[1], XtNy, y - 30);
7124 XtSetValues(popup, args, 2);
7126 XtPopup(popup, XtGrabExclusive);
7127 askQuestionUp = True;
7129 edit = XtNameToWidget(dialog, "*value");
7130 XtSetKeyboardFocus(popup, edit);
7138 if (*name == NULLCHAR) {
7140 } else if (strcmp(name, "$") == 0) {
7141 putc(BELLCHAR, stderr);
7144 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7152 PlaySound(appData.soundMove);
7158 PlaySound(appData.soundIcsWin);
7164 PlaySound(appData.soundIcsLoss);
7170 PlaySound(appData.soundIcsDraw);
7174 PlayIcsUnfinishedSound()
7176 PlaySound(appData.soundIcsUnfinished);
7182 PlaySound(appData.soundIcsAlarm);
7188 system("stty echo");
7194 system("stty -echo");
7198 Colorize(cc, continuation)
7203 int count, outCount, error;
7205 if (textColors[(int)cc].bg > 0) {
7206 if (textColors[(int)cc].fg > 0) {
7207 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7208 textColors[(int)cc].fg, textColors[(int)cc].bg);
7210 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7211 textColors[(int)cc].bg);
7214 if (textColors[(int)cc].fg > 0) {
7215 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7216 textColors[(int)cc].fg);
7218 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7221 count = strlen(buf);
7222 outCount = OutputToProcess(NoProc, buf, count, &error);
7223 if (outCount < count) {
7224 DisplayFatalError(_("Error writing to display"), error, 1);
7227 if (continuation) return;
7230 PlaySound(appData.soundShout);
7233 PlaySound(appData.soundSShout);
7236 PlaySound(appData.soundChannel1);
7239 PlaySound(appData.soundChannel);
7242 PlaySound(appData.soundKibitz);
7245 PlaySound(appData.soundTell);
7247 case ColorChallenge:
7248 PlaySound(appData.soundChallenge);
7251 PlaySound(appData.soundRequest);
7254 PlaySound(appData.soundSeek);
7265 return getpwuid(getuid())->pw_name;
7268 static char *ExpandPathName(path)
7271 static char static_buf[2000];
7272 char *d, *s, buf[2000];
7278 while (*s && isspace(*s))
7287 if (*(s+1) == '/') {
7288 strcpy(d, getpwuid(getuid())->pw_dir);
7293 *strchr(buf, '/') = 0;
7294 pwd = getpwnam(buf);
7297 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7301 strcpy(d, pwd->pw_dir);
7302 strcat(d, strchr(s+1, '/'));
7313 static char host_name[MSG_SIZ];
7315 #if HAVE_GETHOSTNAME
7316 gethostname(host_name, MSG_SIZ);
7318 #else /* not HAVE_GETHOSTNAME */
7319 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7320 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7322 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7324 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7325 #endif /* not HAVE_GETHOSTNAME */
7328 XtIntervalId delayedEventTimerXID = 0;
7329 DelayedEventCallback delayedEventCallback = 0;
7334 delayedEventTimerXID = 0;
7335 delayedEventCallback();
7339 ScheduleDelayedEvent(cb, millisec)
7340 DelayedEventCallback cb; long millisec;
7342 if(delayedEventTimerXID && delayedEventCallback == cb)
7343 // [HGM] alive: replace, rather than add or flush identical event
7344 XtRemoveTimeOut(delayedEventTimerXID);
7345 delayedEventCallback = cb;
7346 delayedEventTimerXID =
7347 XtAppAddTimeOut(appContext, millisec,
7348 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7351 DelayedEventCallback
7354 if (delayedEventTimerXID) {
7355 return delayedEventCallback;
7362 CancelDelayedEvent()
7364 if (delayedEventTimerXID) {
7365 XtRemoveTimeOut(delayedEventTimerXID);
7366 delayedEventTimerXID = 0;
7370 XtIntervalId loadGameTimerXID = 0;
7372 int LoadGameTimerRunning()
7374 return loadGameTimerXID != 0;
7377 int StopLoadGameTimer()
7379 if (loadGameTimerXID != 0) {
7380 XtRemoveTimeOut(loadGameTimerXID);
7381 loadGameTimerXID = 0;
7389 LoadGameTimerCallback(arg, id)
7393 loadGameTimerXID = 0;
7398 StartLoadGameTimer(millisec)
7402 XtAppAddTimeOut(appContext, millisec,
7403 (XtTimerCallbackProc) LoadGameTimerCallback,
7407 XtIntervalId analysisClockXID = 0;
7410 AnalysisClockCallback(arg, id)
7414 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7415 || appData.icsEngineAnalyze) { // [DM]
7416 AnalysisPeriodicEvent(0);
7417 StartAnalysisClock();
7422 StartAnalysisClock()
7425 XtAppAddTimeOut(appContext, 2000,
7426 (XtTimerCallbackProc) AnalysisClockCallback,
7430 XtIntervalId clockTimerXID = 0;
7432 int ClockTimerRunning()
7434 return clockTimerXID != 0;
7437 int StopClockTimer()
7439 if (clockTimerXID != 0) {
7440 XtRemoveTimeOut(clockTimerXID);
7449 ClockTimerCallback(arg, id)
7458 StartClockTimer(millisec)
7462 XtAppAddTimeOut(appContext, millisec,
7463 (XtTimerCallbackProc) ClockTimerCallback,
7468 DisplayTimerLabel(w, color, timer, highlight)
7477 /* check for low time warning */
7478 Pixel foregroundOrWarningColor = timerForegroundPixel;
7481 appData.lowTimeWarning &&
7482 (timer / 1000) < appData.icsAlarmTime)
7483 foregroundOrWarningColor = lowTimeWarningColor;
7485 if (appData.clockMode) {
7486 sprintf(buf, "%s: %s", color, TimeString(timer));
7487 XtSetArg(args[0], XtNlabel, buf);
7489 sprintf(buf, "%s ", color);
7490 XtSetArg(args[0], XtNlabel, buf);
7495 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7496 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7498 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7499 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7502 XtSetValues(w, args, 3);
7506 DisplayWhiteClock(timeRemaining, highlight)
7512 if(appData.noGUI) return;
7513 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7514 if (highlight && iconPixmap == bIconPixmap) {
7515 iconPixmap = wIconPixmap;
7516 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7517 XtSetValues(shellWidget, args, 1);
7522 DisplayBlackClock(timeRemaining, highlight)
7528 if(appData.noGUI) return;
7529 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7530 if (highlight && iconPixmap == wIconPixmap) {
7531 iconPixmap = bIconPixmap;
7532 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7533 XtSetValues(shellWidget, args, 1);
7551 int StartChildProcess(cmdLine, dir, pr)
7558 int to_prog[2], from_prog[2];
7562 if (appData.debugMode) {
7563 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7566 /* We do NOT feed the cmdLine to the shell; we just
7567 parse it into blank-separated arguments in the
7568 most simple-minded way possible.
7571 strcpy(buf, cmdLine);
7574 while(*p == ' ') p++;
7576 if(*p == '"' || *p == '\'')
7577 p = strchr(++argv[i-1], *p);
7578 else p = strchr(p, ' ');
7579 if (p == NULL) break;
7584 SetUpChildIO(to_prog, from_prog);
7586 if ((pid = fork()) == 0) {
7588 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7589 close(to_prog[1]); // first close the unused pipe ends
7590 close(from_prog[0]);
7591 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7592 dup2(from_prog[1], 1);
7593 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7594 close(from_prog[1]); // and closing again loses one of the pipes!
7595 if(fileno(stderr) >= 2) // better safe than sorry...
7596 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7598 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7603 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7605 execvp(argv[0], argv);
7607 /* If we get here, exec failed */
7612 /* Parent process */
7614 close(from_prog[1]);
7616 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7619 cp->fdFrom = from_prog[0];
7620 cp->fdTo = to_prog[1];
7625 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7626 static RETSIGTYPE AlarmCallBack(int n)
7632 DestroyChildProcess(pr, signalType)
7636 ChildProc *cp = (ChildProc *) pr;
7638 if (cp->kind != CPReal) return;
7640 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7641 signal(SIGALRM, AlarmCallBack);
7643 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7644 kill(cp->pid, SIGKILL); // kill it forcefully
7645 wait((int *) 0); // and wait again
7649 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7651 /* Process is exiting either because of the kill or because of
7652 a quit command sent by the backend; either way, wait for it to die.
7661 InterruptChildProcess(pr)
7664 ChildProc *cp = (ChildProc *) pr;
7666 if (cp->kind != CPReal) return;
7667 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7670 int OpenTelnet(host, port, pr)
7675 char cmdLine[MSG_SIZ];
7677 if (port[0] == NULLCHAR) {
7678 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7680 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7682 return StartChildProcess(cmdLine, "", pr);
7685 int OpenTCP(host, port, pr)
7691 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7692 #else /* !OMIT_SOCKETS */
7694 struct sockaddr_in sa;
7696 unsigned short uport;
7699 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7703 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7704 sa.sin_family = AF_INET;
7705 sa.sin_addr.s_addr = INADDR_ANY;
7706 uport = (unsigned short) 0;
7707 sa.sin_port = htons(uport);
7708 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7712 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7713 if (!(hp = gethostbyname(host))) {
7715 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7716 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7717 hp->h_addrtype = AF_INET;
7719 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7720 hp->h_addr_list[0] = (char *) malloc(4);
7721 hp->h_addr_list[0][0] = b0;
7722 hp->h_addr_list[0][1] = b1;
7723 hp->h_addr_list[0][2] = b2;
7724 hp->h_addr_list[0][3] = b3;
7729 sa.sin_family = hp->h_addrtype;
7730 uport = (unsigned short) atoi(port);
7731 sa.sin_port = htons(uport);
7732 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7734 if (connect(s, (struct sockaddr *) &sa,
7735 sizeof(struct sockaddr_in)) < 0) {
7739 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7746 #endif /* !OMIT_SOCKETS */
7751 int OpenCommPort(name, pr)
7758 fd = open(name, 2, 0);
7759 if (fd < 0) return errno;
7761 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7771 int OpenLoopback(pr)
7777 SetUpChildIO(to, from);
7779 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7782 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7789 int OpenRcmd(host, user, cmd, pr)
7790 char *host, *user, *cmd;
7793 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7797 #define INPUT_SOURCE_BUF_SIZE 8192
7806 char buf[INPUT_SOURCE_BUF_SIZE];
7811 DoInputCallback(closure, source, xid)
7816 InputSource *is = (InputSource *) closure;
7821 if (is->lineByLine) {
7822 count = read(is->fd, is->unused,
7823 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7825 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7828 is->unused += count;
7830 while (p < is->unused) {
7831 q = memchr(p, '\n', is->unused - p);
7832 if (q == NULL) break;
7834 (is->func)(is, is->closure, p, q - p, 0);
7838 while (p < is->unused) {
7843 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7848 (is->func)(is, is->closure, is->buf, count, error);
7852 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7859 ChildProc *cp = (ChildProc *) pr;
7861 is = (InputSource *) calloc(1, sizeof(InputSource));
7862 is->lineByLine = lineByLine;
7866 is->fd = fileno(stdin);
7868 is->kind = cp->kind;
7869 is->fd = cp->fdFrom;
7872 is->unused = is->buf;
7875 is->xid = XtAppAddInput(appContext, is->fd,
7876 (XtPointer) (XtInputReadMask),
7877 (XtInputCallbackProc) DoInputCallback,
7879 is->closure = closure;
7880 return (InputSourceRef) is;
7884 RemoveInputSource(isr)
7887 InputSource *is = (InputSource *) isr;
7889 if (is->xid == 0) return;
7890 XtRemoveInput(is->xid);
7894 int OutputToProcess(pr, message, count, outError)
7900 static int line = 0;
7901 ChildProc *cp = (ChildProc *) pr;
7906 if (appData.noJoin || !appData.useInternalWrap)
7907 outCount = fwrite(message, 1, count, stdout);
7910 int width = get_term_width();
7911 int len = wrap(NULL, message, count, width, &line);
7912 char *msg = malloc(len);
7916 outCount = fwrite(message, 1, count, stdout);
7919 dbgchk = wrap(msg, message, count, width, &line);
7920 if (dbgchk != len && appData.debugMode)
7921 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7922 outCount = fwrite(msg, 1, dbgchk, stdout);
7928 outCount = write(cp->fdTo, message, count);
7938 /* Output message to process, with "ms" milliseconds of delay
7939 between each character. This is needed when sending the logon
7940 script to ICC, which for some reason doesn't like the
7941 instantaneous send. */
7942 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7949 ChildProc *cp = (ChildProc *) pr;
7954 r = write(cp->fdTo, message++, 1);
7967 /**** Animation code by Hugh Fisher, DCS, ANU.
7969 Known problem: if a window overlapping the board is
7970 moved away while a piece is being animated underneath,
7971 the newly exposed area won't be updated properly.
7972 I can live with this.
7974 Known problem: if you look carefully at the animation
7975 of pieces in mono mode, they are being drawn as solid
7976 shapes without interior detail while moving. Fixing
7977 this would be a major complication for minimal return.
7980 /* Masks for XPM pieces. Black and white pieces can have
7981 different shapes, but in the interest of retaining my
7982 sanity pieces must have the same outline on both light
7983 and dark squares, and all pieces must use the same
7984 background square colors/images. */
7986 static int xpmDone = 0;
7989 CreateAnimMasks (pieceDepth)
7996 unsigned long plane;
7999 /* Need a bitmap just to get a GC with right depth */
8000 buf = XCreatePixmap(xDisplay, xBoardWindow,
8002 values.foreground = 1;
8003 values.background = 0;
8004 /* Don't use XtGetGC, not read only */
8005 maskGC = XCreateGC(xDisplay, buf,
8006 GCForeground | GCBackground, &values);
8007 XFreePixmap(xDisplay, buf);
8009 buf = XCreatePixmap(xDisplay, xBoardWindow,
8010 squareSize, squareSize, pieceDepth);
8011 values.foreground = XBlackPixel(xDisplay, xScreen);
8012 values.background = XWhitePixel(xDisplay, xScreen);
8013 bufGC = XCreateGC(xDisplay, buf,
8014 GCForeground | GCBackground, &values);
8016 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8017 /* Begin with empty mask */
8018 if(!xpmDone) // [HGM] pieces: keep using existing
8019 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8020 squareSize, squareSize, 1);
8021 XSetFunction(xDisplay, maskGC, GXclear);
8022 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8023 0, 0, squareSize, squareSize);
8025 /* Take a copy of the piece */
8030 XSetFunction(xDisplay, bufGC, GXcopy);
8031 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8033 0, 0, squareSize, squareSize, 0, 0);
8035 /* XOR the background (light) over the piece */
8036 XSetFunction(xDisplay, bufGC, GXxor);
8038 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8039 0, 0, squareSize, squareSize, 0, 0);
8041 XSetForeground(xDisplay, bufGC, lightSquareColor);
8042 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8045 /* We now have an inverted piece image with the background
8046 erased. Construct mask by just selecting all the non-zero
8047 pixels - no need to reconstruct the original image. */
8048 XSetFunction(xDisplay, maskGC, GXor);
8050 /* Might be quicker to download an XImage and create bitmap
8051 data from it rather than this N copies per piece, but it
8052 only takes a fraction of a second and there is a much
8053 longer delay for loading the pieces. */
8054 for (n = 0; n < pieceDepth; n ++) {
8055 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8056 0, 0, squareSize, squareSize,
8062 XFreePixmap(xDisplay, buf);
8063 XFreeGC(xDisplay, bufGC);
8064 XFreeGC(xDisplay, maskGC);
8068 InitAnimState (anim, info)
8070 XWindowAttributes * info;
8075 /* Each buffer is square size, same depth as window */
8076 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8077 squareSize, squareSize, info->depth);
8078 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8079 squareSize, squareSize, info->depth);
8081 /* Create a plain GC for blitting */
8082 mask = GCForeground | GCBackground | GCFunction |
8083 GCPlaneMask | GCGraphicsExposures;
8084 values.foreground = XBlackPixel(xDisplay, xScreen);
8085 values.background = XWhitePixel(xDisplay, xScreen);
8086 values.function = GXcopy;
8087 values.plane_mask = AllPlanes;
8088 values.graphics_exposures = False;
8089 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8091 /* Piece will be copied from an existing context at
8092 the start of each new animation/drag. */
8093 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8095 /* Outline will be a read-only copy of an existing */
8096 anim->outlineGC = None;
8102 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8103 XWindowAttributes info;
8105 if (xpmDone && gameInfo.variant == old) return;
8106 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8107 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8109 InitAnimState(&game, &info);
8110 InitAnimState(&player, &info);
8112 /* For XPM pieces, we need bitmaps to use as masks. */
8114 CreateAnimMasks(info.depth);
8120 static Boolean frameWaiting;
8122 static RETSIGTYPE FrameAlarm (sig)
8125 frameWaiting = False;
8126 /* In case System-V style signals. Needed?? */
8127 signal(SIGALRM, FrameAlarm);
8134 struct itimerval delay;
8136 XSync(xDisplay, False);
8139 frameWaiting = True;
8140 signal(SIGALRM, FrameAlarm);
8141 delay.it_interval.tv_sec =
8142 delay.it_value.tv_sec = time / 1000;
8143 delay.it_interval.tv_usec =
8144 delay.it_value.tv_usec = (time % 1000) * 1000;
8145 setitimer(ITIMER_REAL, &delay, NULL);
8146 while (frameWaiting) pause();
8147 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8148 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8149 setitimer(ITIMER_REAL, &delay, NULL);
8159 XSync(xDisplay, False);
8161 usleep(time * 1000);
8166 /* Convert board position to corner of screen rect and color */
8169 ScreenSquare(column, row, pt, color)
8170 int column; int row; XPoint * pt; int * color;
8173 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8174 pt->y = lineGap + row * (squareSize + lineGap);
8176 pt->x = lineGap + column * (squareSize + lineGap);
8177 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8179 *color = SquareColor(row, column);
8182 /* Convert window coords to square */
8185 BoardSquare(x, y, column, row)
8186 int x; int y; int * column; int * row;
8188 *column = EventToSquare(x, BOARD_WIDTH);
8189 if (flipView && *column >= 0)
8190 *column = BOARD_WIDTH - 1 - *column;
8191 *row = EventToSquare(y, BOARD_HEIGHT);
8192 if (!flipView && *row >= 0)
8193 *row = BOARD_HEIGHT - 1 - *row;
8198 #undef Max /* just in case */
8200 #define Max(a, b) ((a) > (b) ? (a) : (b))
8201 #define Min(a, b) ((a) < (b) ? (a) : (b))
8204 SetRect(rect, x, y, width, height)
8205 XRectangle * rect; int x; int y; int width; int height;
8209 rect->width = width;
8210 rect->height = height;
8213 /* Test if two frames overlap. If they do, return
8214 intersection rect within old and location of
8215 that rect within new. */
8218 Intersect(old, new, size, area, pt)
8219 XPoint * old; XPoint * new;
8220 int size; XRectangle * area; XPoint * pt;
8222 if (old->x > new->x + size || new->x > old->x + size ||
8223 old->y > new->y + size || new->y > old->y + size) {
8226 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8227 size - abs(old->x - new->x), size - abs(old->y - new->y));
8228 pt->x = Max(old->x - new->x, 0);
8229 pt->y = Max(old->y - new->y, 0);
8234 /* For two overlapping frames, return the rect(s)
8235 in the old that do not intersect with the new. */
8238 CalcUpdateRects(old, new, size, update, nUpdates)
8239 XPoint * old; XPoint * new; int size;
8240 XRectangle update[]; int * nUpdates;
8244 /* If old = new (shouldn't happen) then nothing to draw */
8245 if (old->x == new->x && old->y == new->y) {
8249 /* Work out what bits overlap. Since we know the rects
8250 are the same size we don't need a full intersect calc. */
8252 /* Top or bottom edge? */
8253 if (new->y > old->y) {
8254 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8256 } else if (old->y > new->y) {
8257 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8258 size, old->y - new->y);
8261 /* Left or right edge - don't overlap any update calculated above. */
8262 if (new->x > old->x) {
8263 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8264 new->x - old->x, size - abs(new->y - old->y));
8266 } else if (old->x > new->x) {
8267 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8268 old->x - new->x, size - abs(new->y - old->y));
8275 /* Generate a series of frame coords from start->mid->finish.
8276 The movement rate doubles until the half way point is
8277 reached, then halves back down to the final destination,
8278 which gives a nice slow in/out effect. The algorithmn
8279 may seem to generate too many intermediates for short
8280 moves, but remember that the purpose is to attract the
8281 viewers attention to the piece about to be moved and
8282 then to where it ends up. Too few frames would be less
8286 Tween(start, mid, finish, factor, frames, nFrames)
8287 XPoint * start; XPoint * mid;
8288 XPoint * finish; int factor;
8289 XPoint frames[]; int * nFrames;
8291 int fraction, n, count;
8295 /* Slow in, stepping 1/16th, then 1/8th, ... */
8297 for (n = 0; n < factor; n++)
8299 for (n = 0; n < factor; n++) {
8300 frames[count].x = start->x + (mid->x - start->x) / fraction;
8301 frames[count].y = start->y + (mid->y - start->y) / fraction;
8303 fraction = fraction / 2;
8307 frames[count] = *mid;
8310 /* Slow out, stepping 1/2, then 1/4, ... */
8312 for (n = 0; n < factor; n++) {
8313 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8314 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8316 fraction = fraction * 2;
8321 /* Draw a piece on the screen without disturbing what's there */
8324 SelectGCMask(piece, clip, outline, mask)
8325 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8329 /* Bitmap for piece being moved. */
8330 if (appData.monoMode) {
8331 *mask = *pieceToSolid(piece);
8332 } else if (useImages) {
8334 *mask = xpmMask[piece];
8336 *mask = ximMaskPm[piece];
8339 *mask = *pieceToSolid(piece);
8342 /* GC for piece being moved. Square color doesn't matter, but
8343 since it gets modified we make a copy of the original. */
8345 if (appData.monoMode)
8350 if (appData.monoMode)
8355 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8357 /* Outline only used in mono mode and is not modified */
8359 *outline = bwPieceGC;
8361 *outline = wbPieceGC;
8365 OverlayPiece(piece, clip, outline, dest)
8366 ChessSquare piece; GC clip; GC outline; Drawable dest;
8371 /* Draw solid rectangle which will be clipped to shape of piece */
8372 XFillRectangle(xDisplay, dest, clip,
8373 0, 0, squareSize, squareSize);
8374 if (appData.monoMode)
8375 /* Also draw outline in contrasting color for black
8376 on black / white on white cases */
8377 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8378 0, 0, squareSize, squareSize, 0, 0, 1);
8380 /* Copy the piece */
8385 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8387 0, 0, squareSize, squareSize,
8392 /* Animate the movement of a single piece */
8395 BeginAnimation(anim, piece, startColor, start)
8403 /* The old buffer is initialised with the start square (empty) */
8404 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8405 anim->prevFrame = *start;
8407 /* The piece will be drawn using its own bitmap as a matte */
8408 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8409 XSetClipMask(xDisplay, anim->pieceGC, mask);
8413 AnimationFrame(anim, frame, piece)
8418 XRectangle updates[4];
8423 /* Save what we are about to draw into the new buffer */
8424 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8425 frame->x, frame->y, squareSize, squareSize,
8428 /* Erase bits of the previous frame */
8429 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8430 /* Where the new frame overlapped the previous,
8431 the contents in newBuf are wrong. */
8432 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8433 overlap.x, overlap.y,
8434 overlap.width, overlap.height,
8436 /* Repaint the areas in the old that don't overlap new */
8437 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8438 for (i = 0; i < count; i++)
8439 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8440 updates[i].x - anim->prevFrame.x,
8441 updates[i].y - anim->prevFrame.y,
8442 updates[i].width, updates[i].height,
8443 updates[i].x, updates[i].y);
8445 /* Easy when no overlap */
8446 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8447 0, 0, squareSize, squareSize,
8448 anim->prevFrame.x, anim->prevFrame.y);
8451 /* Save this frame for next time round */
8452 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8453 0, 0, squareSize, squareSize,
8455 anim->prevFrame = *frame;
8457 /* Draw piece over original screen contents, not current,
8458 and copy entire rect. Wipes out overlapping piece images. */
8459 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8460 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8461 0, 0, squareSize, squareSize,
8462 frame->x, frame->y);
8466 EndAnimation (anim, finish)
8470 XRectangle updates[4];
8475 /* The main code will redraw the final square, so we
8476 only need to erase the bits that don't overlap. */
8477 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8478 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8479 for (i = 0; i < count; i++)
8480 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8481 updates[i].x - anim->prevFrame.x,
8482 updates[i].y - anim->prevFrame.y,
8483 updates[i].width, updates[i].height,
8484 updates[i].x, updates[i].y);
8486 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8487 0, 0, squareSize, squareSize,
8488 anim->prevFrame.x, anim->prevFrame.y);
8493 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8495 ChessSquare piece; int startColor;
8496 XPoint * start; XPoint * finish;
8497 XPoint frames[]; int nFrames;
8501 BeginAnimation(anim, piece, startColor, start);
8502 for (n = 0; n < nFrames; n++) {
8503 AnimationFrame(anim, &(frames[n]), piece);
8504 FrameDelay(appData.animSpeed);
8506 EndAnimation(anim, finish);
8509 /* Main control logic for deciding what to animate and how */
8512 AnimateMove(board, fromX, fromY, toX, toY)
8521 XPoint start, finish, mid;
8522 XPoint frames[kFactor * 2 + 1];
8523 int nFrames, startColor, endColor;
8525 /* Are we animating? */
8526 if (!appData.animate || appData.blindfold)
8529 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8530 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8531 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8533 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8534 piece = board[fromY][fromX];
8535 if (piece >= EmptySquare) return;
8540 hop = (piece == WhiteKnight || piece == BlackKnight);
8543 if (appData.debugMode) {
8544 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8545 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8546 piece, fromX, fromY, toX, toY); }
8548 ScreenSquare(fromX, fromY, &start, &startColor);
8549 ScreenSquare(toX, toY, &finish, &endColor);
8552 /* Knight: make diagonal movement then straight */
8553 if (abs(toY - fromY) < abs(toX - fromX)) {
8554 mid.x = start.x + (finish.x - start.x) / 2;
8558 mid.y = start.y + (finish.y - start.y) / 2;
8561 mid.x = start.x + (finish.x - start.x) / 2;
8562 mid.y = start.y + (finish.y - start.y) / 2;
8565 /* Don't use as many frames for very short moves */
8566 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8567 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8569 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8570 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8572 /* Be sure end square is redrawn */
8573 damage[toY][toX] = True;
8577 DragPieceBegin(x, y)
8580 int boardX, boardY, color;
8583 /* Are we animating? */
8584 if (!appData.animateDragging || appData.blindfold)
8587 /* Figure out which square we start in and the
8588 mouse position relative to top left corner. */
8589 BoardSquare(x, y, &boardX, &boardY);
8590 player.startBoardX = boardX;
8591 player.startBoardY = boardY;
8592 ScreenSquare(boardX, boardY, &corner, &color);
8593 player.startSquare = corner;
8594 player.startColor = color;
8595 /* As soon as we start dragging, the piece will jump slightly to
8596 be centered over the mouse pointer. */
8597 player.mouseDelta.x = squareSize/2;
8598 player.mouseDelta.y = squareSize/2;
8599 /* Initialise animation */
8600 player.dragPiece = PieceForSquare(boardX, boardY);
8602 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8603 player.dragActive = True;
8604 BeginAnimation(&player, player.dragPiece, color, &corner);
8605 /* Mark this square as needing to be redrawn. Note that
8606 we don't remove the piece though, since logically (ie
8607 as seen by opponent) the move hasn't been made yet. */
8608 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8609 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8610 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8611 corner.x, corner.y, squareSize, squareSize,
8612 0, 0); // [HGM] zh: unstack in stead of grab
8613 damage[boardY][boardX] = True;
8615 player.dragActive = False;
8625 /* Are we animating? */
8626 if (!appData.animateDragging || appData.blindfold)
8630 if (! player.dragActive)
8632 /* Move piece, maintaining same relative position
8633 of mouse within square */
8634 corner.x = x - player.mouseDelta.x;
8635 corner.y = y - player.mouseDelta.y;
8636 AnimationFrame(&player, &corner, player.dragPiece);
8638 if (appData.highlightDragging) {
8640 BoardSquare(x, y, &boardX, &boardY);
8641 SetHighlights(fromX, fromY, boardX, boardY);
8650 int boardX, boardY, color;
8653 /* Are we animating? */
8654 if (!appData.animateDragging || appData.blindfold)
8658 if (! player.dragActive)
8660 /* Last frame in sequence is square piece is
8661 placed on, which may not match mouse exactly. */
8662 BoardSquare(x, y, &boardX, &boardY);
8663 ScreenSquare(boardX, boardY, &corner, &color);
8664 EndAnimation(&player, &corner);
8666 /* Be sure end square is redrawn */
8667 damage[boardY][boardX] = True;
8669 /* This prevents weird things happening with fast successive
8670 clicks which on my Sun at least can cause motion events
8671 without corresponding press/release. */
8672 player.dragActive = False;
8675 /* Handle expose event while piece being dragged */
8680 if (!player.dragActive || appData.blindfold)
8683 /* What we're doing: logically, the move hasn't been made yet,
8684 so the piece is still in it's original square. But visually
8685 it's being dragged around the board. So we erase the square
8686 that the piece is on and draw it at the last known drag point. */
8687 BlankSquare(player.startSquare.x, player.startSquare.y,
8688 player.startColor, EmptySquare, xBoardWindow);
8689 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8690 damage[player.startBoardY][player.startBoardX] = TRUE;
8693 #include <sys/ioctl.h>
8694 int get_term_width()
8696 int fd, default_width;
8699 default_width = 79; // this is FICS default anyway...
8701 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8703 if (!ioctl(fd, TIOCGSIZE, &win))
8704 default_width = win.ts_cols;
8705 #elif defined(TIOCGWINSZ)
8707 if (!ioctl(fd, TIOCGWINSZ, &win))
8708 default_width = win.ws_col;
8710 return default_width;
8713 void update_ics_width()
8715 static int old_width = 0;
8716 int new_width = get_term_width();
8718 if (old_width != new_width)
8719 ics_printf("set width %d\n", new_width);
8720 old_width = new_width;
8723 void NotifyFrontendLogin()