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 DEBUG_FILE "xboard.debug"
1253 #define SetCurrentDirectory chdir
1254 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1258 // these two must some day move to frontend.h, when they are implemented
1259 Boolean MoveHistoryIsUp();
1260 Boolean GameListIsUp();
1262 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1265 // front-end part of option handling
1267 // [HGM] This platform-dependent table provides the location for storing the color info
1268 extern char *crWhite, * crBlack;
1272 &appData.whitePieceColor,
1273 &appData.blackPieceColor,
1274 &appData.lightSquareColor,
1275 &appData.darkSquareColor,
1276 &appData.highlightSquareColor,
1277 &appData.premoveHighlightColor,
1290 ParseFont(char *name, int number)
1291 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1293 case 0: // CLOCK_FONT
1294 appData.clockFont = strdup(name);
1296 case 1: // MESSAGE_FONT
1297 appData.font = strdup(name);
1299 case 2: // COORD_FONT
1300 appData.coordFont = strdup(name);
1309 { // only 2 fonts currently
1310 appData.clockFont = CLOCK_FONT_NAME;
1311 appData.coordFont = COORD_FONT_NAME;
1312 appData.font = DEFAULT_FONT_NAME;
1317 { // no-op, until we identify the code for this already in XBoard and move it here
1321 ParseColor(int n, char *name)
1322 { // in XBoard, just copy the color-name string
1323 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1327 ParseTextAttribs(ColorClass cc, char *s)
1329 (&appData.colorShout)[cc] = strdup(s);
1333 ParseBoardSize(void *addr, char *name)
1335 appData.boardSize = strdup(name);
1340 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1344 SetCommPortDefaults()
1345 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1348 // [HGM] args: these three cases taken out to stay in front-end
1350 SaveFontArg(FILE *f, ArgDescriptor *ad)
1353 switch((int)ad->argLoc) {
1354 case 0: // CLOCK_FONT
1355 name = appData.clockFont;
1357 case 1: // MESSAGE_FONT
1358 name = appData.font;
1360 case 2: // COORD_FONT
1361 name = appData.coordFont;
1366 // Do not save fonts for now, as the saved font would be board-size specific
1367 // and not suitable for a re-start at another board size
1368 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1373 { // nothing to do, as the sounds are at all times represented by their text-string names already
1377 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1378 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1379 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1383 SaveColor(FILE *f, ArgDescriptor *ad)
1384 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1385 if(colorVariable[(int)ad->argLoc])
1386 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1390 SaveBoardSize(FILE *f, char *name, void *addr)
1391 { // wrapper to shield back-end from BoardSize & sizeInfo
1392 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1396 ParseCommPortSettings(char *s)
1397 { // no such option in XBoard (yet)
1400 extern Widget engineOutputShell;
1401 extern Widget tagsShell, editTagsShell;
1403 GetActualPlacement(Widget wg, WindowPlacement *wp)
1413 XtSetArg(args[i], XtNx, &x); i++;
1414 XtSetArg(args[i], XtNy, &y); i++;
1415 XtSetArg(args[i], XtNwidth, &w); i++;
1416 XtSetArg(args[i], XtNheight, &h); i++;
1417 XtGetValues(wg, args, i);
1426 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1427 // In XBoard this will have to wait until awareness of window parameters is implemented
1428 GetActualPlacement(shellWidget, &wpMain);
1429 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1430 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1431 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1432 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1433 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1434 else GetActualPlacement(editShell, &wpComment);
1435 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1436 else GetActualPlacement(editTagsShell, &wpTags);
1440 PrintCommPortSettings(FILE *f, char *name)
1441 { // This option does not exist in XBoard
1445 MySearchPath(char *installDir, char *name, char *fullname)
1446 { // just append installDir and name. Perhaps ExpandPath should be used here?
1447 name = ExpandPathName(name);
1448 if(name && name[0] == '/') strcpy(fullname, name); else {
1449 sprintf(fullname, "%s%c%s", installDir, '/', name);
1455 MyGetFullPathName(char *name, char *fullname)
1456 { // should use ExpandPath?
1457 name = ExpandPathName(name);
1458 strcpy(fullname, name);
1463 EnsureOnScreen(int *x, int *y, int minX, int minY)
1470 { // [HGM] args: allows testing if main window is realized from back-end
1471 return xBoardWindow != 0;
1475 PopUpStartupDialog()
1476 { // start menu not implemented in XBoard
1479 ConvertToLine(int argc, char **argv)
1481 static char line[128*1024], buf[1024];
1485 for(i=1; i<argc; i++) {
1486 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1487 && argv[i][0] != '{' )
1488 sprintf(buf, "{%s} ", argv[i]);
1489 else sprintf(buf, "%s ", argv[i]);
1492 line[strlen(line)-1] = NULLCHAR;
1496 //--------------------------------------------------------------------------------------------
1499 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1501 #define BoardSize int
1502 void InitDrawingSizes(BoardSize boardSize, int flags)
1503 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1504 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1506 XtGeometryResult gres;
1509 if(!formWidget) return;
1512 * Enable shell resizing.
1514 shellArgs[0].value = (XtArgVal) &w;
1515 shellArgs[1].value = (XtArgVal) &h;
1516 XtGetValues(shellWidget, shellArgs, 2);
1518 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1519 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1520 XtSetValues(shellWidget, &shellArgs[2], 4);
1522 XtSetArg(args[0], XtNdefaultDistance, &sep);
1523 XtGetValues(formWidget, args, 1);
1525 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1526 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1529 XtSetArg(args[0], XtNwidth, boardWidth);
1530 XtSetArg(args[1], XtNheight, boardHeight);
1531 XtSetValues(boardWidget, args, 2);
1533 timerWidth = (boardWidth - sep) / 2;
1534 XtSetArg(args[0], XtNwidth, timerWidth);
1535 XtSetValues(whiteTimerWidget, args, 1);
1536 XtSetValues(blackTimerWidget, args, 1);
1538 XawFormDoLayout(formWidget, False);
1540 if (appData.titleInWindow) {
1542 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1543 XtSetArg(args[i], XtNheight, &h); i++;
1544 XtGetValues(titleWidget, args, i);
1546 w = boardWidth - 2*bor;
1548 XtSetArg(args[0], XtNwidth, &w);
1549 XtGetValues(menuBarWidget, args, 1);
1550 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1553 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1554 if (gres != XtGeometryYes && appData.debugMode) {
1556 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1557 programName, gres, w, h, wr, hr);
1561 XawFormDoLayout(formWidget, True);
1564 * Inhibit shell resizing.
1566 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1567 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1568 shellArgs[4].value = shellArgs[2].value = w;
1569 shellArgs[5].value = shellArgs[3].value = h;
1570 XtSetValues(shellWidget, &shellArgs[0], 6);
1572 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1575 for(i=0; i<4; i++) {
1577 for(p=0; p<=(int)WhiteKing; p++)
1578 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1579 if(gameInfo.variant == VariantShogi) {
1580 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1581 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1582 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1583 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1584 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1587 if(gameInfo.variant == VariantGothic) {
1588 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1592 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1593 for(p=0; p<=(int)WhiteKing; p++)
1594 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1595 if(gameInfo.variant == VariantShogi) {
1596 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1597 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1598 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1599 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1600 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1603 if(gameInfo.variant == VariantGothic) {
1604 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1610 for(i=0; i<2; i++) {
1612 for(p=0; p<=(int)WhiteKing; p++)
1613 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1614 if(gameInfo.variant == VariantShogi) {
1615 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1616 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1617 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1618 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1619 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1622 if(gameInfo.variant == VariantGothic) {
1623 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1634 void EscapeExpand(char *p, char *q)
1635 { // [HGM] initstring: routine to shape up string arguments
1636 while(*p++ = *q++) if(p[-1] == '\\')
1638 case 'n': p[-1] = '\n'; break;
1639 case 'r': p[-1] = '\r'; break;
1640 case 't': p[-1] = '\t'; break;
1641 case '\\': p[-1] = '\\'; break;
1642 case 0: *p = 0; return;
1643 default: p[-1] = q[-1]; break;
1652 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1653 XSetWindowAttributes window_attributes;
1655 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1656 XrmValue vFrom, vTo;
1657 XtGeometryResult gres;
1660 int forceMono = False;
1662 srandom(time(0)); // [HGM] book: make random truly random
1664 setbuf(stdout, NULL);
1665 setbuf(stderr, NULL);
1668 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1669 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1673 programName = strrchr(argv[0], '/');
1674 if (programName == NULL)
1675 programName = argv[0];
1680 XtSetLanguageProc(NULL, NULL, NULL);
1681 bindtextdomain(PACKAGE, LOCALEDIR);
1682 textdomain(PACKAGE);
1686 XtAppInitialize(&appContext, "XBoard", shellOptions,
1687 XtNumber(shellOptions),
1688 &argc, argv, xboardResources, NULL, 0);
1689 appData.boardSize = "";
1690 InitAppData(ConvertToLine(argc, argv));
1692 if (p == NULL) p = "/tmp";
1693 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1694 gameCopyFilename = (char*) malloc(i);
1695 gamePasteFilename = (char*) malloc(i);
1696 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1697 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1699 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1700 clientResources, XtNumber(clientResources),
1703 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1704 static char buf[MSG_SIZ];
1705 EscapeExpand(buf, appData.initString);
1706 appData.initString = strdup(buf);
1707 EscapeExpand(buf, appData.secondInitString);
1708 appData.secondInitString = strdup(buf);
1709 EscapeExpand(buf, appData.firstComputerString);
1710 appData.firstComputerString = strdup(buf);
1711 EscapeExpand(buf, appData.secondComputerString);
1712 appData.secondComputerString = strdup(buf);
1715 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1718 if (chdir(chessDir) != 0) {
1719 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1725 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1726 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1727 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1728 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1731 setbuf(debugFP, NULL);
1734 /* [HGM,HR] make sure board size is acceptable */
1735 if(appData.NrFiles > BOARD_FILES ||
1736 appData.NrRanks > BOARD_RANKS )
1737 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1740 /* This feature does not work; animation needs a rewrite */
1741 appData.highlightDragging = FALSE;
1745 xDisplay = XtDisplay(shellWidget);
1746 xScreen = DefaultScreen(xDisplay);
1747 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1749 gameInfo.variant = StringToVariant(appData.variant);
1750 InitPosition(FALSE);
1753 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1755 if (isdigit(appData.boardSize[0])) {
1756 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1757 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1758 &fontPxlSize, &smallLayout, &tinyLayout);
1760 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1761 programName, appData.boardSize);
1765 /* Find some defaults; use the nearest known size */
1766 SizeDefaults *szd, *nearest;
1767 int distance = 99999;
1768 nearest = szd = sizeDefaults;
1769 while (szd->name != NULL) {
1770 if (abs(szd->squareSize - squareSize) < distance) {
1772 distance = abs(szd->squareSize - squareSize);
1773 if (distance == 0) break;
1777 if (i < 2) lineGap = nearest->lineGap;
1778 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1779 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1780 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1781 if (i < 6) smallLayout = nearest->smallLayout;
1782 if (i < 7) tinyLayout = nearest->tinyLayout;
1785 SizeDefaults *szd = sizeDefaults;
1786 if (*appData.boardSize == NULLCHAR) {
1787 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1788 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1791 if (szd->name == NULL) szd--;
1792 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1794 while (szd->name != NULL &&
1795 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1796 if (szd->name == NULL) {
1797 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1798 programName, appData.boardSize);
1802 squareSize = szd->squareSize;
1803 lineGap = szd->lineGap;
1804 clockFontPxlSize = szd->clockFontPxlSize;
1805 coordFontPxlSize = szd->coordFontPxlSize;
1806 fontPxlSize = szd->fontPxlSize;
1807 smallLayout = szd->smallLayout;
1808 tinyLayout = szd->tinyLayout;
1811 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1812 if (strlen(appData.pixmapDirectory) > 0) {
1813 p = ExpandPathName(appData.pixmapDirectory);
1815 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1816 appData.pixmapDirectory);
1819 if (appData.debugMode) {
1820 fprintf(stderr, _("\
1821 XBoard square size (hint): %d\n\
1822 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1824 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1825 if (appData.debugMode) {
1826 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1830 /* [HR] height treated separately (hacked) */
1831 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1832 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1833 if (appData.showJail == 1) {
1834 /* Jail on top and bottom */
1835 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1836 XtSetArg(boardArgs[2], XtNheight,
1837 boardHeight + 2*(lineGap + squareSize));
1838 } else if (appData.showJail == 2) {
1840 XtSetArg(boardArgs[1], XtNwidth,
1841 boardWidth + 2*(lineGap + squareSize));
1842 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1845 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1846 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1850 * Determine what fonts to use.
1852 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1853 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1854 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1855 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1856 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1857 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1858 appData.font = FindFont(appData.font, fontPxlSize);
1859 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1860 countFontStruct = XQueryFont(xDisplay, countFontID);
1861 // appData.font = FindFont(appData.font, fontPxlSize);
1863 xdb = XtDatabase(xDisplay);
1864 XrmPutStringResource(&xdb, "*font", appData.font);
1867 * Detect if there are not enough colors available and adapt.
1869 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1870 appData.monoMode = True;
1873 if (!appData.monoMode) {
1874 vFrom.addr = (caddr_t) appData.lightSquareColor;
1875 vFrom.size = strlen(appData.lightSquareColor);
1876 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1877 if (vTo.addr == NULL) {
1878 appData.monoMode = True;
1881 lightSquareColor = *(Pixel *) vTo.addr;
1884 if (!appData.monoMode) {
1885 vFrom.addr = (caddr_t) appData.darkSquareColor;
1886 vFrom.size = strlen(appData.darkSquareColor);
1887 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1888 if (vTo.addr == NULL) {
1889 appData.monoMode = True;
1892 darkSquareColor = *(Pixel *) vTo.addr;
1895 if (!appData.monoMode) {
1896 vFrom.addr = (caddr_t) appData.whitePieceColor;
1897 vFrom.size = strlen(appData.whitePieceColor);
1898 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1899 if (vTo.addr == NULL) {
1900 appData.monoMode = True;
1903 whitePieceColor = *(Pixel *) vTo.addr;
1906 if (!appData.monoMode) {
1907 vFrom.addr = (caddr_t) appData.blackPieceColor;
1908 vFrom.size = strlen(appData.blackPieceColor);
1909 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1910 if (vTo.addr == NULL) {
1911 appData.monoMode = True;
1914 blackPieceColor = *(Pixel *) vTo.addr;
1918 if (!appData.monoMode) {
1919 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1920 vFrom.size = strlen(appData.highlightSquareColor);
1921 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1922 if (vTo.addr == NULL) {
1923 appData.monoMode = True;
1926 highlightSquareColor = *(Pixel *) vTo.addr;
1930 if (!appData.monoMode) {
1931 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1932 vFrom.size = strlen(appData.premoveHighlightColor);
1933 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1934 if (vTo.addr == NULL) {
1935 appData.monoMode = True;
1938 premoveHighlightColor = *(Pixel *) vTo.addr;
1943 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1946 if (appData.bitmapDirectory == NULL ||
1947 appData.bitmapDirectory[0] == NULLCHAR)
1948 appData.bitmapDirectory = DEF_BITMAP_DIR;
1951 if (appData.lowTimeWarning && !appData.monoMode) {
1952 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1953 vFrom.size = strlen(appData.lowTimeWarningColor);
1954 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1955 if (vTo.addr == NULL)
1956 appData.monoMode = True;
1958 lowTimeWarningColor = *(Pixel *) vTo.addr;
1961 if (appData.monoMode && appData.debugMode) {
1962 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1963 (unsigned long) XWhitePixel(xDisplay, xScreen),
1964 (unsigned long) XBlackPixel(xDisplay, xScreen));
1967 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1968 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1969 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1970 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1971 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1972 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1973 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1974 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1975 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1976 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1978 if (appData.colorize) {
1980 _("%s: can't parse color names; disabling colorization\n"),
1983 appData.colorize = FALSE;
1985 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1986 textColors[ColorNone].attr = 0;
1988 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1994 layoutName = "tinyLayout";
1995 } else if (smallLayout) {
1996 layoutName = "smallLayout";
1998 layoutName = "normalLayout";
2000 /* Outer layoutWidget is there only to provide a name for use in
2001 resources that depend on the layout style */
2003 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2004 layoutArgs, XtNumber(layoutArgs));
2006 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2007 formArgs, XtNumber(formArgs));
2008 XtSetArg(args[0], XtNdefaultDistance, &sep);
2009 XtGetValues(formWidget, args, 1);
2012 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2013 XtSetArg(args[0], XtNtop, XtChainTop);
2014 XtSetArg(args[1], XtNbottom, XtChainTop);
2015 XtSetArg(args[2], XtNright, XtChainLeft);
2016 XtSetValues(menuBarWidget, args, 3);
2018 widgetList[j++] = whiteTimerWidget =
2019 XtCreateWidget("whiteTime", labelWidgetClass,
2020 formWidget, timerArgs, XtNumber(timerArgs));
2021 XtSetArg(args[0], XtNfont, clockFontStruct);
2022 XtSetArg(args[1], XtNtop, XtChainTop);
2023 XtSetArg(args[2], XtNbottom, XtChainTop);
2024 XtSetValues(whiteTimerWidget, args, 3);
2026 widgetList[j++] = blackTimerWidget =
2027 XtCreateWidget("blackTime", labelWidgetClass,
2028 formWidget, timerArgs, XtNumber(timerArgs));
2029 XtSetArg(args[0], XtNfont, clockFontStruct);
2030 XtSetArg(args[1], XtNtop, XtChainTop);
2031 XtSetArg(args[2], XtNbottom, XtChainTop);
2032 XtSetValues(blackTimerWidget, args, 3);
2034 if (appData.titleInWindow) {
2035 widgetList[j++] = titleWidget =
2036 XtCreateWidget("title", labelWidgetClass, formWidget,
2037 titleArgs, XtNumber(titleArgs));
2038 XtSetArg(args[0], XtNtop, XtChainTop);
2039 XtSetArg(args[1], XtNbottom, XtChainTop);
2040 XtSetValues(titleWidget, args, 2);
2043 if (appData.showButtonBar) {
2044 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2045 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2046 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2047 XtSetArg(args[2], XtNtop, XtChainTop);
2048 XtSetArg(args[3], XtNbottom, XtChainTop);
2049 XtSetValues(buttonBarWidget, args, 4);
2052 widgetList[j++] = messageWidget =
2053 XtCreateWidget("message", labelWidgetClass, formWidget,
2054 messageArgs, XtNumber(messageArgs));
2055 XtSetArg(args[0], XtNtop, XtChainTop);
2056 XtSetArg(args[1], XtNbottom, XtChainTop);
2057 XtSetValues(messageWidget, args, 2);
2059 widgetList[j++] = boardWidget =
2060 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2061 XtNumber(boardArgs));
2063 XtManageChildren(widgetList, j);
2065 timerWidth = (boardWidth - sep) / 2;
2066 XtSetArg(args[0], XtNwidth, timerWidth);
2067 XtSetValues(whiteTimerWidget, args, 1);
2068 XtSetValues(blackTimerWidget, args, 1);
2070 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2071 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2072 XtGetValues(whiteTimerWidget, args, 2);
2074 if (appData.showButtonBar) {
2075 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2076 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2077 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2081 * formWidget uses these constraints but they are stored
2085 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2086 XtSetValues(menuBarWidget, args, i);
2087 if (appData.titleInWindow) {
2090 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2091 XtSetValues(whiteTimerWidget, args, i);
2093 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2094 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2095 XtSetValues(blackTimerWidget, args, i);
2097 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2098 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2099 XtSetValues(titleWidget, args, i);
2101 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2102 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2103 XtSetValues(messageWidget, args, i);
2104 if (appData.showButtonBar) {
2106 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2107 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2108 XtSetValues(buttonBarWidget, args, i);
2112 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2113 XtSetValues(whiteTimerWidget, args, i);
2115 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2116 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2117 XtSetValues(blackTimerWidget, args, i);
2119 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2120 XtSetValues(titleWidget, args, i);
2122 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2123 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2124 XtSetValues(messageWidget, args, i);
2125 if (appData.showButtonBar) {
2127 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2128 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2129 XtSetValues(buttonBarWidget, args, i);
2134 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2135 XtSetValues(whiteTimerWidget, args, i);
2137 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2138 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2139 XtSetValues(blackTimerWidget, args, i);
2141 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2142 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2143 XtSetValues(messageWidget, args, i);
2144 if (appData.showButtonBar) {
2146 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2147 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2148 XtSetValues(buttonBarWidget, args, i);
2152 XtSetArg(args[0], XtNfromVert, messageWidget);
2153 XtSetArg(args[1], XtNtop, XtChainTop);
2154 XtSetArg(args[2], XtNbottom, XtChainBottom);
2155 XtSetArg(args[3], XtNleft, XtChainLeft);
2156 XtSetArg(args[4], XtNright, XtChainRight);
2157 XtSetValues(boardWidget, args, 5);
2159 XtRealizeWidget(shellWidget);
2162 XtSetArg(args[0], XtNx, wpMain.x);
2163 XtSetArg(args[1], XtNy, wpMain.y);
2164 XtSetValues(shellWidget, args, 2);
2168 * Correct the width of the message and title widgets.
2169 * It is not known why some systems need the extra fudge term.
2170 * The value "2" is probably larger than needed.
2172 XawFormDoLayout(formWidget, False);
2174 #define WIDTH_FUDGE 2
2176 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2177 XtSetArg(args[i], XtNheight, &h); i++;
2178 XtGetValues(messageWidget, args, i);
2179 if (appData.showButtonBar) {
2181 XtSetArg(args[i], XtNwidth, &w); i++;
2182 XtGetValues(buttonBarWidget, args, i);
2183 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2185 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2188 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2189 if (gres != XtGeometryYes && appData.debugMode) {
2190 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2191 programName, gres, w, h, wr, hr);
2194 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2195 /* The size used for the child widget in layout lags one resize behind
2196 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2198 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2199 if (gres != XtGeometryYes && appData.debugMode) {
2200 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2201 programName, gres, w, h, wr, hr);
2204 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2205 XtSetArg(args[1], XtNright, XtChainRight);
2206 XtSetValues(messageWidget, args, 2);
2208 if (appData.titleInWindow) {
2210 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2211 XtSetArg(args[i], XtNheight, &h); i++;
2212 XtGetValues(titleWidget, args, i);
2214 w = boardWidth - 2*bor;
2216 XtSetArg(args[0], XtNwidth, &w);
2217 XtGetValues(menuBarWidget, args, 1);
2218 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2221 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2222 if (gres != XtGeometryYes && appData.debugMode) {
2224 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2225 programName, gres, w, h, wr, hr);
2228 XawFormDoLayout(formWidget, True);
2230 xBoardWindow = XtWindow(boardWidget);
2232 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2233 // not need to go into InitDrawingSizes().
2237 * Create X checkmark bitmap and initialize option menu checks.
2239 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2240 checkmark_bits, checkmark_width, checkmark_height);
2241 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2242 if (appData.alwaysPromoteToQueen) {
2243 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2246 if (appData.animateDragging) {
2247 XtSetValues(XtNameToWidget(menuBarWidget,
2248 "menuOptions.Animate Dragging"),
2251 if (appData.animate) {
2252 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2255 if (appData.autoComment) {
2256 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2259 if (appData.autoCallFlag) {
2260 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2263 if (appData.autoFlipView) {
2264 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2267 if (appData.autoObserve) {
2268 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2271 if (appData.autoRaiseBoard) {
2272 XtSetValues(XtNameToWidget(menuBarWidget,
2273 "menuOptions.Auto Raise Board"), args, 1);
2275 if (appData.autoSaveGames) {
2276 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2279 if (appData.saveGameFile[0] != NULLCHAR) {
2280 /* Can't turn this off from menu */
2281 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2283 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2287 if (appData.blindfold) {
2288 XtSetValues(XtNameToWidget(menuBarWidget,
2289 "menuOptions.Blindfold"), args, 1);
2291 if (appData.flashCount > 0) {
2292 XtSetValues(XtNameToWidget(menuBarWidget,
2293 "menuOptions.Flash Moves"),
2296 if (appData.getMoveList) {
2297 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2301 if (appData.highlightDragging) {
2302 XtSetValues(XtNameToWidget(menuBarWidget,
2303 "menuOptions.Highlight Dragging"),
2307 if (appData.highlightLastMove) {
2308 XtSetValues(XtNameToWidget(menuBarWidget,
2309 "menuOptions.Highlight Last Move"),
2312 if (appData.icsAlarm) {
2313 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2316 if (appData.ringBellAfterMoves) {
2317 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2320 if (appData.oldSaveStyle) {
2321 XtSetValues(XtNameToWidget(menuBarWidget,
2322 "menuOptions.Old Save Style"), args, 1);
2324 if (appData.periodicUpdates) {
2325 XtSetValues(XtNameToWidget(menuBarWidget,
2326 "menuOptions.Periodic Updates"), args, 1);
2328 if (appData.ponderNextMove) {
2329 XtSetValues(XtNameToWidget(menuBarWidget,
2330 "menuOptions.Ponder Next Move"), args, 1);
2332 if (appData.popupExitMessage) {
2333 XtSetValues(XtNameToWidget(menuBarWidget,
2334 "menuOptions.Popup Exit Message"), args, 1);
2336 if (appData.popupMoveErrors) {
2337 XtSetValues(XtNameToWidget(menuBarWidget,
2338 "menuOptions.Popup Move Errors"), args, 1);
2340 if (appData.premove) {
2341 XtSetValues(XtNameToWidget(menuBarWidget,
2342 "menuOptions.Premove"), args, 1);
2344 if (appData.quietPlay) {
2345 XtSetValues(XtNameToWidget(menuBarWidget,
2346 "menuOptions.Quiet Play"), args, 1);
2348 if (appData.showCoords) {
2349 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2352 if (appData.hideThinkingFromHuman) {
2353 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2356 if (appData.testLegality) {
2357 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2360 if (saveSettingsOnExit) {
2361 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2368 ReadBitmap(&wIconPixmap, "icon_white.bm",
2369 icon_white_bits, icon_white_width, icon_white_height);
2370 ReadBitmap(&bIconPixmap, "icon_black.bm",
2371 icon_black_bits, icon_black_width, icon_black_height);
2372 iconPixmap = wIconPixmap;
2374 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2375 XtSetValues(shellWidget, args, i);
2378 * Create a cursor for the board widget.
2380 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2381 XChangeWindowAttributes(xDisplay, xBoardWindow,
2382 CWCursor, &window_attributes);
2385 * Inhibit shell resizing.
2387 shellArgs[0].value = (XtArgVal) &w;
2388 shellArgs[1].value = (XtArgVal) &h;
2389 XtGetValues(shellWidget, shellArgs, 2);
2390 shellArgs[4].value = shellArgs[2].value = w;
2391 shellArgs[5].value = shellArgs[3].value = h;
2392 XtSetValues(shellWidget, &shellArgs[2], 4);
2393 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2394 marginH = h - boardHeight;
2396 CatchDeleteWindow(shellWidget, "QuitProc");
2401 if (appData.bitmapDirectory[0] != NULLCHAR) {
2408 /* Create regular pieces */
2409 if (!useImages) CreatePieces();
2414 if (appData.animate || appData.animateDragging)
2417 XtAugmentTranslations(formWidget,
2418 XtParseTranslationTable(globalTranslations));
2419 XtAugmentTranslations(boardWidget,
2420 XtParseTranslationTable(boardTranslations));
2421 XtAugmentTranslations(whiteTimerWidget,
2422 XtParseTranslationTable(whiteTranslations));
2423 XtAugmentTranslations(blackTimerWidget,
2424 XtParseTranslationTable(blackTranslations));
2426 /* Why is the following needed on some versions of X instead
2427 * of a translation? */
2428 XtAddEventHandler(boardWidget, ExposureMask, False,
2429 (XtEventHandler) EventProc, NULL);
2432 /* [AS] Restore layout */
2433 if( wpMoveHistory.visible ) {
2437 if( wpEvalGraph.visible )
2442 if( wpEngineOutput.visible ) {
2443 EngineOutputPopUp();
2448 if (errorExitStatus == -1) {
2449 if (appData.icsActive) {
2450 /* We now wait until we see "login:" from the ICS before
2451 sending the logon script (problems with timestamp otherwise) */
2452 /*ICSInitScript();*/
2453 if (appData.icsInputBox) ICSInputBoxPopUp();
2457 signal(SIGWINCH, TermSizeSigHandler);
2459 signal(SIGINT, IntSigHandler);
2460 signal(SIGTERM, IntSigHandler);
2461 if (*appData.cmailGameName != NULLCHAR) {
2462 signal(SIGUSR1, CmailSigHandler);
2465 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2468 XtAppMainLoop(appContext);
2469 if (appData.debugMode) fclose(debugFP); // [DM] debug
2476 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2477 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2479 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2480 unlink(gameCopyFilename);
2481 unlink(gamePasteFilename);
2484 RETSIGTYPE TermSizeSigHandler(int sig)
2497 CmailSigHandler(sig)
2503 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2505 /* Activate call-back function CmailSigHandlerCallBack() */
2506 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2508 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2512 CmailSigHandlerCallBack(isr, closure, message, count, error)
2520 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2522 /**** end signal code ****/
2532 f = fopen(appData.icsLogon, "r");
2538 strcat(buf, appData.icsLogon);
2539 f = fopen(buf, "r");
2543 ProcessICSInitScript(f);
2550 EditCommentPopDown();
2565 if (!menuBarWidget) return;
2566 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2568 DisplayError("menuStep.Revert", 0);
2570 XtSetSensitive(w, !grey);
2575 SetMenuEnables(enab)
2579 if (!menuBarWidget) return;
2580 while (enab->name != NULL) {
2581 w = XtNameToWidget(menuBarWidget, enab->name);
2583 DisplayError(enab->name, 0);
2585 XtSetSensitive(w, enab->value);
2591 Enables icsEnables[] = {
2592 { "menuFile.Mail Move", False },
2593 { "menuFile.Reload CMail Message", False },
2594 { "menuMode.Machine Black", False },
2595 { "menuMode.Machine White", False },
2596 { "menuMode.Analysis Mode", False },
2597 { "menuMode.Analyze File", False },
2598 { "menuMode.Two Machines", False },
2600 { "menuHelp.Hint", False },
2601 { "menuHelp.Book", False },
2602 { "menuStep.Move Now", False },
2603 { "menuOptions.Periodic Updates", False },
2604 { "menuOptions.Hide Thinking", False },
2605 { "menuOptions.Ponder Next Move", False },
2610 Enables ncpEnables[] = {
2611 { "menuFile.Mail Move", False },
2612 { "menuFile.Reload CMail Message", False },
2613 { "menuMode.Machine White", False },
2614 { "menuMode.Machine Black", False },
2615 { "menuMode.Analysis Mode", False },
2616 { "menuMode.Analyze File", False },
2617 { "menuMode.Two Machines", False },
2618 { "menuMode.ICS Client", False },
2619 { "menuMode.ICS Input Box", False },
2620 { "Action", False },
2621 { "menuStep.Revert", False },
2622 { "menuStep.Move Now", False },
2623 { "menuStep.Retract Move", False },
2624 { "menuOptions.Auto Comment", False },
2625 { "menuOptions.Auto Flag", False },
2626 { "menuOptions.Auto Flip View", False },
2627 { "menuOptions.Auto Observe", False },
2628 { "menuOptions.Auto Raise Board", False },
2629 { "menuOptions.Get Move List", False },
2630 { "menuOptions.ICS Alarm", False },
2631 { "menuOptions.Move Sound", False },
2632 { "menuOptions.Quiet Play", False },
2633 { "menuOptions.Hide Thinking", False },
2634 { "menuOptions.Periodic Updates", False },
2635 { "menuOptions.Ponder Next Move", False },
2636 { "menuHelp.Hint", False },
2637 { "menuHelp.Book", False },
2641 Enables gnuEnables[] = {
2642 { "menuMode.ICS Client", False },
2643 { "menuMode.ICS Input Box", False },
2644 { "menuAction.Accept", False },
2645 { "menuAction.Decline", False },
2646 { "menuAction.Rematch", False },
2647 { "menuAction.Adjourn", False },
2648 { "menuAction.Stop Examining", False },
2649 { "menuAction.Stop Observing", False },
2650 { "menuStep.Revert", False },
2651 { "menuOptions.Auto Comment", False },
2652 { "menuOptions.Auto Observe", False },
2653 { "menuOptions.Auto Raise Board", False },
2654 { "menuOptions.Get Move List", False },
2655 { "menuOptions.Premove", False },
2656 { "menuOptions.Quiet Play", False },
2658 /* The next two options rely on SetCmailMode being called *after* */
2659 /* SetGNUMode so that when GNU is being used to give hints these */
2660 /* menu options are still available */
2662 { "menuFile.Mail Move", False },
2663 { "menuFile.Reload CMail Message", False },
2667 Enables cmailEnables[] = {
2669 { "menuAction.Call Flag", False },
2670 { "menuAction.Draw", True },
2671 { "menuAction.Adjourn", False },
2672 { "menuAction.Abort", False },
2673 { "menuAction.Stop Observing", False },
2674 { "menuAction.Stop Examining", False },
2675 { "menuFile.Mail Move", True },
2676 { "menuFile.Reload CMail Message", True },
2680 Enables trainingOnEnables[] = {
2681 { "menuMode.Edit Comment", False },
2682 { "menuMode.Pause", False },
2683 { "menuStep.Forward", False },
2684 { "menuStep.Backward", False },
2685 { "menuStep.Forward to End", False },
2686 { "menuStep.Back to Start", False },
2687 { "menuStep.Move Now", False },
2688 { "menuStep.Truncate Game", False },
2692 Enables trainingOffEnables[] = {
2693 { "menuMode.Edit Comment", True },
2694 { "menuMode.Pause", True },
2695 { "menuStep.Forward", True },
2696 { "menuStep.Backward", True },
2697 { "menuStep.Forward to End", True },
2698 { "menuStep.Back to Start", True },
2699 { "menuStep.Move Now", True },
2700 { "menuStep.Truncate Game", True },
2704 Enables machineThinkingEnables[] = {
2705 { "menuFile.Load Game", False },
2706 { "menuFile.Load Next Game", False },
2707 { "menuFile.Load Previous Game", False },
2708 { "menuFile.Reload Same Game", False },
2709 { "menuFile.Paste Game", False },
2710 { "menuFile.Load Position", False },
2711 { "menuFile.Load Next Position", False },
2712 { "menuFile.Load Previous Position", False },
2713 { "menuFile.Reload Same Position", False },
2714 { "menuFile.Paste Position", False },
2715 { "menuMode.Machine White", False },
2716 { "menuMode.Machine Black", False },
2717 { "menuMode.Two Machines", False },
2718 { "menuStep.Retract Move", False },
2722 Enables userThinkingEnables[] = {
2723 { "menuFile.Load Game", True },
2724 { "menuFile.Load Next Game", True },
2725 { "menuFile.Load Previous Game", True },
2726 { "menuFile.Reload Same Game", True },
2727 { "menuFile.Paste Game", True },
2728 { "menuFile.Load Position", True },
2729 { "menuFile.Load Next Position", True },
2730 { "menuFile.Load Previous Position", True },
2731 { "menuFile.Reload Same Position", True },
2732 { "menuFile.Paste Position", True },
2733 { "menuMode.Machine White", True },
2734 { "menuMode.Machine Black", True },
2735 { "menuMode.Two Machines", True },
2736 { "menuStep.Retract Move", True },
2742 SetMenuEnables(icsEnables);
2745 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2746 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2753 SetMenuEnables(ncpEnables);
2759 SetMenuEnables(gnuEnables);
2765 SetMenuEnables(cmailEnables);
2771 SetMenuEnables(trainingOnEnables);
2772 if (appData.showButtonBar) {
2773 XtSetSensitive(buttonBarWidget, False);
2779 SetTrainingModeOff()
2781 SetMenuEnables(trainingOffEnables);
2782 if (appData.showButtonBar) {
2783 XtSetSensitive(buttonBarWidget, True);
2788 SetUserThinkingEnables()
2790 if (appData.noChessProgram) return;
2791 SetMenuEnables(userThinkingEnables);
2795 SetMachineThinkingEnables()
2797 if (appData.noChessProgram) return;
2798 SetMenuEnables(machineThinkingEnables);
2800 case MachinePlaysBlack:
2801 case MachinePlaysWhite:
2802 case TwoMachinesPlay:
2803 XtSetSensitive(XtNameToWidget(menuBarWidget,
2804 ModeToWidgetName(gameMode)), True);
2811 #define Abs(n) ((n)<0 ? -(n) : (n))
2814 * Find a font that matches "pattern" that is as close as
2815 * possible to the targetPxlSize. Prefer fonts that are k
2816 * pixels smaller to fonts that are k pixels larger. The
2817 * pattern must be in the X Consortium standard format,
2818 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2819 * The return value should be freed with XtFree when no
2822 char *FindFont(pattern, targetPxlSize)
2826 char **fonts, *p, *best, *scalable, *scalableTail;
2827 int i, j, nfonts, minerr, err, pxlSize;
2830 char **missing_list;
2832 char *def_string, *base_fnt_lst, strInt[3];
2834 XFontStruct **fnt_list;
2836 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2837 sprintf(strInt, "%d", targetPxlSize);
2838 p = strstr(pattern, "--");
2839 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2840 strcat(base_fnt_lst, strInt);
2841 strcat(base_fnt_lst, strchr(p + 2, '-'));
2843 if ((fntSet = XCreateFontSet(xDisplay,
2847 &def_string)) == NULL) {
2849 fprintf(stderr, _("Unable to create font set.\n"));
2853 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2855 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2857 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2858 programName, pattern);
2866 for (i=0; i<nfonts; i++) {
2869 if (*p != '-') continue;
2871 if (*p == NULLCHAR) break;
2872 if (*p++ == '-') j++;
2874 if (j < 7) continue;
2877 scalable = fonts[i];
2880 err = pxlSize - targetPxlSize;
2881 if (Abs(err) < Abs(minerr) ||
2882 (minerr > 0 && err < 0 && -err == minerr)) {
2888 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2889 /* If the error is too big and there is a scalable font,
2890 use the scalable font. */
2891 int headlen = scalableTail - scalable;
2892 p = (char *) XtMalloc(strlen(scalable) + 10);
2893 while (isdigit(*scalableTail)) scalableTail++;
2894 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2896 p = (char *) XtMalloc(strlen(best) + 1);
2899 if (appData.debugMode) {
2900 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2901 pattern, targetPxlSize, p);
2904 if (missing_count > 0)
2905 XFreeStringList(missing_list);
2906 XFreeFontSet(xDisplay, fntSet);
2908 XFreeFontNames(fonts);
2915 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2916 | GCBackground | GCFunction | GCPlaneMask;
2917 XGCValues gc_values;
2920 gc_values.plane_mask = AllPlanes;
2921 gc_values.line_width = lineGap;
2922 gc_values.line_style = LineSolid;
2923 gc_values.function = GXcopy;
2925 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2926 gc_values.background = XBlackPixel(xDisplay, xScreen);
2927 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2929 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2930 gc_values.background = XWhitePixel(xDisplay, xScreen);
2931 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2932 XSetFont(xDisplay, coordGC, coordFontID);
2934 // [HGM] make font for holdings counts (white on black0
2935 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2936 gc_values.background = XBlackPixel(xDisplay, xScreen);
2937 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2938 XSetFont(xDisplay, countGC, countFontID);
2940 if (appData.monoMode) {
2941 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2942 gc_values.background = XWhitePixel(xDisplay, xScreen);
2943 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2945 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2946 gc_values.background = XBlackPixel(xDisplay, xScreen);
2947 lightSquareGC = wbPieceGC
2948 = XtGetGC(shellWidget, value_mask, &gc_values);
2950 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2951 gc_values.background = XWhitePixel(xDisplay, xScreen);
2952 darkSquareGC = bwPieceGC
2953 = XtGetGC(shellWidget, value_mask, &gc_values);
2955 if (DefaultDepth(xDisplay, xScreen) == 1) {
2956 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2957 gc_values.function = GXcopyInverted;
2958 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2959 gc_values.function = GXcopy;
2960 if (XBlackPixel(xDisplay, xScreen) == 1) {
2961 bwPieceGC = darkSquareGC;
2962 wbPieceGC = copyInvertedGC;
2964 bwPieceGC = copyInvertedGC;
2965 wbPieceGC = lightSquareGC;
2969 gc_values.foreground = highlightSquareColor;
2970 gc_values.background = highlightSquareColor;
2971 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2973 gc_values.foreground = premoveHighlightColor;
2974 gc_values.background = premoveHighlightColor;
2975 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2977 gc_values.foreground = lightSquareColor;
2978 gc_values.background = darkSquareColor;
2979 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2981 gc_values.foreground = darkSquareColor;
2982 gc_values.background = lightSquareColor;
2983 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2985 gc_values.foreground = jailSquareColor;
2986 gc_values.background = jailSquareColor;
2987 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2989 gc_values.foreground = whitePieceColor;
2990 gc_values.background = darkSquareColor;
2991 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2993 gc_values.foreground = whitePieceColor;
2994 gc_values.background = lightSquareColor;
2995 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2997 gc_values.foreground = whitePieceColor;
2998 gc_values.background = jailSquareColor;
2999 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3001 gc_values.foreground = blackPieceColor;
3002 gc_values.background = darkSquareColor;
3003 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3005 gc_values.foreground = blackPieceColor;
3006 gc_values.background = lightSquareColor;
3007 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3009 gc_values.foreground = blackPieceColor;
3010 gc_values.background = jailSquareColor;
3011 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3015 void loadXIM(xim, xmask, filename, dest, mask)
3028 fp = fopen(filename, "rb");
3030 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3037 for (y=0; y<h; ++y) {
3038 for (x=0; x<h; ++x) {
3043 XPutPixel(xim, x, y, blackPieceColor);
3045 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3048 XPutPixel(xim, x, y, darkSquareColor);
3050 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3053 XPutPixel(xim, x, y, whitePieceColor);
3055 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3058 XPutPixel(xim, x, y, lightSquareColor);
3060 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3066 /* create Pixmap of piece */
3067 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3069 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3072 /* create Pixmap of clipmask
3073 Note: We assume the white/black pieces have the same
3074 outline, so we make only 6 masks. This is okay
3075 since the XPM clipmask routines do the same. */
3077 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3079 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3082 /* now create the 1-bit version */
3083 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3086 values.foreground = 1;
3087 values.background = 0;
3089 /* Don't use XtGetGC, not read only */
3090 maskGC = XCreateGC(xDisplay, *mask,
3091 GCForeground | GCBackground, &values);
3092 XCopyPlane(xDisplay, temp, *mask, maskGC,
3093 0, 0, squareSize, squareSize, 0, 0, 1);
3094 XFreePixmap(xDisplay, temp);
3099 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3101 void CreateXIMPieces()
3106 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3111 /* The XSynchronize calls were copied from CreatePieces.
3112 Not sure if needed, but can't hurt */
3113 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3116 /* temp needed by loadXIM() */
3117 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3118 0, 0, ss, ss, AllPlanes, XYPixmap);
3120 if (strlen(appData.pixmapDirectory) == 0) {
3124 if (appData.monoMode) {
3125 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3129 fprintf(stderr, _("\nLoading XIMs...\n"));
3131 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3132 fprintf(stderr, "%d", piece+1);
3133 for (kind=0; kind<4; kind++) {
3134 fprintf(stderr, ".");
3135 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3136 ExpandPathName(appData.pixmapDirectory),
3137 piece <= (int) WhiteKing ? "" : "w",
3138 pieceBitmapNames[piece],
3140 ximPieceBitmap[kind][piece] =
3141 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3142 0, 0, ss, ss, AllPlanes, XYPixmap);
3143 if (appData.debugMode)
3144 fprintf(stderr, _("(File:%s:) "), buf);
3145 loadXIM(ximPieceBitmap[kind][piece],
3147 &(xpmPieceBitmap2[kind][piece]),
3148 &(ximMaskPm2[piece]));
3149 if(piece <= (int)WhiteKing)
3150 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3152 fprintf(stderr," ");
3154 /* Load light and dark squares */
3155 /* If the LSQ and DSQ pieces don't exist, we will
3156 draw them with solid squares. */
3157 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3158 if (access(buf, 0) != 0) {
3162 fprintf(stderr, _("light square "));
3164 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3165 0, 0, ss, ss, AllPlanes, XYPixmap);
3166 if (appData.debugMode)
3167 fprintf(stderr, _("(File:%s:) "), buf);
3169 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3170 fprintf(stderr, _("dark square "));
3171 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3172 ExpandPathName(appData.pixmapDirectory), ss);
3173 if (appData.debugMode)
3174 fprintf(stderr, _("(File:%s:) "), buf);
3176 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3177 0, 0, ss, ss, AllPlanes, XYPixmap);
3178 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3179 xpmJailSquare = xpmLightSquare;
3181 fprintf(stderr, _("Done.\n"));
3183 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3187 void CreateXPMPieces()
3191 u_int ss = squareSize;
3193 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3194 XpmColorSymbol symbols[4];
3196 /* The XSynchronize calls were copied from CreatePieces.
3197 Not sure if needed, but can't hurt */
3198 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3200 /* Setup translations so piece colors match square colors */
3201 symbols[0].name = "light_piece";
3202 symbols[0].value = appData.whitePieceColor;
3203 symbols[1].name = "dark_piece";
3204 symbols[1].value = appData.blackPieceColor;
3205 symbols[2].name = "light_square";
3206 symbols[2].value = appData.lightSquareColor;
3207 symbols[3].name = "dark_square";
3208 symbols[3].value = appData.darkSquareColor;
3210 attr.valuemask = XpmColorSymbols;
3211 attr.colorsymbols = symbols;
3212 attr.numsymbols = 4;
3214 if (appData.monoMode) {
3215 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3219 if (strlen(appData.pixmapDirectory) == 0) {
3220 XpmPieces* pieces = builtInXpms;
3223 while (pieces->size != squareSize && pieces->size) pieces++;
3224 if (!pieces->size) {
3225 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3228 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3229 for (kind=0; kind<4; kind++) {
3231 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3232 pieces->xpm[piece][kind],
3233 &(xpmPieceBitmap2[kind][piece]),
3234 NULL, &attr)) != 0) {
3235 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3239 if(piece <= (int) WhiteKing)
3240 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3244 xpmJailSquare = xpmLightSquare;
3248 fprintf(stderr, _("\nLoading XPMs...\n"));
3251 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3252 fprintf(stderr, "%d ", piece+1);
3253 for (kind=0; kind<4; kind++) {
3254 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3255 ExpandPathName(appData.pixmapDirectory),
3256 piece > (int) WhiteKing ? "w" : "",
3257 pieceBitmapNames[piece],
3259 if (appData.debugMode) {
3260 fprintf(stderr, _("(File:%s:) "), buf);
3262 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3263 &(xpmPieceBitmap2[kind][piece]),
3264 NULL, &attr)) != 0) {
3265 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3266 // [HGM] missing: read of unorthodox piece failed; substitute King.
3267 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3268 ExpandPathName(appData.pixmapDirectory),
3270 if (appData.debugMode) {
3271 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3273 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3274 &(xpmPieceBitmap2[kind][piece]),
3278 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3283 if(piece <= (int) WhiteKing)
3284 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3287 /* Load light and dark squares */
3288 /* If the LSQ and DSQ pieces don't exist, we will
3289 draw them with solid squares. */
3290 fprintf(stderr, _("light square "));
3291 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3292 if (access(buf, 0) != 0) {
3296 if (appData.debugMode)
3297 fprintf(stderr, _("(File:%s:) "), buf);
3299 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3300 &xpmLightSquare, NULL, &attr)) != 0) {
3301 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3304 fprintf(stderr, _("dark square "));
3305 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3306 ExpandPathName(appData.pixmapDirectory), ss);
3307 if (appData.debugMode) {
3308 fprintf(stderr, _("(File:%s:) "), buf);
3310 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3311 &xpmDarkSquare, NULL, &attr)) != 0) {
3312 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3316 xpmJailSquare = xpmLightSquare;
3317 fprintf(stderr, _("Done.\n"));
3319 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3322 #endif /* HAVE_LIBXPM */
3325 /* No built-in bitmaps */
3330 u_int ss = squareSize;
3332 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3335 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3336 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3337 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3338 pieceBitmapNames[piece],
3339 ss, kind == SOLID ? 's' : 'o');
3340 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3341 if(piece <= (int)WhiteKing)
3342 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3346 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3350 /* With built-in bitmaps */
3353 BuiltInBits* bib = builtInBits;
3356 u_int ss = squareSize;
3358 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3361 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3363 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3364 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3365 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3366 pieceBitmapNames[piece],
3367 ss, kind == SOLID ? 's' : 'o');
3368 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3369 bib->bits[kind][piece], ss, ss);
3370 if(piece <= (int)WhiteKing)
3371 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3375 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3380 void ReadBitmap(pm, name, bits, wreq, hreq)
3383 unsigned char bits[];
3389 char msg[MSG_SIZ], fullname[MSG_SIZ];
3391 if (*appData.bitmapDirectory != NULLCHAR) {
3392 strcpy(fullname, appData.bitmapDirectory);
3393 strcat(fullname, "/");
3394 strcat(fullname, name);
3395 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3396 &w, &h, pm, &x_hot, &y_hot);
3397 fprintf(stderr, "load %s\n", name);
3398 if (errcode != BitmapSuccess) {
3400 case BitmapOpenFailed:
3401 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3403 case BitmapFileInvalid:
3404 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3406 case BitmapNoMemory:
3407 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3411 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3415 fprintf(stderr, _("%s: %s...using built-in\n"),
3417 } else if (w != wreq || h != hreq) {
3419 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3420 programName, fullname, w, h, wreq, hreq);
3426 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3435 if (lineGap == 0) return;
3437 /* [HR] Split this into 2 loops for non-square boards. */
3439 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3440 gridSegments[i].x1 = 0;
3441 gridSegments[i].x2 =
3442 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3443 gridSegments[i].y1 = gridSegments[i].y2
3444 = lineGap / 2 + (i * (squareSize + lineGap));
3447 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3448 gridSegments[j + i].y1 = 0;
3449 gridSegments[j + i].y2 =
3450 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3451 gridSegments[j + i].x1 = gridSegments[j + i].x2
3452 = lineGap / 2 + (j * (squareSize + lineGap));
3456 static void MenuBarSelect(w, addr, index)
3461 XtActionProc proc = (XtActionProc) addr;
3463 (proc)(NULL, NULL, NULL, NULL);
3466 void CreateMenuBarPopup(parent, name, mb)
3476 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3479 XtSetArg(args[j], XtNleftMargin, 20); j++;
3480 XtSetArg(args[j], XtNrightMargin, 20); j++;
3482 while (mi->string != NULL) {
3483 if (strcmp(mi->string, "----") == 0) {
3484 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3487 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3488 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3490 XtAddCallback(entry, XtNcallback,
3491 (XtCallbackProc) MenuBarSelect,
3492 (caddr_t) mi->proc);
3498 Widget CreateMenuBar(mb)
3502 Widget anchor, menuBar;
3504 char menuName[MSG_SIZ];
3507 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3508 XtSetArg(args[j], XtNvSpace, 0); j++;
3509 XtSetArg(args[j], XtNborderWidth, 0); j++;
3510 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3511 formWidget, args, j);
3513 while (mb->name != NULL) {
3514 strcpy(menuName, "menu");
3515 strcat(menuName, mb->name);
3517 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3520 shortName[0] = _(mb->name)[0];
3521 shortName[1] = NULLCHAR;
3522 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3525 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3528 XtSetArg(args[j], XtNborderWidth, 0); j++;
3529 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3531 CreateMenuBarPopup(menuBar, menuName, mb);
3537 Widget CreateButtonBar(mi)
3541 Widget button, buttonBar;
3545 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3547 XtSetArg(args[j], XtNhSpace, 0); j++;
3549 XtSetArg(args[j], XtNborderWidth, 0); j++;
3550 XtSetArg(args[j], XtNvSpace, 0); j++;
3551 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3552 formWidget, args, j);
3554 while (mi->string != NULL) {
3557 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3558 XtSetArg(args[j], XtNborderWidth, 0); j++;
3560 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3561 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3562 buttonBar, args, j);
3563 XtAddCallback(button, XtNcallback,
3564 (XtCallbackProc) MenuBarSelect,
3565 (caddr_t) mi->proc);
3572 CreatePieceMenu(name, color)
3579 ChessSquare selection;
3581 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3582 boardWidget, args, 0);
3584 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3585 String item = pieceMenuStrings[color][i];
3587 if (strcmp(item, "----") == 0) {
3588 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3591 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3592 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3594 selection = pieceMenuTranslation[color][i];
3595 XtAddCallback(entry, XtNcallback,
3596 (XtCallbackProc) PieceMenuSelect,
3597 (caddr_t) selection);
3598 if (selection == WhitePawn || selection == BlackPawn) {
3599 XtSetArg(args[0], XtNpopupOnEntry, entry);
3600 XtSetValues(menu, args, 1);
3613 ChessSquare selection;
3615 whitePieceMenu = CreatePieceMenu("menuW", 0);
3616 blackPieceMenu = CreatePieceMenu("menuB", 1);
3618 XtRegisterGrabAction(PieceMenuPopup, True,
3619 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3620 GrabModeAsync, GrabModeAsync);
3622 XtSetArg(args[0], XtNlabel, _("Drop"));
3623 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3624 boardWidget, args, 1);
3625 for (i = 0; i < DROP_MENU_SIZE; i++) {
3626 String item = dropMenuStrings[i];
3628 if (strcmp(item, "----") == 0) {
3629 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3632 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3633 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3635 selection = dropMenuTranslation[i];
3636 XtAddCallback(entry, XtNcallback,
3637 (XtCallbackProc) DropMenuSelect,
3638 (caddr_t) selection);
3643 void SetupDropMenu()
3651 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3652 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3653 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3654 dmEnables[i].piece);
3655 XtSetSensitive(entry, p != NULL || !appData.testLegality
3656 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3657 && !appData.icsActive));
3659 while (p && *p++ == dmEnables[i].piece) count++;
3660 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3662 XtSetArg(args[j], XtNlabel, label); j++;
3663 XtSetValues(entry, args, j);
3667 void PieceMenuPopup(w, event, params, num_params)
3671 Cardinal *num_params;
3674 if (event->type != ButtonPress) return;
3675 if (errorUp) ErrorPopDown();
3679 whichMenu = params[0];
3681 case IcsPlayingWhite:
3682 case IcsPlayingBlack:
3684 case MachinePlaysWhite:
3685 case MachinePlaysBlack:
3686 if (appData.testLegality &&
3687 gameInfo.variant != VariantBughouse &&
3688 gameInfo.variant != VariantCrazyhouse) return;
3690 whichMenu = "menuD";
3696 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3697 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3698 pmFromX = pmFromY = -1;
3702 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3704 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3706 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3709 static void PieceMenuSelect(w, piece, junk)
3714 if (pmFromX < 0 || pmFromY < 0) return;
3715 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3718 static void DropMenuSelect(w, piece, junk)
3723 if (pmFromX < 0 || pmFromY < 0) return;
3724 DropMenuEvent(piece, pmFromX, pmFromY);
3727 void WhiteClock(w, event, prms, nprms)
3733 if (gameMode == EditPosition || gameMode == IcsExamining) {
3734 SetWhiteToPlayEvent();
3735 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3740 void BlackClock(w, event, prms, nprms)
3746 if (gameMode == EditPosition || gameMode == IcsExamining) {
3747 SetBlackToPlayEvent();
3748 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3755 * If the user selects on a border boundary, return -1; if off the board,
3756 * return -2. Otherwise map the event coordinate to the square.
3758 int EventToSquare(x, limit)
3766 if ((x % (squareSize + lineGap)) >= squareSize)
3768 x /= (squareSize + lineGap);
3774 static void do_flash_delay(msec)
3780 static void drawHighlight(file, rank, gc)
3786 if (lineGap == 0 || appData.blindfold) return;
3789 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3790 (squareSize + lineGap);
3791 y = lineGap/2 + rank * (squareSize + lineGap);
3793 x = lineGap/2 + file * (squareSize + lineGap);
3794 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3795 (squareSize + lineGap);
3798 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3799 squareSize+lineGap, squareSize+lineGap);
3802 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3803 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3806 SetHighlights(fromX, fromY, toX, toY)
3807 int fromX, fromY, toX, toY;
3809 if (hi1X != fromX || hi1Y != fromY) {
3810 if (hi1X >= 0 && hi1Y >= 0) {
3811 drawHighlight(hi1X, hi1Y, lineGC);
3813 if (fromX >= 0 && fromY >= 0) {
3814 drawHighlight(fromX, fromY, highlineGC);
3817 if (hi2X != toX || hi2Y != toY) {
3818 if (hi2X >= 0 && hi2Y >= 0) {
3819 drawHighlight(hi2X, hi2Y, lineGC);
3821 if (toX >= 0 && toY >= 0) {
3822 drawHighlight(toX, toY, highlineGC);
3834 SetHighlights(-1, -1, -1, -1);
3839 SetPremoveHighlights(fromX, fromY, toX, toY)
3840 int fromX, fromY, toX, toY;
3842 if (pm1X != fromX || pm1Y != fromY) {
3843 if (pm1X >= 0 && pm1Y >= 0) {
3844 drawHighlight(pm1X, pm1Y, lineGC);
3846 if (fromX >= 0 && fromY >= 0) {
3847 drawHighlight(fromX, fromY, prelineGC);
3850 if (pm2X != toX || pm2Y != toY) {
3851 if (pm2X >= 0 && pm2Y >= 0) {
3852 drawHighlight(pm2X, pm2Y, lineGC);
3854 if (toX >= 0 && toY >= 0) {
3855 drawHighlight(toX, toY, prelineGC);
3865 ClearPremoveHighlights()
3867 SetPremoveHighlights(-1, -1, -1, -1);
3870 static void BlankSquare(x, y, color, piece, dest)
3875 if (useImages && useImageSqs) {
3879 pm = xpmLightSquare;
3884 case 2: /* neutral */
3889 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3890 squareSize, squareSize, x, y);
3900 case 2: /* neutral */
3905 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3910 I split out the routines to draw a piece so that I could
3911 make a generic flash routine.
3913 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3915 int square_color, x, y;
3918 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3919 switch (square_color) {
3921 case 2: /* neutral */
3923 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3924 ? *pieceToOutline(piece)
3925 : *pieceToSolid(piece),
3926 dest, bwPieceGC, 0, 0,
3927 squareSize, squareSize, x, y);
3930 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3931 ? *pieceToSolid(piece)
3932 : *pieceToOutline(piece),
3933 dest, wbPieceGC, 0, 0,
3934 squareSize, squareSize, x, y);
3939 static void monoDrawPiece(piece, square_color, x, y, dest)
3941 int square_color, x, y;
3944 switch (square_color) {
3946 case 2: /* neutral */
3948 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3949 ? *pieceToOutline(piece)
3950 : *pieceToSolid(piece),
3951 dest, bwPieceGC, 0, 0,
3952 squareSize, squareSize, x, y, 1);
3955 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3956 ? *pieceToSolid(piece)
3957 : *pieceToOutline(piece),
3958 dest, wbPieceGC, 0, 0,
3959 squareSize, squareSize, x, y, 1);
3964 static void colorDrawPiece(piece, square_color, x, y, dest)
3966 int square_color, x, y;
3969 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3970 switch (square_color) {
3972 XCopyPlane(xDisplay, *pieceToSolid(piece),
3973 dest, (int) piece < (int) BlackPawn
3974 ? wlPieceGC : blPieceGC, 0, 0,
3975 squareSize, squareSize, x, y, 1);
3978 XCopyPlane(xDisplay, *pieceToSolid(piece),
3979 dest, (int) piece < (int) BlackPawn
3980 ? wdPieceGC : bdPieceGC, 0, 0,
3981 squareSize, squareSize, x, y, 1);
3983 case 2: /* neutral */
3985 XCopyPlane(xDisplay, *pieceToSolid(piece),
3986 dest, (int) piece < (int) BlackPawn
3987 ? wjPieceGC : bjPieceGC, 0, 0,
3988 squareSize, squareSize, x, y, 1);
3993 static void colorDrawPieceImage(piece, square_color, x, y, dest)
3995 int square_color, x, y;
4000 switch (square_color) {
4002 case 2: /* neutral */
4004 if ((int)piece < (int) BlackPawn) {
4012 if ((int)piece < (int) BlackPawn) {
4020 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4021 dest, wlPieceGC, 0, 0,
4022 squareSize, squareSize, x, y);
4025 typedef void (*DrawFunc)();
4027 DrawFunc ChooseDrawFunc()
4029 if (appData.monoMode) {
4030 if (DefaultDepth(xDisplay, xScreen) == 1) {
4031 return monoDrawPiece_1bit;
4033 return monoDrawPiece;
4037 return colorDrawPieceImage;
4039 return colorDrawPiece;
4043 /* [HR] determine square color depending on chess variant. */
4044 static int SquareColor(row, column)
4049 if (gameInfo.variant == VariantXiangqi) {
4050 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4052 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4054 } else if (row <= 4) {
4060 square_color = ((column + row) % 2) == 1;
4063 /* [hgm] holdings: next line makes all holdings squares light */
4064 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4066 return square_color;
4069 void DrawSquare(row, column, piece, do_flash)
4070 int row, column, do_flash;
4073 int square_color, x, y, direction, font_ascent, font_descent;
4076 XCharStruct overall;
4080 /* Calculate delay in milliseconds (2-delays per complete flash) */
4081 flash_delay = 500 / appData.flashRate;
4084 x = lineGap + ((BOARD_WIDTH-1)-column) *
4085 (squareSize + lineGap);
4086 y = lineGap + row * (squareSize + lineGap);
4088 x = lineGap + column * (squareSize + lineGap);
4089 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4090 (squareSize + lineGap);
4093 square_color = SquareColor(row, column);
4095 if ( // [HGM] holdings: blank out area between board and holdings
4096 column == BOARD_LEFT-1 || column == BOARD_RGHT
4097 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4098 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4099 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4101 // [HGM] print piece counts next to holdings
4102 string[1] = NULLCHAR;
4103 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4104 string[0] = '0' + piece;
4105 XTextExtents(countFontStruct, string, 1, &direction,
4106 &font_ascent, &font_descent, &overall);
4107 if (appData.monoMode) {
4108 XDrawImageString(xDisplay, xBoardWindow, countGC,
4109 x + squareSize - overall.width - 2,
4110 y + font_ascent + 1, string, 1);
4112 XDrawString(xDisplay, xBoardWindow, countGC,
4113 x + squareSize - overall.width - 2,
4114 y + font_ascent + 1, string, 1);
4117 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4118 string[0] = '0' + piece;
4119 XTextExtents(countFontStruct, string, 1, &direction,
4120 &font_ascent, &font_descent, &overall);
4121 if (appData.monoMode) {
4122 XDrawImageString(xDisplay, xBoardWindow, countGC,
4123 x + 2, y + font_ascent + 1, string, 1);
4125 XDrawString(xDisplay, xBoardWindow, countGC,
4126 x + 2, y + font_ascent + 1, string, 1);
4130 if (piece == EmptySquare || appData.blindfold) {
4131 BlankSquare(x, y, square_color, piece, xBoardWindow);
4133 drawfunc = ChooseDrawFunc();
4134 if (do_flash && appData.flashCount > 0) {
4135 for (i=0; i<appData.flashCount; ++i) {
4137 drawfunc(piece, square_color, x, y, xBoardWindow);
4138 XSync(xDisplay, False);
4139 do_flash_delay(flash_delay);
4141 BlankSquare(x, y, square_color, piece, xBoardWindow);
4142 XSync(xDisplay, False);
4143 do_flash_delay(flash_delay);
4146 drawfunc(piece, square_color, x, y, xBoardWindow);
4150 string[1] = NULLCHAR;
4151 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4152 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4153 string[0] = 'a' + column - BOARD_LEFT;
4154 XTextExtents(coordFontStruct, string, 1, &direction,
4155 &font_ascent, &font_descent, &overall);
4156 if (appData.monoMode) {
4157 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4158 x + squareSize - overall.width - 2,
4159 y + squareSize - font_descent - 1, string, 1);
4161 XDrawString(xDisplay, xBoardWindow, coordGC,
4162 x + squareSize - overall.width - 2,
4163 y + squareSize - font_descent - 1, string, 1);
4166 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4167 string[0] = ONE + row;
4168 XTextExtents(coordFontStruct, string, 1, &direction,
4169 &font_ascent, &font_descent, &overall);
4170 if (appData.monoMode) {
4171 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4172 x + 2, y + font_ascent + 1, string, 1);
4174 XDrawString(xDisplay, xBoardWindow, coordGC,
4175 x + 2, y + font_ascent + 1, string, 1);
4181 /* Why is this needed on some versions of X? */
4182 void EventProc(widget, unused, event)
4187 if (!XtIsRealized(widget))
4190 switch (event->type) {
4192 if (event->xexpose.count > 0) return; /* no clipping is done */
4193 XDrawPosition(widget, True, NULL);
4201 void DrawPosition(fullRedraw, board)
4202 /*Boolean*/int fullRedraw;
4205 XDrawPosition(boardWidget, fullRedraw, board);
4208 /* Returns 1 if there are "too many" differences between b1 and b2
4209 (i.e. more than 1 move was made) */
4210 static int too_many_diffs(b1, b2)
4216 for (i=0; i<BOARD_HEIGHT; ++i) {
4217 for (j=0; j<BOARD_WIDTH; ++j) {
4218 if (b1[i][j] != b2[i][j]) {
4219 if (++c > 4) /* Castling causes 4 diffs */
4228 /* Matrix describing castling maneuvers */
4229 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4230 static int castling_matrix[4][5] = {
4231 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4232 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4233 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4234 { 7, 7, 4, 5, 6 } /* 0-0, black */
4237 /* Checks whether castling occurred. If it did, *rrow and *rcol
4238 are set to the destination (row,col) of the rook that moved.
4240 Returns 1 if castling occurred, 0 if not.
4242 Note: Only handles a max of 1 castling move, so be sure
4243 to call too_many_diffs() first.
4245 static int check_castle_draw(newb, oldb, rrow, rcol)
4252 /* For each type of castling... */
4253 for (i=0; i<4; ++i) {
4254 r = castling_matrix[i];
4256 /* Check the 4 squares involved in the castling move */
4258 for (j=1; j<=4; ++j) {
4259 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4266 /* All 4 changed, so it must be a castling move */
4275 static int damage[BOARD_RANKS][BOARD_FILES];
4278 * event handler for redrawing the board
4280 void XDrawPosition(w, repaint, board)
4282 /*Boolean*/int repaint;
4286 static int lastFlipView = 0;
4287 static int lastBoardValid = 0;
4288 static Board lastBoard;
4292 if (board == NULL) {
4293 if (!lastBoardValid) return;
4296 if (!lastBoardValid || lastFlipView != flipView) {
4297 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4298 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4303 * It would be simpler to clear the window with XClearWindow()
4304 * but this causes a very distracting flicker.
4307 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4309 /* If too much changes (begin observing new game, etc.), don't
4311 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4313 /* Special check for castling so we don't flash both the king
4314 and the rook (just flash the king). */
4316 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4317 /* Draw rook with NO flashing. King will be drawn flashing later */
4318 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4319 lastBoard[rrow][rcol] = board[rrow][rcol];
4323 /* First pass -- Draw (newly) empty squares and repair damage.
4324 This prevents you from having a piece show up twice while it
4325 is flashing on its new square */
4326 for (i = 0; i < BOARD_HEIGHT; i++)
4327 for (j = 0; j < BOARD_WIDTH; j++)
4328 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4330 DrawSquare(i, j, board[i][j], 0);
4331 damage[i][j] = False;
4334 /* Second pass -- Draw piece(s) in new position and flash them */
4335 for (i = 0; i < BOARD_HEIGHT; i++)
4336 for (j = 0; j < BOARD_WIDTH; j++)
4337 if (board[i][j] != lastBoard[i][j]) {
4338 DrawSquare(i, j, board[i][j], do_flash);
4342 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4343 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4345 for (i = 0; i < BOARD_HEIGHT; i++)
4346 for (j = 0; j < BOARD_WIDTH; j++) {
4347 DrawSquare(i, j, board[i][j], 0);
4348 damage[i][j] = False;
4352 CopyBoard(lastBoard, board);
4354 lastFlipView = flipView;
4356 /* Draw highlights */
4357 if (pm1X >= 0 && pm1Y >= 0) {
4358 drawHighlight(pm1X, pm1Y, prelineGC);
4360 if (pm2X >= 0 && pm2Y >= 0) {
4361 drawHighlight(pm2X, pm2Y, prelineGC);
4363 if (hi1X >= 0 && hi1Y >= 0) {
4364 drawHighlight(hi1X, hi1Y, highlineGC);
4366 if (hi2X >= 0 && hi2Y >= 0) {
4367 drawHighlight(hi2X, hi2Y, highlineGC);
4370 /* If piece being dragged around board, must redraw that too */
4373 XSync(xDisplay, False);
4378 * event handler for redrawing the board
4380 void DrawPositionProc(w, event, prms, nprms)
4386 XDrawPosition(w, True, NULL);
4391 * event handler for parsing user moves
4393 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4394 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4395 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4396 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4397 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4398 // and at the end FinishMove() to perform the move after optional promotion popups.
4399 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4400 void HandleUserMove(w, event, prms, nprms)
4406 if (w != boardWidget || errorExitStatus != -1) return;
4409 if (event->type == ButtonPress) {
4410 XtPopdown(promotionShell);
4411 XtDestroyWidget(promotionShell);
4412 promotionUp = False;
4420 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4421 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4422 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4425 void AnimateUserMove (Widget w, XEvent * event,
4426 String * params, Cardinal * nParams)
4428 DragPieceMove(event->xmotion.x, event->xmotion.y);
4431 Widget CommentCreate(name, text, mutable, callback, lines)
4433 int /*Boolean*/ mutable;
4434 XtCallbackProc callback;
4438 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4443 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4444 XtGetValues(boardWidget, args, j);
4447 XtSetArg(args[j], XtNresizable, True); j++;
4450 XtCreatePopupShell(name, topLevelShellWidgetClass,
4451 shellWidget, args, j);
4454 XtCreatePopupShell(name, transientShellWidgetClass,
4455 shellWidget, args, j);
4458 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4459 layoutArgs, XtNumber(layoutArgs));
4461 XtCreateManagedWidget("form", formWidgetClass, layout,
4462 formArgs, XtNumber(formArgs));
4466 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4467 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4469 XtSetArg(args[j], XtNstring, text); j++;
4470 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4471 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4472 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4473 XtSetArg(args[j], XtNright, XtChainRight); j++;
4474 XtSetArg(args[j], XtNresizable, True); j++;
4475 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4476 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4477 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4478 XtSetArg(args[j], XtNautoFill, True); j++;
4479 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4481 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4485 XtSetArg(args[j], XtNfromVert, edit); j++;
4486 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4487 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4488 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4489 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4491 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4492 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4495 XtSetArg(args[j], XtNfromVert, edit); j++;
4496 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4497 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4498 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4499 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4500 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4502 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4503 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4506 XtSetArg(args[j], XtNfromVert, edit); j++;
4507 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4508 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4509 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4510 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4511 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4513 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4514 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4517 XtSetArg(args[j], XtNfromVert, edit); j++;
4518 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4519 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4520 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4521 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4523 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4524 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4527 XtSetArg(args[j], XtNfromVert, edit); j++;
4528 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4529 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4530 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4531 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4532 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4534 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4535 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4538 XtRealizeWidget(shell);
4540 if (commentX == -1) {
4543 Dimension pw_height;
4544 Dimension ew_height;
4547 XtSetArg(args[j], XtNheight, &ew_height); j++;
4548 XtGetValues(edit, args, j);
4551 XtSetArg(args[j], XtNheight, &pw_height); j++;
4552 XtGetValues(shell, args, j);
4553 commentH = pw_height + (lines - 1) * ew_height;
4554 commentW = bw_width - 16;
4556 XSync(xDisplay, False);
4558 /* This code seems to tickle an X bug if it is executed too soon
4559 after xboard starts up. The coordinates get transformed as if
4560 the main window was positioned at (0, 0).
4562 XtTranslateCoords(shellWidget,
4563 (bw_width - commentW) / 2, 0 - commentH / 2,
4564 &commentX, &commentY);
4566 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4567 RootWindowOfScreen(XtScreen(shellWidget)),
4568 (bw_width - commentW) / 2, 0 - commentH / 2,
4573 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4576 if(wpComment.width > 0) {
4577 commentX = wpComment.x;
4578 commentY = wpComment.y;
4579 commentW = wpComment.width;
4580 commentH = wpComment.height;
4584 XtSetArg(args[j], XtNheight, commentH); j++;
4585 XtSetArg(args[j], XtNwidth, commentW); j++;
4586 XtSetArg(args[j], XtNx, commentX); j++;
4587 XtSetArg(args[j], XtNy, commentY); j++;
4588 XtSetValues(shell, args, j);
4589 XtSetKeyboardFocus(shell, edit);
4594 /* Used for analysis window and ICS input window */
4595 Widget MiscCreate(name, text, mutable, callback, lines)
4597 int /*Boolean*/ mutable;
4598 XtCallbackProc callback;
4602 Widget shell, layout, form, edit;
4604 Dimension bw_width, pw_height, ew_height, w, h;
4610 XtSetArg(args[j], XtNresizable, True); j++;
4613 XtCreatePopupShell(name, topLevelShellWidgetClass,
4614 shellWidget, args, j);
4617 XtCreatePopupShell(name, transientShellWidgetClass,
4618 shellWidget, args, j);
4621 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4622 layoutArgs, XtNumber(layoutArgs));
4624 XtCreateManagedWidget("form", formWidgetClass, layout,
4625 formArgs, XtNumber(formArgs));
4629 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4630 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4632 XtSetArg(args[j], XtNstring, text); j++;
4633 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4634 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4635 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4636 XtSetArg(args[j], XtNright, XtChainRight); j++;
4637 XtSetArg(args[j], XtNresizable, True); j++;
4638 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4639 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4640 XtSetArg(args[j], XtNautoFill, True); j++;
4641 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4643 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4645 XtRealizeWidget(shell);
4648 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4649 XtGetValues(boardWidget, args, j);
4652 XtSetArg(args[j], XtNheight, &ew_height); j++;
4653 XtGetValues(edit, args, j);
4656 XtSetArg(args[j], XtNheight, &pw_height); j++;
4657 XtGetValues(shell, args, j);
4658 h = pw_height + (lines - 1) * ew_height;
4661 XSync(xDisplay, False);
4663 /* This code seems to tickle an X bug if it is executed too soon
4664 after xboard starts up. The coordinates get transformed as if
4665 the main window was positioned at (0, 0).
4667 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4669 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4670 RootWindowOfScreen(XtScreen(shellWidget)),
4671 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4675 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4678 XtSetArg(args[j], XtNheight, h); j++;
4679 XtSetArg(args[j], XtNwidth, w); j++;
4680 XtSetArg(args[j], XtNx, x); j++;
4681 XtSetArg(args[j], XtNy, y); j++;
4682 XtSetValues(shell, args, j);
4688 static int savedIndex; /* gross that this is global */
4690 void EditCommentPopUp(index, title, text)
4699 if (text == NULL) text = "";
4701 if (editShell == NULL) {
4703 CommentCreate(title, text, True, EditCommentCallback, 4);
4704 XtRealizeWidget(editShell);
4705 CatchDeleteWindow(editShell, "EditCommentPopDown");
4707 edit = XtNameToWidget(editShell, "*form.text");
4709 XtSetArg(args[j], XtNstring, text); j++;
4710 XtSetValues(edit, args, j);
4712 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4713 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4714 XtSetValues(editShell, args, j);
4717 XtPopup(editShell, XtGrabNone);
4721 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4722 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4726 void EditCommentCallback(w, client_data, call_data)
4728 XtPointer client_data, call_data;
4736 XtSetArg(args[j], XtNlabel, &name); j++;
4737 XtGetValues(w, args, j);
4739 if (strcmp(name, _("ok")) == 0) {
4740 edit = XtNameToWidget(editShell, "*form.text");
4742 XtSetArg(args[j], XtNstring, &val); j++;
4743 XtGetValues(edit, args, j);
4744 ReplaceComment(savedIndex, val);
4745 EditCommentPopDown();
4746 } else if (strcmp(name, _("cancel")) == 0) {
4747 EditCommentPopDown();
4748 } else if (strcmp(name, _("clear")) == 0) {
4749 edit = XtNameToWidget(editShell, "*form.text");
4750 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4751 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4755 void EditCommentPopDown()
4760 if (!editUp) return;
4762 XtSetArg(args[j], XtNx, &commentX); j++;
4763 XtSetArg(args[j], XtNy, &commentY); j++;
4764 XtSetArg(args[j], XtNheight, &commentH); j++;
4765 XtSetArg(args[j], XtNwidth, &commentW); j++;
4766 XtGetValues(editShell, args, j);
4767 XtPopdown(editShell);
4770 XtSetArg(args[j], XtNleftBitmap, None); j++;
4771 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4775 void ICSInputBoxPopUp()
4780 char *title = _("ICS Input");
4783 if (ICSInputShell == NULL) {
4784 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4785 tr = XtParseTranslationTable(ICSInputTranslations);
4786 edit = XtNameToWidget(ICSInputShell, "*form.text");
4787 XtOverrideTranslations(edit, tr);
4788 XtRealizeWidget(ICSInputShell);
4789 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4792 edit = XtNameToWidget(ICSInputShell, "*form.text");
4794 XtSetArg(args[j], XtNstring, ""); j++;
4795 XtSetValues(edit, args, j);
4797 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4798 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4799 XtSetValues(ICSInputShell, args, j);
4802 XtPopup(ICSInputShell, XtGrabNone);
4803 XtSetKeyboardFocus(ICSInputShell, edit);
4805 ICSInputBoxUp = True;
4807 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4808 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4812 void ICSInputSendText()
4819 edit = XtNameToWidget(ICSInputShell, "*form.text");
4821 XtSetArg(args[j], XtNstring, &val); j++;
4822 XtGetValues(edit, args, j);
4823 SendMultiLineToICS(val);
4824 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4825 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4828 void ICSInputBoxPopDown()
4833 if (!ICSInputBoxUp) return;
4835 XtPopdown(ICSInputShell);
4836 ICSInputBoxUp = False;
4838 XtSetArg(args[j], XtNleftBitmap, None); j++;
4839 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4843 void CommentPopUp(title, text)
4850 if (commentShell == NULL) {
4852 CommentCreate(title, text, False, CommentCallback, 4);
4853 XtRealizeWidget(commentShell);
4854 CatchDeleteWindow(commentShell, "CommentPopDown");
4856 edit = XtNameToWidget(commentShell, "*form.text");
4858 XtSetArg(args[j], XtNstring, text); j++;
4859 XtSetValues(edit, args, j);
4861 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4862 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4863 XtSetValues(commentShell, args, j);
4866 XtPopup(commentShell, XtGrabNone);
4867 XSync(xDisplay, False);
4872 void CommentCallback(w, client_data, call_data)
4874 XtPointer client_data, call_data;
4881 XtSetArg(args[j], XtNlabel, &name); j++;
4882 XtGetValues(w, args, j);
4884 if (strcmp(name, _("close")) == 0) {
4886 } else if (strcmp(name, _("edit")) == 0) {
4893 void CommentPopDown()
4898 if (!commentUp) return;
4900 XtSetArg(args[j], XtNx, &commentX); j++;
4901 XtSetArg(args[j], XtNy, &commentY); j++;
4902 XtSetArg(args[j], XtNwidth, &commentW); j++;
4903 XtSetArg(args[j], XtNheight, &commentH); j++;
4904 XtGetValues(commentShell, args, j);
4905 XtPopdown(commentShell);
4906 XSync(xDisplay, False);
4910 void FileNamePopUp(label, def, proc, openMode)
4917 Widget popup, layout, dialog, edit;
4923 fileProc = proc; /* I can't see a way not */
4924 fileOpenMode = openMode; /* to use globals here */
4927 XtSetArg(args[i], XtNresizable, True); i++;
4928 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4929 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4930 fileNameShell = popup =
4931 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4932 shellWidget, args, i);
4935 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4936 layoutArgs, XtNumber(layoutArgs));
4939 XtSetArg(args[i], XtNlabel, label); i++;
4940 XtSetArg(args[i], XtNvalue, def); i++;
4941 XtSetArg(args[i], XtNborderWidth, 0); i++;
4942 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4945 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4946 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4947 (XtPointer) dialog);
4949 XtRealizeWidget(popup);
4950 CatchDeleteWindow(popup, "FileNamePopDown");
4952 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4953 &x, &y, &win_x, &win_y, &mask);
4955 XtSetArg(args[0], XtNx, x - 10);
4956 XtSetArg(args[1], XtNy, y - 30);
4957 XtSetValues(popup, args, 2);
4959 XtPopup(popup, XtGrabExclusive);
4962 edit = XtNameToWidget(dialog, "*value");
4963 XtSetKeyboardFocus(popup, edit);
4966 void FileNamePopDown()
4968 if (!filenameUp) return;
4969 XtPopdown(fileNameShell);
4970 XtDestroyWidget(fileNameShell);
4975 void FileNameCallback(w, client_data, call_data)
4977 XtPointer client_data, call_data;
4982 XtSetArg(args[0], XtNlabel, &name);
4983 XtGetValues(w, args, 1);
4985 if (strcmp(name, _("cancel")) == 0) {
4990 FileNameAction(w, NULL, NULL, NULL);
4993 void FileNameAction(w, event, prms, nprms)
5005 name = XawDialogGetValueString(w = XtParent(w));
5007 if ((name != NULL) && (*name != NULLCHAR)) {
5009 XtPopdown(w = XtParent(XtParent(w)));
5013 p = strrchr(buf, ' ');
5020 fullname = ExpandPathName(buf);
5022 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5025 f = fopen(fullname, fileOpenMode);
5027 DisplayError(_("Failed to open file"), errno);
5029 (void) (*fileProc)(f, index, buf);
5036 XtPopdown(w = XtParent(XtParent(w)));
5042 void PromotionPopUp()
5045 Widget dialog, layout;
5047 Dimension bw_width, pw_width;
5051 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5052 XtGetValues(boardWidget, args, j);
5055 XtSetArg(args[j], XtNresizable, True); j++;
5056 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5058 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5059 shellWidget, args, j);
5061 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5062 layoutArgs, XtNumber(layoutArgs));
5065 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5066 XtSetArg(args[j], XtNborderWidth, 0); j++;
5067 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5070 if(gameInfo.variant != VariantShogi) {
5071 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5072 (XtPointer) dialog);
5073 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5074 (XtPointer) dialog);
5075 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5076 (XtPointer) dialog);
5077 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5078 (XtPointer) dialog);
5079 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5080 gameInfo.variant == VariantGiveaway) {
5081 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5082 (XtPointer) dialog);
5084 if(gameInfo.variant == VariantCapablanca ||
5085 gameInfo.variant == VariantGothic ||
5086 gameInfo.variant == VariantCapaRandom) {
5087 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5088 (XtPointer) dialog);
5089 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5090 (XtPointer) dialog);
5092 } else // [HGM] shogi
5094 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5095 (XtPointer) dialog);
5096 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5097 (XtPointer) dialog);
5099 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5100 (XtPointer) dialog);
5102 XtRealizeWidget(promotionShell);
5103 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5106 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5107 XtGetValues(promotionShell, args, j);
5109 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5110 lineGap + squareSize/3 +
5111 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5112 0 : 6*(squareSize + lineGap)), &x, &y);
5115 XtSetArg(args[j], XtNx, x); j++;
5116 XtSetArg(args[j], XtNy, y); j++;
5117 XtSetValues(promotionShell, args, j);
5119 XtPopup(promotionShell, XtGrabNone);
5124 void PromotionPopDown()
5126 if (!promotionUp) return;
5127 XtPopdown(promotionShell);
5128 XtDestroyWidget(promotionShell);
5129 promotionUp = False;
5132 void PromotionCallback(w, client_data, call_data)
5134 XtPointer client_data, call_data;
5140 XtSetArg(args[0], XtNlabel, &name);
5141 XtGetValues(w, args, 1);
5145 if (fromX == -1) return;
5147 if (strcmp(name, _("cancel")) == 0) {
5151 } else if (strcmp(name, _("Knight")) == 0) {
5153 } else if (strcmp(name, _("Promote")) == 0) {
5155 } else if (strcmp(name, _("Defer")) == 0) {
5158 promoChar = ToLower(name[0]);
5161 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5163 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5164 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5169 void ErrorCallback(w, client_data, call_data)
5171 XtPointer client_data, call_data;
5174 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5176 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5182 if (!errorUp) return;
5184 XtPopdown(errorShell);
5185 XtDestroyWidget(errorShell);
5186 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5189 void ErrorPopUp(title, label, modal)
5190 char *title, *label;
5194 Widget dialog, layout;
5198 Dimension bw_width, pw_width;
5199 Dimension pw_height;
5203 XtSetArg(args[i], XtNresizable, True); i++;
5204 XtSetArg(args[i], XtNtitle, title); i++;
5206 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5207 shellWidget, args, i);
5209 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5210 layoutArgs, XtNumber(layoutArgs));
5213 XtSetArg(args[i], XtNlabel, label); i++;
5214 XtSetArg(args[i], XtNborderWidth, 0); i++;
5215 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5218 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5220 XtRealizeWidget(errorShell);
5221 CatchDeleteWindow(errorShell, "ErrorPopDown");
5224 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5225 XtGetValues(boardWidget, args, i);
5227 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5228 XtSetArg(args[i], XtNheight, &pw_height); i++;
5229 XtGetValues(errorShell, args, i);
5232 /* This code seems to tickle an X bug if it is executed too soon
5233 after xboard starts up. The coordinates get transformed as if
5234 the main window was positioned at (0, 0).
5236 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5237 0 - pw_height + squareSize / 3, &x, &y);
5239 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5240 RootWindowOfScreen(XtScreen(boardWidget)),
5241 (bw_width - pw_width) / 2,
5242 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5246 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5249 XtSetArg(args[i], XtNx, x); i++;
5250 XtSetArg(args[i], XtNy, y); i++;
5251 XtSetValues(errorShell, args, i);
5254 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5257 /* Disable all user input other than deleting the window */
5258 static int frozen = 0;
5262 /* Grab by a widget that doesn't accept input */
5263 XtAddGrab(messageWidget, TRUE, FALSE);
5267 /* Undo a FreezeUI */
5270 if (!frozen) return;
5271 XtRemoveGrab(messageWidget);
5275 char *ModeToWidgetName(mode)
5279 case BeginningOfGame:
5280 if (appData.icsActive)
5281 return "menuMode.ICS Client";
5282 else if (appData.noChessProgram ||
5283 *appData.cmailGameName != NULLCHAR)
5284 return "menuMode.Edit Game";
5286 return "menuMode.Machine Black";
5287 case MachinePlaysBlack:
5288 return "menuMode.Machine Black";
5289 case MachinePlaysWhite:
5290 return "menuMode.Machine White";
5292 return "menuMode.Analysis Mode";
5294 return "menuMode.Analyze File";
5295 case TwoMachinesPlay:
5296 return "menuMode.Two Machines";
5298 return "menuMode.Edit Game";
5299 case PlayFromGameFile:
5300 return "menuFile.Load Game";
5302 return "menuMode.Edit Position";
5304 return "menuMode.Training";
5305 case IcsPlayingWhite:
5306 case IcsPlayingBlack:
5310 return "menuMode.ICS Client";
5317 void ModeHighlight()
5320 static int oldPausing = FALSE;
5321 static GameMode oldmode = (GameMode) -1;
5324 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5326 if (pausing != oldPausing) {
5327 oldPausing = pausing;
5329 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5331 XtSetArg(args[0], XtNleftBitmap, None);
5333 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5336 if (appData.showButtonBar) {
5337 /* Always toggle, don't set. Previous code messes up when
5338 invoked while the button is pressed, as releasing it
5339 toggles the state again. */
5342 XtSetArg(args[0], XtNbackground, &oldbg);
5343 XtSetArg(args[1], XtNforeground, &oldfg);
5344 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5346 XtSetArg(args[0], XtNbackground, oldfg);
5347 XtSetArg(args[1], XtNforeground, oldbg);
5349 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5353 wname = ModeToWidgetName(oldmode);
5354 if (wname != NULL) {
5355 XtSetArg(args[0], XtNleftBitmap, None);
5356 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5358 wname = ModeToWidgetName(gameMode);
5359 if (wname != NULL) {
5360 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5361 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5365 /* Maybe all the enables should be handled here, not just this one */
5366 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5367 gameMode == Training || gameMode == PlayFromGameFile);
5372 * Button/menu procedures
5374 void ResetProc(w, event, prms, nprms)
5383 int LoadGamePopUp(f, gameNumber, title)
5388 cmailMsgLoaded = FALSE;
5389 if (gameNumber == 0) {
5390 int error = GameListBuild(f);
5392 DisplayError(_("Cannot build game list"), error);
5393 } else if (!ListEmpty(&gameList) &&
5394 ((ListGame *) gameList.tailPred)->number > 1) {
5395 GameListPopUp(f, title);
5401 return LoadGame(f, gameNumber, title, FALSE);
5404 void LoadGameProc(w, event, prms, nprms)
5410 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5413 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5416 void LoadNextGameProc(w, event, prms, nprms)
5425 void LoadPrevGameProc(w, event, prms, nprms)
5434 void ReloadGameProc(w, event, prms, nprms)
5443 void LoadNextPositionProc(w, event, prms, nprms)
5452 void LoadPrevPositionProc(w, event, prms, nprms)
5461 void ReloadPositionProc(w, event, prms, nprms)
5470 void LoadPositionProc(w, event, prms, nprms)
5476 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5479 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5482 void SaveGameProc(w, event, prms, nprms)
5488 FileNamePopUp(_("Save game file name?"),
5489 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5493 void SavePositionProc(w, event, prms, nprms)
5499 FileNamePopUp(_("Save position file name?"),
5500 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5504 void ReloadCmailMsgProc(w, event, prms, nprms)
5510 ReloadCmailMsgEvent(FALSE);
5513 void MailMoveProc(w, event, prms, nprms)
5522 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5523 static char *selected_fen_position=NULL;
5526 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5527 Atom *type_return, XtPointer *value_return,
5528 unsigned long *length_return, int *format_return)
5530 char *selection_tmp;
5532 if (!selected_fen_position) return False; /* should never happen */
5533 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5534 /* note: since no XtSelectionDoneProc was registered, Xt will
5535 * automatically call XtFree on the value returned. So have to
5536 * make a copy of it allocated with XtMalloc */
5537 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5538 strcpy(selection_tmp, selected_fen_position);
5540 *value_return=selection_tmp;
5541 *length_return=strlen(selection_tmp);
5542 *type_return=*target;
5543 *format_return = 8; /* bits per byte */
5545 } else if (*target == XA_TARGETS(xDisplay)) {
5546 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5547 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5548 targets_tmp[1] = XA_STRING;
5549 *value_return = targets_tmp;
5550 *type_return = XA_ATOM;
5552 *format_return = 8 * sizeof(Atom);
5553 if (*format_return > 32) {
5554 *length_return *= *format_return / 32;
5555 *format_return = 32;
5563 /* note: when called from menu all parameters are NULL, so no clue what the
5564 * Widget which was clicked on was, or what the click event was
5566 void CopyPositionProc(w, event, prms, nprms)
5573 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5574 * have a notion of a position that is selected but not copied.
5575 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5577 if(gameMode == EditPosition) EditPositionDone(TRUE);
5578 if (selected_fen_position) free(selected_fen_position);
5579 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5580 if (!selected_fen_position) return;
5581 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5583 SendPositionSelection,
5584 NULL/* lose_ownership_proc */ ,
5585 NULL/* transfer_done_proc */);
5586 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5588 SendPositionSelection,
5589 NULL/* lose_ownership_proc */ ,
5590 NULL/* transfer_done_proc */);
5593 /* function called when the data to Paste is ready */
5595 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5596 Atom *type, XtPointer value, unsigned long *len, int *format)
5599 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5600 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5601 EditPositionPasteFEN(fenstr);
5605 /* called when Paste Position button is pressed,
5606 * all parameters will be NULL */
5607 void PastePositionProc(w, event, prms, nprms)
5613 XtGetSelectionValue(menuBarWidget,
5614 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5615 /* (XtSelectionCallbackProc) */ PastePositionCB,
5616 NULL, /* client_data passed to PastePositionCB */
5618 /* better to use the time field from the event that triggered the
5619 * call to this function, but that isn't trivial to get
5627 SendGameSelection(Widget w, Atom *selection, Atom *target,
5628 Atom *type_return, XtPointer *value_return,
5629 unsigned long *length_return, int *format_return)
5631 char *selection_tmp;
5633 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5634 FILE* f = fopen(gameCopyFilename, "r");
5637 if (f == NULL) return False;
5641 selection_tmp = XtMalloc(len + 1);
5642 count = fread(selection_tmp, 1, len, f);
5644 XtFree(selection_tmp);
5647 selection_tmp[len] = NULLCHAR;
5648 *value_return = selection_tmp;
5649 *length_return = len;
5650 *type_return = *target;
5651 *format_return = 8; /* bits per byte */
5653 } else if (*target == XA_TARGETS(xDisplay)) {
5654 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5655 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5656 targets_tmp[1] = XA_STRING;
5657 *value_return = targets_tmp;
5658 *type_return = XA_ATOM;
5660 *format_return = 8 * sizeof(Atom);
5661 if (*format_return > 32) {
5662 *length_return *= *format_return / 32;
5663 *format_return = 32;
5671 /* note: when called from menu all parameters are NULL, so no clue what the
5672 * Widget which was clicked on was, or what the click event was
5674 void CopyGameProc(w, event, prms, nprms)
5682 ret = SaveGameToFile(gameCopyFilename, FALSE);
5686 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5687 * have a notion of a game that is selected but not copied.
5688 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5690 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5693 NULL/* lose_ownership_proc */ ,
5694 NULL/* transfer_done_proc */);
5695 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5698 NULL/* lose_ownership_proc */ ,
5699 NULL/* transfer_done_proc */);
5702 /* function called when the data to Paste is ready */
5704 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5705 Atom *type, XtPointer value, unsigned long *len, int *format)
5708 if (value == NULL || *len == 0) {
5709 return; /* nothing had been selected to copy */
5711 f = fopen(gamePasteFilename, "w");
5713 DisplayError(_("Can't open temp file"), errno);
5716 fwrite(value, 1, *len, f);
5719 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5722 /* called when Paste Game button is pressed,
5723 * all parameters will be NULL */
5724 void PasteGameProc(w, event, prms, nprms)
5730 XtGetSelectionValue(menuBarWidget,
5731 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5732 /* (XtSelectionCallbackProc) */ PasteGameCB,
5733 NULL, /* client_data passed to PasteGameCB */
5735 /* better to use the time field from the event that triggered the
5736 * call to this function, but that isn't trivial to get
5746 SaveGameProc(NULL, NULL, NULL, NULL);
5750 void QuitProc(w, event, prms, nprms)
5759 void PauseProc(w, event, prms, nprms)
5769 void MachineBlackProc(w, event, prms, nprms)
5775 MachineBlackEvent();
5778 void MachineWhiteProc(w, event, prms, nprms)
5784 MachineWhiteEvent();
5787 void AnalyzeModeProc(w, event, prms, nprms)
5795 if (!first.analysisSupport) {
5796 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5797 DisplayError(buf, 0);
5800 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5801 if (appData.icsActive) {
5802 if (gameMode != IcsObserving) {
5803 sprintf(buf,_("You are not observing a game"));
5804 DisplayError(buf, 0);
5806 if (appData.icsEngineAnalyze) {
5807 if (appData.debugMode)
5808 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5814 /* if enable, use want disable icsEngineAnalyze */
5815 if (appData.icsEngineAnalyze) {
5820 appData.icsEngineAnalyze = TRUE;
5821 if (appData.debugMode)
5822 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5824 if (!appData.showThinking)
5825 ShowThinkingProc(w,event,prms,nprms);
5830 void AnalyzeFileProc(w, event, prms, nprms)
5836 if (!first.analysisSupport) {
5838 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5839 DisplayError(buf, 0);
5844 if (!appData.showThinking)
5845 ShowThinkingProc(w,event,prms,nprms);
5848 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5849 AnalysisPeriodicEvent(1);
5852 void TwoMachinesProc(w, event, prms, nprms)
5861 void IcsClientProc(w, event, prms, nprms)
5870 void EditGameProc(w, event, prms, nprms)
5879 void EditPositionProc(w, event, prms, nprms)
5885 EditPositionEvent();
5888 void TrainingProc(w, event, prms, nprms)
5897 void EditCommentProc(w, event, prms, nprms)
5904 EditCommentPopDown();
5910 void IcsInputBoxProc(w, event, prms, nprms)
5916 if (ICSInputBoxUp) {
5917 ICSInputBoxPopDown();
5923 void AcceptProc(w, event, prms, nprms)
5932 void DeclineProc(w, event, prms, nprms)
5941 void RematchProc(w, event, prms, nprms)
5950 void CallFlagProc(w, event, prms, nprms)
5959 void DrawProc(w, event, prms, nprms)
5968 void AbortProc(w, event, prms, nprms)
5977 void AdjournProc(w, event, prms, nprms)
5986 void ResignProc(w, event, prms, nprms)
5995 void AdjuWhiteProc(w, event, prms, nprms)
6001 UserAdjudicationEvent(+1);
6004 void AdjuBlackProc(w, event, prms, nprms)
6010 UserAdjudicationEvent(-1);
6013 void AdjuDrawProc(w, event, prms, nprms)
6019 UserAdjudicationEvent(0);
6022 void EnterKeyProc(w, event, prms, nprms)
6028 if (ICSInputBoxUp == True)
6032 void StopObservingProc(w, event, prms, nprms)
6038 StopObservingEvent();
6041 void StopExaminingProc(w, event, prms, nprms)
6047 StopExaminingEvent();
6051 void ForwardProc(w, event, prms, nprms)
6061 void BackwardProc(w, event, prms, nprms)
6070 void ToStartProc(w, event, prms, nprms)
6079 void ToEndProc(w, event, prms, nprms)
6088 void RevertProc(w, event, prms, nprms)
6097 void TruncateGameProc(w, event, prms, nprms)
6103 TruncateGameEvent();
6105 void RetractMoveProc(w, event, prms, nprms)
6114 void MoveNowProc(w, event, prms, nprms)
6124 void AlwaysQueenProc(w, event, prms, nprms)
6132 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6134 if (appData.alwaysPromoteToQueen) {
6135 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6137 XtSetArg(args[0], XtNleftBitmap, None);
6139 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6143 void AnimateDraggingProc(w, event, prms, nprms)
6151 appData.animateDragging = !appData.animateDragging;
6153 if (appData.animateDragging) {
6154 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6157 XtSetArg(args[0], XtNleftBitmap, None);
6159 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6163 void AnimateMovingProc(w, event, prms, nprms)
6171 appData.animate = !appData.animate;
6173 if (appData.animate) {
6174 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6177 XtSetArg(args[0], XtNleftBitmap, None);
6179 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6183 void AutocommProc(w, event, prms, nprms)
6191 appData.autoComment = !appData.autoComment;
6193 if (appData.autoComment) {
6194 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6196 XtSetArg(args[0], XtNleftBitmap, None);
6198 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6203 void AutoflagProc(w, event, prms, nprms)
6211 appData.autoCallFlag = !appData.autoCallFlag;
6213 if (appData.autoCallFlag) {
6214 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6216 XtSetArg(args[0], XtNleftBitmap, None);
6218 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6222 void AutoflipProc(w, event, prms, nprms)
6230 appData.autoFlipView = !appData.autoFlipView;
6232 if (appData.autoFlipView) {
6233 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6235 XtSetArg(args[0], XtNleftBitmap, None);
6237 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6241 void AutobsProc(w, event, prms, nprms)
6249 appData.autoObserve = !appData.autoObserve;
6251 if (appData.autoObserve) {
6252 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6254 XtSetArg(args[0], XtNleftBitmap, None);
6256 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6260 void AutoraiseProc(w, event, prms, nprms)
6268 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6270 if (appData.autoRaiseBoard) {
6271 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6273 XtSetArg(args[0], XtNleftBitmap, None);
6275 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6279 void AutosaveProc(w, event, prms, nprms)
6287 appData.autoSaveGames = !appData.autoSaveGames;
6289 if (appData.autoSaveGames) {
6290 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6292 XtSetArg(args[0], XtNleftBitmap, None);
6294 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6298 void BlindfoldProc(w, event, prms, nprms)
6306 appData.blindfold = !appData.blindfold;
6308 if (appData.blindfold) {
6309 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6311 XtSetArg(args[0], XtNleftBitmap, None);
6313 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6316 DrawPosition(True, NULL);
6319 void TestLegalityProc(w, event, prms, nprms)
6327 appData.testLegality = !appData.testLegality;
6329 if (appData.testLegality) {
6330 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6332 XtSetArg(args[0], XtNleftBitmap, None);
6334 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6339 void FlashMovesProc(w, event, prms, nprms)
6347 if (appData.flashCount == 0) {
6348 appData.flashCount = 3;
6350 appData.flashCount = -appData.flashCount;
6353 if (appData.flashCount > 0) {
6354 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6356 XtSetArg(args[0], XtNleftBitmap, None);
6358 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6362 void FlipViewProc(w, event, prms, nprms)
6368 flipView = !flipView;
6369 DrawPosition(True, NULL);
6372 void GetMoveListProc(w, event, prms, nprms)
6380 appData.getMoveList = !appData.getMoveList;
6382 if (appData.getMoveList) {
6383 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6386 XtSetArg(args[0], XtNleftBitmap, None);
6388 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6393 void HighlightDraggingProc(w, event, prms, nprms)
6401 appData.highlightDragging = !appData.highlightDragging;
6403 if (appData.highlightDragging) {
6404 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6406 XtSetArg(args[0], XtNleftBitmap, None);
6408 XtSetValues(XtNameToWidget(menuBarWidget,
6409 "menuOptions.Highlight Dragging"), args, 1);
6413 void HighlightLastMoveProc(w, event, prms, nprms)
6421 appData.highlightLastMove = !appData.highlightLastMove;
6423 if (appData.highlightLastMove) {
6424 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6426 XtSetArg(args[0], XtNleftBitmap, None);
6428 XtSetValues(XtNameToWidget(menuBarWidget,
6429 "menuOptions.Highlight Last Move"), args, 1);
6432 void IcsAlarmProc(w, event, prms, nprms)
6440 appData.icsAlarm = !appData.icsAlarm;
6442 if (appData.icsAlarm) {
6443 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6445 XtSetArg(args[0], XtNleftBitmap, None);
6447 XtSetValues(XtNameToWidget(menuBarWidget,
6448 "menuOptions.ICS Alarm"), args, 1);
6451 void MoveSoundProc(w, event, prms, nprms)
6459 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6461 if (appData.ringBellAfterMoves) {
6462 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6464 XtSetArg(args[0], XtNleftBitmap, None);
6466 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6471 void OldSaveStyleProc(w, event, prms, nprms)
6479 appData.oldSaveStyle = !appData.oldSaveStyle;
6481 if (appData.oldSaveStyle) {
6482 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6484 XtSetArg(args[0], XtNleftBitmap, None);
6486 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6490 void PeriodicUpdatesProc(w, event, prms, nprms)
6498 PeriodicUpdatesEvent(!appData.periodicUpdates);
6500 if (appData.periodicUpdates) {
6501 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6503 XtSetArg(args[0], XtNleftBitmap, None);
6505 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6509 void PonderNextMoveProc(w, event, prms, nprms)
6517 PonderNextMoveEvent(!appData.ponderNextMove);
6519 if (appData.ponderNextMove) {
6520 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6522 XtSetArg(args[0], XtNleftBitmap, None);
6524 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6528 void PopupExitMessageProc(w, event, prms, nprms)
6536 appData.popupExitMessage = !appData.popupExitMessage;
6538 if (appData.popupExitMessage) {
6539 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6541 XtSetArg(args[0], XtNleftBitmap, None);
6543 XtSetValues(XtNameToWidget(menuBarWidget,
6544 "menuOptions.Popup Exit Message"), args, 1);
6547 void PopupMoveErrorsProc(w, event, prms, nprms)
6555 appData.popupMoveErrors = !appData.popupMoveErrors;
6557 if (appData.popupMoveErrors) {
6558 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6560 XtSetArg(args[0], XtNleftBitmap, None);
6562 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6566 void PremoveProc(w, event, prms, nprms)
6574 appData.premove = !appData.premove;
6576 if (appData.premove) {
6577 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6579 XtSetArg(args[0], XtNleftBitmap, None);
6581 XtSetValues(XtNameToWidget(menuBarWidget,
6582 "menuOptions.Premove"), args, 1);
6585 void QuietPlayProc(w, event, prms, nprms)
6593 appData.quietPlay = !appData.quietPlay;
6595 if (appData.quietPlay) {
6596 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6598 XtSetArg(args[0], XtNleftBitmap, None);
6600 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6604 void ShowCoordsProc(w, event, prms, nprms)
6612 appData.showCoords = !appData.showCoords;
6614 if (appData.showCoords) {
6615 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6617 XtSetArg(args[0], XtNleftBitmap, None);
6619 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6622 DrawPosition(True, NULL);
6625 void ShowThinkingProc(w, event, prms, nprms)
6631 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6632 ShowThinkingEvent();
6635 void HideThinkingProc(w, event, prms, nprms)
6643 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6644 ShowThinkingEvent();
6646 if (appData.hideThinkingFromHuman) {
6647 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6649 XtSetArg(args[0], XtNleftBitmap, None);
6651 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6655 void SaveOnExitProc(w, event, prms, nprms)
6663 saveSettingsOnExit = !saveSettingsOnExit;
6665 if (saveSettingsOnExit) {
6666 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6668 XtSetArg(args[0], XtNleftBitmap, None);
6670 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6674 void SaveSettingsProc(w, event, prms, nprms)
6680 SaveSettings(settingsFileName);
6683 void InfoProc(w, event, prms, nprms)
6690 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6695 void ManProc(w, event, prms, nprms)
6703 if (nprms && *nprms > 0)
6707 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6711 void HintProc(w, event, prms, nprms)
6720 void BookProc(w, event, prms, nprms)
6729 void AboutProc(w, event, prms, nprms)
6737 char *zippy = " (with Zippy code)";
6741 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6742 programVersion, zippy,
6743 "Copyright 1991 Digital Equipment Corporation",
6744 "Enhancements Copyright 1992-2009 Free Software Foundation",
6745 "Enhancements Copyright 2005 Alessandro Scotti",
6746 PACKAGE, " is free software and carries NO WARRANTY;",
6747 "see the file COPYING for more information.");
6748 ErrorPopUp(_("About XBoard"), buf, FALSE);
6751 void DebugProc(w, event, prms, nprms)
6757 appData.debugMode = !appData.debugMode;
6760 void AboutGameProc(w, event, prms, nprms)
6769 void NothingProc(w, event, prms, nprms)
6778 void Iconify(w, event, prms, nprms)
6787 XtSetArg(args[0], XtNiconic, True);
6788 XtSetValues(shellWidget, args, 1);
6791 void DisplayMessage(message, extMessage)
6792 char *message, *extMessage;
6794 /* display a message in the message widget */
6803 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6808 message = extMessage;
6812 /* need to test if messageWidget already exists, since this function
6813 can also be called during the startup, if for example a Xresource
6814 is not set up correctly */
6817 XtSetArg(arg, XtNlabel, message);
6818 XtSetValues(messageWidget, &arg, 1);
6824 void DisplayTitle(text)
6829 char title[MSG_SIZ];
6832 if (text == NULL) text = "";
6834 if (appData.titleInWindow) {
6836 XtSetArg(args[i], XtNlabel, text); i++;
6837 XtSetValues(titleWidget, args, i);
6840 if (*text != NULLCHAR) {
6842 strcpy(title, text);
6843 } else if (appData.icsActive) {
6844 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6845 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6846 } else if (appData.cmailGameName[0] != NULLCHAR) {
6847 snprintf(icon, sizeof(icon), "%s", "CMail");
6848 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6850 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6851 } else if (gameInfo.variant == VariantGothic) {
6852 strcpy(icon, programName);
6853 strcpy(title, GOTHIC);
6856 } else if (gameInfo.variant == VariantFalcon) {
6857 strcpy(icon, programName);
6858 strcpy(title, FALCON);
6860 } else if (appData.noChessProgram) {
6861 strcpy(icon, programName);
6862 strcpy(title, programName);
6864 strcpy(icon, first.tidy);
6865 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6868 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6869 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6870 XtSetValues(shellWidget, args, i);
6874 void DisplayError(message, error)
6881 if (appData.debugMode || appData.matchMode) {
6882 fprintf(stderr, "%s: %s\n", programName, message);
6885 if (appData.debugMode || appData.matchMode) {
6886 fprintf(stderr, "%s: %s: %s\n",
6887 programName, message, strerror(error));
6889 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6892 ErrorPopUp(_("Error"), message, FALSE);
6896 void DisplayMoveError(message)
6901 DrawPosition(FALSE, NULL);
6902 if (appData.debugMode || appData.matchMode) {
6903 fprintf(stderr, "%s: %s\n", programName, message);
6905 if (appData.popupMoveErrors) {
6906 ErrorPopUp(_("Error"), message, FALSE);
6908 DisplayMessage(message, "");
6913 void DisplayFatalError(message, error, status)
6919 errorExitStatus = status;
6921 fprintf(stderr, "%s: %s\n", programName, message);
6923 fprintf(stderr, "%s: %s: %s\n",
6924 programName, message, strerror(error));
6925 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6928 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6929 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6935 void DisplayInformation(message)
6939 ErrorPopUp(_("Information"), message, TRUE);
6942 void DisplayNote(message)
6946 ErrorPopUp(_("Note"), message, FALSE);
6950 NullXErrorCheck(dpy, error_event)
6952 XErrorEvent *error_event;
6957 void DisplayIcsInteractionTitle(message)
6960 if (oldICSInteractionTitle == NULL) {
6961 /* Magic to find the old window title, adapted from vim */
6962 char *wina = getenv("WINDOWID");
6964 Window win = (Window) atoi(wina);
6965 Window root, parent, *children;
6966 unsigned int nchildren;
6967 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6969 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6970 if (!XQueryTree(xDisplay, win, &root, &parent,
6971 &children, &nchildren)) break;
6972 if (children) XFree((void *)children);
6973 if (parent == root || parent == 0) break;
6976 XSetErrorHandler(oldHandler);
6978 if (oldICSInteractionTitle == NULL) {
6979 oldICSInteractionTitle = "xterm";
6982 printf("\033]0;%s\007", message);
6986 char pendingReplyPrefix[MSG_SIZ];
6987 ProcRef pendingReplyPR;
6989 void AskQuestionProc(w, event, prms, nprms)
6996 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7000 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7003 void AskQuestionPopDown()
7005 if (!askQuestionUp) return;
7006 XtPopdown(askQuestionShell);
7007 XtDestroyWidget(askQuestionShell);
7008 askQuestionUp = False;
7011 void AskQuestionReplyAction(w, event, prms, nprms)
7021 reply = XawDialogGetValueString(w = XtParent(w));
7022 strcpy(buf, pendingReplyPrefix);
7023 if (*buf) strcat(buf, " ");
7026 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7027 AskQuestionPopDown();
7029 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7032 void AskQuestionCallback(w, client_data, call_data)
7034 XtPointer client_data, call_data;
7039 XtSetArg(args[0], XtNlabel, &name);
7040 XtGetValues(w, args, 1);
7042 if (strcmp(name, _("cancel")) == 0) {
7043 AskQuestionPopDown();
7045 AskQuestionReplyAction(w, NULL, NULL, NULL);
7049 void AskQuestion(title, question, replyPrefix, pr)
7050 char *title, *question, *replyPrefix;
7054 Widget popup, layout, dialog, edit;
7060 strcpy(pendingReplyPrefix, replyPrefix);
7061 pendingReplyPR = pr;
7064 XtSetArg(args[i], XtNresizable, True); i++;
7065 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7066 askQuestionShell = popup =
7067 XtCreatePopupShell(title, transientShellWidgetClass,
7068 shellWidget, args, i);
7071 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7072 layoutArgs, XtNumber(layoutArgs));
7075 XtSetArg(args[i], XtNlabel, question); i++;
7076 XtSetArg(args[i], XtNvalue, ""); i++;
7077 XtSetArg(args[i], XtNborderWidth, 0); i++;
7078 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7081 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7082 (XtPointer) dialog);
7083 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7084 (XtPointer) dialog);
7086 XtRealizeWidget(popup);
7087 CatchDeleteWindow(popup, "AskQuestionPopDown");
7089 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7090 &x, &y, &win_x, &win_y, &mask);
7092 XtSetArg(args[0], XtNx, x - 10);
7093 XtSetArg(args[1], XtNy, y - 30);
7094 XtSetValues(popup, args, 2);
7096 XtPopup(popup, XtGrabExclusive);
7097 askQuestionUp = True;
7099 edit = XtNameToWidget(dialog, "*value");
7100 XtSetKeyboardFocus(popup, edit);
7108 if (*name == NULLCHAR) {
7110 } else if (strcmp(name, "$") == 0) {
7111 putc(BELLCHAR, stderr);
7114 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7122 PlaySound(appData.soundMove);
7128 PlaySound(appData.soundIcsWin);
7134 PlaySound(appData.soundIcsLoss);
7140 PlaySound(appData.soundIcsDraw);
7144 PlayIcsUnfinishedSound()
7146 PlaySound(appData.soundIcsUnfinished);
7152 PlaySound(appData.soundIcsAlarm);
7158 system("stty echo");
7164 system("stty -echo");
7168 Colorize(cc, continuation)
7173 int count, outCount, error;
7175 if (textColors[(int)cc].bg > 0) {
7176 if (textColors[(int)cc].fg > 0) {
7177 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7178 textColors[(int)cc].fg, textColors[(int)cc].bg);
7180 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7181 textColors[(int)cc].bg);
7184 if (textColors[(int)cc].fg > 0) {
7185 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7186 textColors[(int)cc].fg);
7188 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7191 count = strlen(buf);
7192 outCount = OutputToProcess(NoProc, buf, count, &error);
7193 if (outCount < count) {
7194 DisplayFatalError(_("Error writing to display"), error, 1);
7197 if (continuation) return;
7200 PlaySound(appData.soundShout);
7203 PlaySound(appData.soundSShout);
7206 PlaySound(appData.soundChannel1);
7209 PlaySound(appData.soundChannel);
7212 PlaySound(appData.soundKibitz);
7215 PlaySound(appData.soundTell);
7217 case ColorChallenge:
7218 PlaySound(appData.soundChallenge);
7221 PlaySound(appData.soundRequest);
7224 PlaySound(appData.soundSeek);
7235 return getpwuid(getuid())->pw_name;
7238 static char *ExpandPathName(path)
7241 static char static_buf[2000];
7242 char *d, *s, buf[2000];
7248 while (*s && isspace(*s))
7257 if (*(s+1) == '/') {
7258 strcpy(d, getpwuid(getuid())->pw_dir);
7263 *strchr(buf, '/') = 0;
7264 pwd = getpwnam(buf);
7267 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7271 strcpy(d, pwd->pw_dir);
7272 strcat(d, strchr(s+1, '/'));
7283 static char host_name[MSG_SIZ];
7285 #if HAVE_GETHOSTNAME
7286 gethostname(host_name, MSG_SIZ);
7288 #else /* not HAVE_GETHOSTNAME */
7289 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7290 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7292 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7294 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7295 #endif /* not HAVE_GETHOSTNAME */
7298 XtIntervalId delayedEventTimerXID = 0;
7299 DelayedEventCallback delayedEventCallback = 0;
7304 delayedEventTimerXID = 0;
7305 delayedEventCallback();
7309 ScheduleDelayedEvent(cb, millisec)
7310 DelayedEventCallback cb; long millisec;
7312 if(delayedEventTimerXID && delayedEventCallback == cb)
7313 // [HGM] alive: replace, rather than add or flush identical event
7314 XtRemoveTimeOut(delayedEventTimerXID);
7315 delayedEventCallback = cb;
7316 delayedEventTimerXID =
7317 XtAppAddTimeOut(appContext, millisec,
7318 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7321 DelayedEventCallback
7324 if (delayedEventTimerXID) {
7325 return delayedEventCallback;
7332 CancelDelayedEvent()
7334 if (delayedEventTimerXID) {
7335 XtRemoveTimeOut(delayedEventTimerXID);
7336 delayedEventTimerXID = 0;
7340 XtIntervalId loadGameTimerXID = 0;
7342 int LoadGameTimerRunning()
7344 return loadGameTimerXID != 0;
7347 int StopLoadGameTimer()
7349 if (loadGameTimerXID != 0) {
7350 XtRemoveTimeOut(loadGameTimerXID);
7351 loadGameTimerXID = 0;
7359 LoadGameTimerCallback(arg, id)
7363 loadGameTimerXID = 0;
7368 StartLoadGameTimer(millisec)
7372 XtAppAddTimeOut(appContext, millisec,
7373 (XtTimerCallbackProc) LoadGameTimerCallback,
7377 XtIntervalId analysisClockXID = 0;
7380 AnalysisClockCallback(arg, id)
7384 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7385 || appData.icsEngineAnalyze) { // [DM]
7386 AnalysisPeriodicEvent(0);
7387 StartAnalysisClock();
7392 StartAnalysisClock()
7395 XtAppAddTimeOut(appContext, 2000,
7396 (XtTimerCallbackProc) AnalysisClockCallback,
7400 XtIntervalId clockTimerXID = 0;
7402 int ClockTimerRunning()
7404 return clockTimerXID != 0;
7407 int StopClockTimer()
7409 if (clockTimerXID != 0) {
7410 XtRemoveTimeOut(clockTimerXID);
7419 ClockTimerCallback(arg, id)
7428 StartClockTimer(millisec)
7432 XtAppAddTimeOut(appContext, millisec,
7433 (XtTimerCallbackProc) ClockTimerCallback,
7438 DisplayTimerLabel(w, color, timer, highlight)
7447 /* check for low time warning */
7448 Pixel foregroundOrWarningColor = timerForegroundPixel;
7451 appData.lowTimeWarning &&
7452 (timer / 1000) < appData.icsAlarmTime)
7453 foregroundOrWarningColor = lowTimeWarningColor;
7455 if (appData.clockMode) {
7456 sprintf(buf, "%s: %s", color, TimeString(timer));
7457 XtSetArg(args[0], XtNlabel, buf);
7459 sprintf(buf, "%s ", color);
7460 XtSetArg(args[0], XtNlabel, buf);
7465 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7466 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7468 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7469 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7472 XtSetValues(w, args, 3);
7476 DisplayWhiteClock(timeRemaining, highlight)
7482 if(appData.noGUI) return;
7483 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7484 if (highlight && iconPixmap == bIconPixmap) {
7485 iconPixmap = wIconPixmap;
7486 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7487 XtSetValues(shellWidget, args, 1);
7492 DisplayBlackClock(timeRemaining, highlight)
7498 if(appData.noGUI) return;
7499 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7500 if (highlight && iconPixmap == wIconPixmap) {
7501 iconPixmap = bIconPixmap;
7502 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7503 XtSetValues(shellWidget, args, 1);
7521 int StartChildProcess(cmdLine, dir, pr)
7528 int to_prog[2], from_prog[2];
7532 if (appData.debugMode) {
7533 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7536 /* We do NOT feed the cmdLine to the shell; we just
7537 parse it into blank-separated arguments in the
7538 most simple-minded way possible.
7541 strcpy(buf, cmdLine);
7544 while(*p == ' ') p++;
7546 if(*p == '"' || *p == '\'')
7547 p = strchr(++argv[i-1], *p);
7548 else p = strchr(p, ' ');
7549 if (p == NULL) break;
7554 SetUpChildIO(to_prog, from_prog);
7556 if ((pid = fork()) == 0) {
7558 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7559 close(to_prog[1]); // first close the unused pipe ends
7560 close(from_prog[0]);
7561 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7562 dup2(from_prog[1], 1);
7563 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7564 close(from_prog[1]); // and closing again loses one of the pipes!
7565 if(fileno(stderr) >= 2) // better safe than sorry...
7566 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7568 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7573 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7575 execvp(argv[0], argv);
7577 /* If we get here, exec failed */
7582 /* Parent process */
7584 close(from_prog[1]);
7586 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7589 cp->fdFrom = from_prog[0];
7590 cp->fdTo = to_prog[1];
7595 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7596 static RETSIGTYPE AlarmCallBack(int n)
7602 DestroyChildProcess(pr, signalType)
7606 ChildProc *cp = (ChildProc *) pr;
7608 if (cp->kind != CPReal) return;
7610 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7611 signal(SIGALRM, AlarmCallBack);
7613 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7614 kill(cp->pid, SIGKILL); // kill it forcefully
7615 wait((int *) 0); // and wait again
7619 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7621 /* Process is exiting either because of the kill or because of
7622 a quit command sent by the backend; either way, wait for it to die.
7631 InterruptChildProcess(pr)
7634 ChildProc *cp = (ChildProc *) pr;
7636 if (cp->kind != CPReal) return;
7637 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7640 int OpenTelnet(host, port, pr)
7645 char cmdLine[MSG_SIZ];
7647 if (port[0] == NULLCHAR) {
7648 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7650 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7652 return StartChildProcess(cmdLine, "", pr);
7655 int OpenTCP(host, port, pr)
7661 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7662 #else /* !OMIT_SOCKETS */
7664 struct sockaddr_in sa;
7666 unsigned short uport;
7669 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7673 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7674 sa.sin_family = AF_INET;
7675 sa.sin_addr.s_addr = INADDR_ANY;
7676 uport = (unsigned short) 0;
7677 sa.sin_port = htons(uport);
7678 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7682 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7683 if (!(hp = gethostbyname(host))) {
7685 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7686 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7687 hp->h_addrtype = AF_INET;
7689 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7690 hp->h_addr_list[0] = (char *) malloc(4);
7691 hp->h_addr_list[0][0] = b0;
7692 hp->h_addr_list[0][1] = b1;
7693 hp->h_addr_list[0][2] = b2;
7694 hp->h_addr_list[0][3] = b3;
7699 sa.sin_family = hp->h_addrtype;
7700 uport = (unsigned short) atoi(port);
7701 sa.sin_port = htons(uport);
7702 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7704 if (connect(s, (struct sockaddr *) &sa,
7705 sizeof(struct sockaddr_in)) < 0) {
7709 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7716 #endif /* !OMIT_SOCKETS */
7721 int OpenCommPort(name, pr)
7728 fd = open(name, 2, 0);
7729 if (fd < 0) return errno;
7731 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7741 int OpenLoopback(pr)
7747 SetUpChildIO(to, from);
7749 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7752 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7759 int OpenRcmd(host, user, cmd, pr)
7760 char *host, *user, *cmd;
7763 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7767 #define INPUT_SOURCE_BUF_SIZE 8192
7776 char buf[INPUT_SOURCE_BUF_SIZE];
7781 DoInputCallback(closure, source, xid)
7786 InputSource *is = (InputSource *) closure;
7791 if (is->lineByLine) {
7792 count = read(is->fd, is->unused,
7793 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7795 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7798 is->unused += count;
7800 while (p < is->unused) {
7801 q = memchr(p, '\n', is->unused - p);
7802 if (q == NULL) break;
7804 (is->func)(is, is->closure, p, q - p, 0);
7808 while (p < is->unused) {
7813 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7818 (is->func)(is, is->closure, is->buf, count, error);
7822 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7829 ChildProc *cp = (ChildProc *) pr;
7831 is = (InputSource *) calloc(1, sizeof(InputSource));
7832 is->lineByLine = lineByLine;
7836 is->fd = fileno(stdin);
7838 is->kind = cp->kind;
7839 is->fd = cp->fdFrom;
7842 is->unused = is->buf;
7845 is->xid = XtAppAddInput(appContext, is->fd,
7846 (XtPointer) (XtInputReadMask),
7847 (XtInputCallbackProc) DoInputCallback,
7849 is->closure = closure;
7850 return (InputSourceRef) is;
7854 RemoveInputSource(isr)
7857 InputSource *is = (InputSource *) isr;
7859 if (is->xid == 0) return;
7860 XtRemoveInput(is->xid);
7864 int OutputToProcess(pr, message, count, outError)
7870 static int line = 0;
7871 ChildProc *cp = (ChildProc *) pr;
7876 if (appData.noJoin || !appData.useInternalWrap)
7877 outCount = fwrite(message, 1, count, stdout);
7880 int width = get_term_width();
7881 int len = wrap(NULL, message, count, width, &line);
7882 char *msg = malloc(len);
7886 outCount = fwrite(message, 1, count, stdout);
7889 dbgchk = wrap(msg, message, count, width, &line);
7890 if (dbgchk != len && appData.debugMode)
7891 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7892 outCount = fwrite(msg, 1, dbgchk, stdout);
7898 outCount = write(cp->fdTo, message, count);
7908 /* Output message to process, with "ms" milliseconds of delay
7909 between each character. This is needed when sending the logon
7910 script to ICC, which for some reason doesn't like the
7911 instantaneous send. */
7912 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7919 ChildProc *cp = (ChildProc *) pr;
7924 r = write(cp->fdTo, message++, 1);
7937 /**** Animation code by Hugh Fisher, DCS, ANU.
7939 Known problem: if a window overlapping the board is
7940 moved away while a piece is being animated underneath,
7941 the newly exposed area won't be updated properly.
7942 I can live with this.
7944 Known problem: if you look carefully at the animation
7945 of pieces in mono mode, they are being drawn as solid
7946 shapes without interior detail while moving. Fixing
7947 this would be a major complication for minimal return.
7950 /* Masks for XPM pieces. Black and white pieces can have
7951 different shapes, but in the interest of retaining my
7952 sanity pieces must have the same outline on both light
7953 and dark squares, and all pieces must use the same
7954 background square colors/images. */
7956 static int xpmDone = 0;
7959 CreateAnimMasks (pieceDepth)
7966 unsigned long plane;
7969 /* Need a bitmap just to get a GC with right depth */
7970 buf = XCreatePixmap(xDisplay, xBoardWindow,
7972 values.foreground = 1;
7973 values.background = 0;
7974 /* Don't use XtGetGC, not read only */
7975 maskGC = XCreateGC(xDisplay, buf,
7976 GCForeground | GCBackground, &values);
7977 XFreePixmap(xDisplay, buf);
7979 buf = XCreatePixmap(xDisplay, xBoardWindow,
7980 squareSize, squareSize, pieceDepth);
7981 values.foreground = XBlackPixel(xDisplay, xScreen);
7982 values.background = XWhitePixel(xDisplay, xScreen);
7983 bufGC = XCreateGC(xDisplay, buf,
7984 GCForeground | GCBackground, &values);
7986 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7987 /* Begin with empty mask */
7988 if(!xpmDone) // [HGM] pieces: keep using existing
7989 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7990 squareSize, squareSize, 1);
7991 XSetFunction(xDisplay, maskGC, GXclear);
7992 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7993 0, 0, squareSize, squareSize);
7995 /* Take a copy of the piece */
8000 XSetFunction(xDisplay, bufGC, GXcopy);
8001 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8003 0, 0, squareSize, squareSize, 0, 0);
8005 /* XOR the background (light) over the piece */
8006 XSetFunction(xDisplay, bufGC, GXxor);
8008 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8009 0, 0, squareSize, squareSize, 0, 0);
8011 XSetForeground(xDisplay, bufGC, lightSquareColor);
8012 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8015 /* We now have an inverted piece image with the background
8016 erased. Construct mask by just selecting all the non-zero
8017 pixels - no need to reconstruct the original image. */
8018 XSetFunction(xDisplay, maskGC, GXor);
8020 /* Might be quicker to download an XImage and create bitmap
8021 data from it rather than this N copies per piece, but it
8022 only takes a fraction of a second and there is a much
8023 longer delay for loading the pieces. */
8024 for (n = 0; n < pieceDepth; n ++) {
8025 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8026 0, 0, squareSize, squareSize,
8032 XFreePixmap(xDisplay, buf);
8033 XFreeGC(xDisplay, bufGC);
8034 XFreeGC(xDisplay, maskGC);
8038 InitAnimState (anim, info)
8040 XWindowAttributes * info;
8045 /* Each buffer is square size, same depth as window */
8046 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8047 squareSize, squareSize, info->depth);
8048 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8049 squareSize, squareSize, info->depth);
8051 /* Create a plain GC for blitting */
8052 mask = GCForeground | GCBackground | GCFunction |
8053 GCPlaneMask | GCGraphicsExposures;
8054 values.foreground = XBlackPixel(xDisplay, xScreen);
8055 values.background = XWhitePixel(xDisplay, xScreen);
8056 values.function = GXcopy;
8057 values.plane_mask = AllPlanes;
8058 values.graphics_exposures = False;
8059 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8061 /* Piece will be copied from an existing context at
8062 the start of each new animation/drag. */
8063 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8065 /* Outline will be a read-only copy of an existing */
8066 anim->outlineGC = None;
8072 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8073 XWindowAttributes info;
8075 if (xpmDone && gameInfo.variant == old) return;
8076 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8077 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8079 InitAnimState(&game, &info);
8080 InitAnimState(&player, &info);
8082 /* For XPM pieces, we need bitmaps to use as masks. */
8084 CreateAnimMasks(info.depth);
8090 static Boolean frameWaiting;
8092 static RETSIGTYPE FrameAlarm (sig)
8095 frameWaiting = False;
8096 /* In case System-V style signals. Needed?? */
8097 signal(SIGALRM, FrameAlarm);
8104 struct itimerval delay;
8106 XSync(xDisplay, False);
8109 frameWaiting = True;
8110 signal(SIGALRM, FrameAlarm);
8111 delay.it_interval.tv_sec =
8112 delay.it_value.tv_sec = time / 1000;
8113 delay.it_interval.tv_usec =
8114 delay.it_value.tv_usec = (time % 1000) * 1000;
8115 setitimer(ITIMER_REAL, &delay, NULL);
8116 while (frameWaiting) pause();
8117 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8118 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8119 setitimer(ITIMER_REAL, &delay, NULL);
8129 XSync(xDisplay, False);
8131 usleep(time * 1000);
8136 /* Convert board position to corner of screen rect and color */
8139 ScreenSquare(column, row, pt, color)
8140 int column; int row; XPoint * pt; int * color;
8143 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8144 pt->y = lineGap + row * (squareSize + lineGap);
8146 pt->x = lineGap + column * (squareSize + lineGap);
8147 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8149 *color = SquareColor(row, column);
8152 /* Convert window coords to square */
8155 BoardSquare(x, y, column, row)
8156 int x; int y; int * column; int * row;
8158 *column = EventToSquare(x, BOARD_WIDTH);
8159 if (flipView && *column >= 0)
8160 *column = BOARD_WIDTH - 1 - *column;
8161 *row = EventToSquare(y, BOARD_HEIGHT);
8162 if (!flipView && *row >= 0)
8163 *row = BOARD_HEIGHT - 1 - *row;
8168 #undef Max /* just in case */
8170 #define Max(a, b) ((a) > (b) ? (a) : (b))
8171 #define Min(a, b) ((a) < (b) ? (a) : (b))
8174 SetRect(rect, x, y, width, height)
8175 XRectangle * rect; int x; int y; int width; int height;
8179 rect->width = width;
8180 rect->height = height;
8183 /* Test if two frames overlap. If they do, return
8184 intersection rect within old and location of
8185 that rect within new. */
8188 Intersect(old, new, size, area, pt)
8189 XPoint * old; XPoint * new;
8190 int size; XRectangle * area; XPoint * pt;
8192 if (old->x > new->x + size || new->x > old->x + size ||
8193 old->y > new->y + size || new->y > old->y + size) {
8196 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8197 size - abs(old->x - new->x), size - abs(old->y - new->y));
8198 pt->x = Max(old->x - new->x, 0);
8199 pt->y = Max(old->y - new->y, 0);
8204 /* For two overlapping frames, return the rect(s)
8205 in the old that do not intersect with the new. */
8208 CalcUpdateRects(old, new, size, update, nUpdates)
8209 XPoint * old; XPoint * new; int size;
8210 XRectangle update[]; int * nUpdates;
8214 /* If old = new (shouldn't happen) then nothing to draw */
8215 if (old->x == new->x && old->y == new->y) {
8219 /* Work out what bits overlap. Since we know the rects
8220 are the same size we don't need a full intersect calc. */
8222 /* Top or bottom edge? */
8223 if (new->y > old->y) {
8224 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8226 } else if (old->y > new->y) {
8227 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8228 size, old->y - new->y);
8231 /* Left or right edge - don't overlap any update calculated above. */
8232 if (new->x > old->x) {
8233 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8234 new->x - old->x, size - abs(new->y - old->y));
8236 } else if (old->x > new->x) {
8237 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8238 old->x - new->x, size - abs(new->y - old->y));
8245 /* Generate a series of frame coords from start->mid->finish.
8246 The movement rate doubles until the half way point is
8247 reached, then halves back down to the final destination,
8248 which gives a nice slow in/out effect. The algorithmn
8249 may seem to generate too many intermediates for short
8250 moves, but remember that the purpose is to attract the
8251 viewers attention to the piece about to be moved and
8252 then to where it ends up. Too few frames would be less
8256 Tween(start, mid, finish, factor, frames, nFrames)
8257 XPoint * start; XPoint * mid;
8258 XPoint * finish; int factor;
8259 XPoint frames[]; int * nFrames;
8261 int fraction, n, count;
8265 /* Slow in, stepping 1/16th, then 1/8th, ... */
8267 for (n = 0; n < factor; n++)
8269 for (n = 0; n < factor; n++) {
8270 frames[count].x = start->x + (mid->x - start->x) / fraction;
8271 frames[count].y = start->y + (mid->y - start->y) / fraction;
8273 fraction = fraction / 2;
8277 frames[count] = *mid;
8280 /* Slow out, stepping 1/2, then 1/4, ... */
8282 for (n = 0; n < factor; n++) {
8283 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8284 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8286 fraction = fraction * 2;
8291 /* Draw a piece on the screen without disturbing what's there */
8294 SelectGCMask(piece, clip, outline, mask)
8295 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8299 /* Bitmap for piece being moved. */
8300 if (appData.monoMode) {
8301 *mask = *pieceToSolid(piece);
8302 } else if (useImages) {
8304 *mask = xpmMask[piece];
8306 *mask = ximMaskPm[piece];
8309 *mask = *pieceToSolid(piece);
8312 /* GC for piece being moved. Square color doesn't matter, but
8313 since it gets modified we make a copy of the original. */
8315 if (appData.monoMode)
8320 if (appData.monoMode)
8325 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8327 /* Outline only used in mono mode and is not modified */
8329 *outline = bwPieceGC;
8331 *outline = wbPieceGC;
8335 OverlayPiece(piece, clip, outline, dest)
8336 ChessSquare piece; GC clip; GC outline; Drawable dest;
8341 /* Draw solid rectangle which will be clipped to shape of piece */
8342 XFillRectangle(xDisplay, dest, clip,
8343 0, 0, squareSize, squareSize);
8344 if (appData.monoMode)
8345 /* Also draw outline in contrasting color for black
8346 on black / white on white cases */
8347 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8348 0, 0, squareSize, squareSize, 0, 0, 1);
8350 /* Copy the piece */
8355 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8357 0, 0, squareSize, squareSize,
8362 /* Animate the movement of a single piece */
8365 BeginAnimation(anim, piece, startColor, start)
8373 /* The old buffer is initialised with the start square (empty) */
8374 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8375 anim->prevFrame = *start;
8377 /* The piece will be drawn using its own bitmap as a matte */
8378 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8379 XSetClipMask(xDisplay, anim->pieceGC, mask);
8383 AnimationFrame(anim, frame, piece)
8388 XRectangle updates[4];
8393 /* Save what we are about to draw into the new buffer */
8394 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8395 frame->x, frame->y, squareSize, squareSize,
8398 /* Erase bits of the previous frame */
8399 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8400 /* Where the new frame overlapped the previous,
8401 the contents in newBuf are wrong. */
8402 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8403 overlap.x, overlap.y,
8404 overlap.width, overlap.height,
8406 /* Repaint the areas in the old that don't overlap new */
8407 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8408 for (i = 0; i < count; i++)
8409 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8410 updates[i].x - anim->prevFrame.x,
8411 updates[i].y - anim->prevFrame.y,
8412 updates[i].width, updates[i].height,
8413 updates[i].x, updates[i].y);
8415 /* Easy when no overlap */
8416 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8417 0, 0, squareSize, squareSize,
8418 anim->prevFrame.x, anim->prevFrame.y);
8421 /* Save this frame for next time round */
8422 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8423 0, 0, squareSize, squareSize,
8425 anim->prevFrame = *frame;
8427 /* Draw piece over original screen contents, not current,
8428 and copy entire rect. Wipes out overlapping piece images. */
8429 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8430 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8431 0, 0, squareSize, squareSize,
8432 frame->x, frame->y);
8436 EndAnimation (anim, finish)
8440 XRectangle updates[4];
8445 /* The main code will redraw the final square, so we
8446 only need to erase the bits that don't overlap. */
8447 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8448 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8449 for (i = 0; i < count; i++)
8450 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8451 updates[i].x - anim->prevFrame.x,
8452 updates[i].y - anim->prevFrame.y,
8453 updates[i].width, updates[i].height,
8454 updates[i].x, updates[i].y);
8456 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8457 0, 0, squareSize, squareSize,
8458 anim->prevFrame.x, anim->prevFrame.y);
8463 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8465 ChessSquare piece; int startColor;
8466 XPoint * start; XPoint * finish;
8467 XPoint frames[]; int nFrames;
8471 BeginAnimation(anim, piece, startColor, start);
8472 for (n = 0; n < nFrames; n++) {
8473 AnimationFrame(anim, &(frames[n]), piece);
8474 FrameDelay(appData.animSpeed);
8476 EndAnimation(anim, finish);
8479 /* Main control logic for deciding what to animate and how */
8482 AnimateMove(board, fromX, fromY, toX, toY)
8491 XPoint start, finish, mid;
8492 XPoint frames[kFactor * 2 + 1];
8493 int nFrames, startColor, endColor;
8495 /* Are we animating? */
8496 if (!appData.animate || appData.blindfold)
8499 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8500 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8501 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8503 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8504 piece = board[fromY][fromX];
8505 if (piece >= EmptySquare) return;
8510 hop = (piece == WhiteKnight || piece == BlackKnight);
8513 if (appData.debugMode) {
8514 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8515 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8516 piece, fromX, fromY, toX, toY); }
8518 ScreenSquare(fromX, fromY, &start, &startColor);
8519 ScreenSquare(toX, toY, &finish, &endColor);
8522 /* Knight: make diagonal movement then straight */
8523 if (abs(toY - fromY) < abs(toX - fromX)) {
8524 mid.x = start.x + (finish.x - start.x) / 2;
8528 mid.y = start.y + (finish.y - start.y) / 2;
8531 mid.x = start.x + (finish.x - start.x) / 2;
8532 mid.y = start.y + (finish.y - start.y) / 2;
8535 /* Don't use as many frames for very short moves */
8536 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8537 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8539 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8540 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8542 /* Be sure end square is redrawn */
8543 damage[toY][toX] = True;
8547 DragPieceBegin(x, y)
8550 int boardX, boardY, color;
8553 /* Are we animating? */
8554 if (!appData.animateDragging || appData.blindfold)
8557 /* Figure out which square we start in and the
8558 mouse position relative to top left corner. */
8559 BoardSquare(x, y, &boardX, &boardY);
8560 player.startBoardX = boardX;
8561 player.startBoardY = boardY;
8562 ScreenSquare(boardX, boardY, &corner, &color);
8563 player.startSquare = corner;
8564 player.startColor = color;
8565 /* As soon as we start dragging, the piece will jump slightly to
8566 be centered over the mouse pointer. */
8567 player.mouseDelta.x = squareSize/2;
8568 player.mouseDelta.y = squareSize/2;
8569 /* Initialise animation */
8570 player.dragPiece = PieceForSquare(boardX, boardY);
8572 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8573 player.dragActive = True;
8574 BeginAnimation(&player, player.dragPiece, color, &corner);
8575 /* Mark this square as needing to be redrawn. Note that
8576 we don't remove the piece though, since logically (ie
8577 as seen by opponent) the move hasn't been made yet. */
8578 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8579 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8580 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8581 corner.x, corner.y, squareSize, squareSize,
8582 0, 0); // [HGM] zh: unstack in stead of grab
8583 damage[boardY][boardX] = True;
8585 player.dragActive = False;
8595 /* Are we animating? */
8596 if (!appData.animateDragging || appData.blindfold)
8600 if (! player.dragActive)
8602 /* Move piece, maintaining same relative position
8603 of mouse within square */
8604 corner.x = x - player.mouseDelta.x;
8605 corner.y = y - player.mouseDelta.y;
8606 AnimationFrame(&player, &corner, player.dragPiece);
8608 if (appData.highlightDragging) {
8610 BoardSquare(x, y, &boardX, &boardY);
8611 SetHighlights(fromX, fromY, boardX, boardY);
8620 int boardX, boardY, color;
8623 /* Are we animating? */
8624 if (!appData.animateDragging || appData.blindfold)
8628 if (! player.dragActive)
8630 /* Last frame in sequence is square piece is
8631 placed on, which may not match mouse exactly. */
8632 BoardSquare(x, y, &boardX, &boardY);
8633 ScreenSquare(boardX, boardY, &corner, &color);
8634 EndAnimation(&player, &corner);
8636 /* Be sure end square is redrawn */
8637 damage[boardY][boardX] = True;
8639 /* This prevents weird things happening with fast successive
8640 clicks which on my Sun at least can cause motion events
8641 without corresponding press/release. */
8642 player.dragActive = False;
8645 /* Handle expose event while piece being dragged */
8650 if (!player.dragActive || appData.blindfold)
8653 /* What we're doing: logically, the move hasn't been made yet,
8654 so the piece is still in it's original square. But visually
8655 it's being dragged around the board. So we erase the square
8656 that the piece is on and draw it at the last known drag point. */
8657 BlankSquare(player.startSquare.x, player.startSquare.y,
8658 player.startColor, EmptySquare, xBoardWindow);
8659 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8660 damage[player.startBoardY][player.startBoardX] = TRUE;
8663 #include <sys/ioctl.h>
8664 int get_term_width()
8666 int fd, default_width;
8669 default_width = 79; // this is FICS default anyway...
8671 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8673 if (!ioctl(fd, TIOCGSIZE, &win))
8674 default_width = win.ts_cols;
8675 #elif defined(TIOCGWINSZ)
8677 if (!ioctl(fd, TIOCGWINSZ, &win))
8678 default_width = win.ws_col;
8680 return default_width;
8683 void update_ics_width()
8685 static int old_width = 0;
8686 int new_width = get_term_width();
8688 if (old_width != new_width)
8689 ics_printf("set width %d\n", new_width);
8690 old_width = new_width;
8693 void NotifyFrontendLogin()