2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
58 #include <sys/types.h>
63 # if HAVE_SYS_SOCKET_H
64 # include <sys/socket.h>
65 # include <netinet/in.h>
67 # else /* not HAVE_SYS_SOCKET_H */
68 # if HAVE_LAN_SOCKET_H
69 # include <lan/socket.h>
71 # include <lan/netdb.h>
72 # else /* not HAVE_LAN_SOCKET_H */
73 # define OMIT_SOCKETS 1
74 # endif /* not HAVE_LAN_SOCKET_H */
75 # endif /* not HAVE_SYS_SOCKET_H */
76 #endif /* !OMIT_SOCKETS */
81 #else /* not STDC_HEADERS */
82 extern char *getenv();
85 # else /* not HAVE_STRING_H */
87 # endif /* not HAVE_STRING_H */
88 #endif /* not STDC_HEADERS */
91 # include <sys/fcntl.h>
92 #else /* not HAVE_SYS_FCNTL_H */
95 # endif /* HAVE_FCNTL_H */
96 #endif /* not HAVE_SYS_FCNTL_H */
98 #if HAVE_SYS_SYSTEMINFO_H
99 # include <sys/systeminfo.h>
100 #endif /* HAVE_SYS_SYSTEMINFO_H */
102 #if TIME_WITH_SYS_TIME
103 # include <sys/time.h>
107 # include <sys/time.h>
118 # include <sys/wait.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 # define HAVE_DIR_STRUCT
126 # define dirent direct
127 # define NAMLEN(dirent) (dirent)->d_namlen
129 # include <sys/ndir.h>
130 # define HAVE_DIR_STRUCT
133 # include <sys/dir.h>
134 # define HAVE_DIR_STRUCT
138 # define HAVE_DIR_STRUCT
142 #include <X11/Intrinsic.h>
143 #include <X11/StringDefs.h>
144 #include <X11/Shell.h>
145 #include <X11/cursorfont.h>
146 #include <X11/Xatom.h>
147 #include <X11/Xmu/Atoms.h>
149 #include <X11/Xaw3d/Dialog.h>
150 #include <X11/Xaw3d/Form.h>
151 #include <X11/Xaw3d/List.h>
152 #include <X11/Xaw3d/Label.h>
153 #include <X11/Xaw3d/SimpleMenu.h>
154 #include <X11/Xaw3d/SmeBSB.h>
155 #include <X11/Xaw3d/SmeLine.h>
156 #include <X11/Xaw3d/Box.h>
157 #include <X11/Xaw3d/MenuButton.h>
158 #include <X11/Xaw3d/Text.h>
159 #include <X11/Xaw3d/AsciiText.h>
161 #include <X11/Xaw/Dialog.h>
162 #include <X11/Xaw/Form.h>
163 #include <X11/Xaw/List.h>
164 #include <X11/Xaw/Label.h>
165 #include <X11/Xaw/SimpleMenu.h>
166 #include <X11/Xaw/SmeBSB.h>
167 #include <X11/Xaw/SmeLine.h>
168 #include <X11/Xaw/Box.h>
169 #include <X11/Xaw/MenuButton.h>
170 #include <X11/Xaw/Text.h>
171 #include <X11/Xaw/AsciiText.h>
174 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
179 #include "pixmaps/pixmaps.h"
180 #define IMAGE_EXT "xpm"
182 #define IMAGE_EXT "xim"
183 #include "bitmaps/bitmaps.h"
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
195 #include "xgamelist.h"
196 #include "xhistory.h"
197 #include "xedittags.h"
200 // must be moved to xengineoutput.h
202 void EngineOutputProc P((Widget w, XEvent *event,
203 String *prms, Cardinal *nprms));
204 void EvalGraphProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
233 int main P((int argc, char **argv));
234 RETSIGTYPE CmailSigHandler P((int sig));
235 RETSIGTYPE IntSigHandler P((int sig));
236 RETSIGTYPE TermSizeSigHandler P((int sig));
237 void CreateGCs P((void));
238 void CreateXIMPieces P((void));
239 void CreateXPMPieces P((void));
240 void CreatePieces P((void));
241 void CreatePieceMenus P((void));
242 Widget CreateMenuBar P((Menu *mb));
243 Widget CreateButtonBar P ((MenuItem *mi));
244 char *FindFont P((char *pattern, int targetPxlSize));
245 void PieceMenuPopup P((Widget w, XEvent *event,
246 String *params, Cardinal *num_params));
247 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
248 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
249 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
250 u_int wreq, u_int hreq));
251 void CreateGrid P((void));
252 int EventToSquare P((int x, int limit));
253 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
254 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
255 void HandleUserMove P((Widget w, XEvent *event,
256 String *prms, Cardinal *nprms));
257 void AnimateUserMove P((Widget w, XEvent * event,
258 String * params, Cardinal * nParams));
259 void WhiteClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void BlackClock P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void DrawPositionProc P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
267 void CommentPopUp P((char *title, char *label));
268 void CommentPopDown P((void));
269 void CommentCallback P((Widget w, XtPointer client_data,
270 XtPointer call_data));
271 void ICSInputBoxPopUp P((void));
272 void ICSInputBoxPopDown P((void));
273 void FileNamePopUp P((char *label, char *def,
274 FileProc proc, char *openMode));
275 void FileNamePopDown P((void));
276 void FileNameCallback P((Widget w, XtPointer client_data,
277 XtPointer call_data));
278 void FileNameAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionReplyAction P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionProc P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionPopDown P((void));
285 void PromotionPopDown P((void));
286 void PromotionCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void EditCommentPopDown P((void));
289 void EditCommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
292 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
294 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
296 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
298 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPositionProc P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
304 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
306 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
308 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
310 void PastePositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
315 void SavePositionProc P((Widget w, XEvent *event,
316 String *prms, Cardinal *nprms));
317 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
320 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
324 void MachineWhiteProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeModeProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void AnalyzeFileProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
332 void IcsClientProc P((Widget w, XEvent *event, String *prms,
334 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void EditPositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void EditCommentProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void IcsInputBoxProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void StopObservingProc P((Widget w, XEvent *event, String *prms,
356 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
358 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
365 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
367 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
370 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
372 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
374 void AutocommProc P((Widget w, XEvent *event, String *prms,
376 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AutobsProc P((Widget w, XEvent *event, String *prms,
380 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
385 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
388 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
390 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
392 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
396 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
398 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
400 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
402 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
404 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
408 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
410 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
412 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
414 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void DisplayMove P((int moveNumber));
426 void DisplayTitle P((char *title));
427 void ICSInitScript P((void));
428 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
429 void ErrorPopUp P((char *title, char *text, int modal));
430 void ErrorPopDown P((void));
431 static char *ExpandPathName P((char *path));
432 static void CreateAnimVars P((void));
433 static void DragPieceMove P((int x, int y));
434 static void DrawDragPiece P((void));
435 char *ModeToWidgetName P((GameMode mode));
436 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void ShufflePopDown P(());
444 void EnginePopDown P(());
445 void UciPopDown P(());
446 void TimeControlPopDown P(());
447 void NewVariantPopDown P(());
448 void SettingsPopDown P(());
449 void update_ics_width P(());
450 int get_term_width P(());
451 int CopyMemoProc P(());
453 * XBoard depends on Xt R4 or higher
455 int xtVersion = XtSpecificationRelease;
460 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
461 jailSquareColor, highlightSquareColor, premoveHighlightColor;
462 Pixel lowTimeWarningColor;
463 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
464 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
465 wjPieceGC, bjPieceGC, prelineGC, countGC;
466 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
467 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
468 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
469 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
470 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
471 ICSInputShell, fileNameShell, askQuestionShell;
472 Widget historyShell, evalGraphShell, gameListShell;
473 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
474 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
475 Font clockFontID, coordFontID, countFontID;
476 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
477 XtAppContext appContext;
479 char *oldICSInteractionTitle;
483 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
485 Position commentX = -1, commentY = -1;
486 Dimension commentW, commentH;
487 typedef unsigned int BoardSize;
489 Boolean chessProgram;
491 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
492 int squareSize, smallLayout = 0, tinyLayout = 0,
493 marginW, marginH, // [HGM] for run-time resizing
494 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
495 ICSInputBoxUp = False, askQuestionUp = False,
496 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
497 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
498 Pixel timerForegroundPixel, timerBackgroundPixel;
499 Pixel buttonForegroundPixel, buttonBackgroundPixel;
500 char *chessDir, *programName, *programVersion,
501 *gameCopyFilename, *gamePasteFilename;
502 Boolean alwaysOnTop = False;
503 Boolean saveSettingsOnExit;
504 char *settingsFileName;
505 char *icsTextMenuString;
507 char *firstChessProgramNames;
508 char *secondChessProgramNames;
510 WindowPlacement wpMain;
511 WindowPlacement wpConsole;
512 WindowPlacement wpComment;
513 WindowPlacement wpMoveHistory;
514 WindowPlacement wpEvalGraph;
515 WindowPlacement wpEngineOutput;
516 WindowPlacement wpGameList;
517 WindowPlacement wpTags;
521 Pixmap pieceBitmap[2][(int)BlackPawn];
522 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
523 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
524 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
525 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
526 int useImages, useImageSqs;
527 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
528 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
529 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
530 XImage *ximLightSquare, *ximDarkSquare;
533 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
534 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
536 #define White(piece) ((int)(piece) < (int)BlackPawn)
538 /* Variables for doing smooth animation. This whole thing
539 would be much easier if the board was double-buffered,
540 but that would require a fairly major rewrite. */
545 GC blitGC, pieceGC, outlineGC;
546 XPoint startSquare, prevFrame, mouseDelta;
550 int startBoardX, startBoardY;
553 /* There can be two pieces being animated at once: a player
554 can begin dragging a piece before the remote opponent has moved. */
556 static AnimState game, player;
558 /* Bitmaps for use as masks when drawing XPM pieces.
559 Need one for each black and white piece. */
560 static Pixmap xpmMask[BlackKing + 1];
562 /* This magic number is the number of intermediate frames used
563 in each half of the animation. For short moves it's reduced
564 by 1. The total number of frames will be factor * 2 + 1. */
567 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
569 MenuItem fileMenu[] = {
570 {N_("New Game"), ResetProc},
571 {N_("New Shuffle Game ..."), ShuffleMenuProc},
572 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
573 {"----", NothingProc},
574 {N_("Load Game"), LoadGameProc},
575 {N_("Load Next Game"), LoadNextGameProc},
576 {N_("Load Previous Game"), LoadPrevGameProc},
577 {N_("Reload Same Game"), ReloadGameProc},
578 {N_("Save Game"), SaveGameProc},
579 {"----", NothingProc},
580 {N_("Copy Game"), CopyGameProc},
581 {N_("Paste Game"), PasteGameProc},
582 {"----", NothingProc},
583 {N_("Load Position"), LoadPositionProc},
584 {N_("Load Next Position"), LoadNextPositionProc},
585 {N_("Load Previous Position"), LoadPrevPositionProc},
586 {N_("Reload Same Position"), ReloadPositionProc},
587 {N_("Save Position"), SavePositionProc},
588 {"----", NothingProc},
589 {N_("Copy Position"), CopyPositionProc},
590 {N_("Paste Position"), PastePositionProc},
591 {"----", NothingProc},
592 {N_("Mail Move"), MailMoveProc},
593 {N_("Reload CMail Message"), ReloadCmailMsgProc},
594 {"----", NothingProc},
595 {N_("Exit"), QuitProc},
599 MenuItem modeMenu[] = {
600 {N_("Machine White"), MachineWhiteProc},
601 {N_("Machine Black"), MachineBlackProc},
602 {N_("Two Machines"), TwoMachinesProc},
603 {N_("Analysis Mode"), AnalyzeModeProc},
604 {N_("Analyze File"), AnalyzeFileProc },
605 {N_("ICS Client"), IcsClientProc},
606 {N_("Edit Game"), EditGameProc},
607 {N_("Edit Position"), EditPositionProc},
608 {N_("Training"), TrainingProc},
609 {"----", NothingProc},
610 {N_("Show Engine Output"), EngineOutputProc},
611 {N_("Show Evaluation Graph"), EvalGraphProc},
612 {N_("Show Game List"), ShowGameListProc},
613 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
614 {"----", NothingProc},
615 {N_("Edit Tags"), EditTagsProc},
616 {N_("Edit Comment"), EditCommentProc},
617 {N_("ICS Input Box"), IcsInputBoxProc},
618 {N_("Pause"), PauseProc},
622 MenuItem actionMenu[] = {
623 {N_("Accept"), AcceptProc},
624 {N_("Decline"), DeclineProc},
625 {N_("Rematch"), RematchProc},
626 {"----", NothingProc},
627 {N_("Call Flag"), CallFlagProc},
628 {N_("Draw"), DrawProc},
629 {N_("Adjourn"), AdjournProc},
630 {N_("Abort"), AbortProc},
631 {N_("Resign"), ResignProc},
632 {"----", NothingProc},
633 {N_("Stop Observing"), StopObservingProc},
634 {N_("Stop Examining"), StopExaminingProc},
635 {"----", NothingProc},
636 {N_("Adjudicate to White"), AdjuWhiteProc},
637 {N_("Adjudicate to Black"), AdjuBlackProc},
638 {N_("Adjudicate Draw"), AdjuDrawProc},
642 MenuItem stepMenu[] = {
643 {N_("Backward"), BackwardProc},
644 {N_("Forward"), ForwardProc},
645 {N_("Back to Start"), ToStartProc},
646 {N_("Forward to End"), ToEndProc},
647 {N_("Revert"), RevertProc},
648 {N_("Truncate Game"), TruncateGameProc},
649 {"----", NothingProc},
650 {N_("Move Now"), MoveNowProc},
651 {N_("Retract Move"), RetractMoveProc},
655 MenuItem optionsMenu[] = {
656 {N_("Flip View"), FlipViewProc},
657 {"----", NothingProc},
658 {N_("Adjudications ..."), EngineMenuProc},
659 {N_("General Settings ..."), UciMenuProc},
660 {N_("Engine #1 Settings ..."), FirstSettingsProc},
661 {N_("Engine #2 Settings ..."), SecondSettingsProc},
662 {N_("Time Control ..."), TimeControlProc},
663 {"----", NothingProc},
664 {N_("Always Queen"), AlwaysQueenProc},
665 {N_("Animate Dragging"), AnimateDraggingProc},
666 {N_("Animate Moving"), AnimateMovingProc},
667 {N_("Auto Comment"), AutocommProc},
668 {N_("Auto Flag"), AutoflagProc},
669 {N_("Auto Flip View"), AutoflipProc},
670 {N_("Auto Observe"), AutobsProc},
671 {N_("Auto Raise Board"), AutoraiseProc},
672 {N_("Auto Save"), AutosaveProc},
673 {N_("Blindfold"), BlindfoldProc},
674 {N_("Flash Moves"), FlashMovesProc},
675 {N_("Get Move List"), GetMoveListProc},
677 {N_("Highlight Dragging"), HighlightDraggingProc},
679 {N_("Highlight Last Move"), HighlightLastMoveProc},
680 {N_("Move Sound"), MoveSoundProc},
681 {N_("ICS Alarm"), IcsAlarmProc},
682 {N_("Old Save Style"), OldSaveStyleProc},
683 {N_("Periodic Updates"), PeriodicUpdatesProc},
684 {N_("Ponder Next Move"), PonderNextMoveProc},
685 {N_("Popup Exit Message"), PopupExitMessageProc},
686 {N_("Popup Move Errors"), PopupMoveErrorsProc},
687 {N_("Premove"), PremoveProc},
688 {N_("Quiet Play"), QuietPlayProc},
689 {N_("Show Coords"), ShowCoordsProc},
690 {N_("Hide Thinking"), HideThinkingProc},
691 {N_("Test Legality"), TestLegalityProc},
692 {"----", NothingProc},
693 {N_("Save Settings Now"), SaveSettingsProc},
694 {N_("Save Settings on Exit"), SaveOnExitProc},
698 MenuItem helpMenu[] = {
699 {N_("Info XBoard"), InfoProc},
700 {N_("Man XBoard"), ManProc},
701 {"----", NothingProc},
702 {N_("Hint"), HintProc},
703 {N_("Book"), BookProc},
704 {"----", NothingProc},
705 {N_("About XBoard"), AboutProc},
710 {N_("File"), fileMenu},
711 {N_("Mode"), modeMenu},
712 {N_("Action"), actionMenu},
713 {N_("Step"), stepMenu},
714 {N_("Options"), optionsMenu},
715 {N_("Help"), helpMenu},
719 #define PAUSE_BUTTON N_("P")
720 MenuItem buttonBar[] = {
723 {PAUSE_BUTTON, PauseProc},
729 #define PIECE_MENU_SIZE 18
730 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
731 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
732 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
733 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
734 N_("Empty square"), N_("Clear board") },
735 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
736 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
737 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
738 N_("Empty square"), N_("Clear board") }
740 /* must be in same order as PieceMenuStrings! */
741 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
742 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
743 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
744 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
745 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
746 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
747 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
748 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
749 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
752 #define DROP_MENU_SIZE 6
753 String dropMenuStrings[DROP_MENU_SIZE] = {
754 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
756 /* must be in same order as PieceMenuStrings! */
757 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
758 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
759 WhiteRook, WhiteQueen
767 DropMenuEnables dmEnables[] = {
785 { XtNborderWidth, 0 },
786 { XtNdefaultDistance, 0 },
790 { XtNborderWidth, 0 },
791 { XtNresizable, (XtArgVal) True },
795 { XtNborderWidth, 0 },
801 { XtNjustify, (XtArgVal) XtJustifyRight },
802 { XtNlabel, (XtArgVal) "..." },
803 { XtNresizable, (XtArgVal) True },
804 { XtNresize, (XtArgVal) False }
807 Arg messageArgs[] = {
808 { XtNjustify, (XtArgVal) XtJustifyLeft },
809 { XtNlabel, (XtArgVal) "..." },
810 { XtNresizable, (XtArgVal) True },
811 { XtNresize, (XtArgVal) False }
815 { XtNborderWidth, 0 },
816 { XtNjustify, (XtArgVal) XtJustifyLeft }
819 XtResource clientResources[] = {
820 { "flashCount", "flashCount", XtRInt, sizeof(int),
821 XtOffset(AppDataPtr, flashCount), XtRImmediate,
822 (XtPointer) FLASH_COUNT },
825 XrmOptionDescRec shellOptions[] = {
826 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
827 { "-flash", "flashCount", XrmoptionNoArg, "3" },
828 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
831 XtActionsRec boardActions[] = {
832 { "DrawPosition", DrawPositionProc },
833 { "HandleUserMove", HandleUserMove },
834 { "AnimateUserMove", AnimateUserMove },
835 { "FileNameAction", FileNameAction },
836 { "AskQuestionProc", AskQuestionProc },
837 { "AskQuestionReplyAction", AskQuestionReplyAction },
838 { "PieceMenuPopup", PieceMenuPopup },
839 { "WhiteClock", WhiteClock },
840 { "BlackClock", BlackClock },
841 { "Iconify", Iconify },
842 { "ResetProc", ResetProc },
843 { "LoadGameProc", LoadGameProc },
844 { "LoadNextGameProc", LoadNextGameProc },
845 { "LoadPrevGameProc", LoadPrevGameProc },
846 { "LoadSelectedProc", LoadSelectedProc },
847 { "ReloadGameProc", ReloadGameProc },
848 { "LoadPositionProc", LoadPositionProc },
849 { "LoadNextPositionProc", LoadNextPositionProc },
850 { "LoadPrevPositionProc", LoadPrevPositionProc },
851 { "ReloadPositionProc", ReloadPositionProc },
852 { "CopyPositionProc", CopyPositionProc },
853 { "PastePositionProc", PastePositionProc },
854 { "CopyGameProc", CopyGameProc },
855 { "PasteGameProc", PasteGameProc },
856 { "SaveGameProc", SaveGameProc },
857 { "SavePositionProc", SavePositionProc },
858 { "MailMoveProc", MailMoveProc },
859 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
860 { "QuitProc", QuitProc },
861 { "MachineWhiteProc", MachineWhiteProc },
862 { "MachineBlackProc", MachineBlackProc },
863 { "AnalysisModeProc", AnalyzeModeProc },
864 { "AnalyzeFileProc", AnalyzeFileProc },
865 { "TwoMachinesProc", TwoMachinesProc },
866 { "IcsClientProc", IcsClientProc },
867 { "EditGameProc", EditGameProc },
868 { "EditPositionProc", EditPositionProc },
869 { "TrainingProc", EditPositionProc },
870 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
871 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
872 { "ShowGameListProc", ShowGameListProc },
873 { "ShowMoveListProc", HistoryShowProc},
874 { "EditTagsProc", EditCommentProc },
875 { "EditCommentProc", EditCommentProc },
876 { "IcsAlarmProc", IcsAlarmProc },
877 { "IcsInputBoxProc", IcsInputBoxProc },
878 { "PauseProc", PauseProc },
879 { "AcceptProc", AcceptProc },
880 { "DeclineProc", DeclineProc },
881 { "RematchProc", RematchProc },
882 { "CallFlagProc", CallFlagProc },
883 { "DrawProc", DrawProc },
884 { "AdjournProc", AdjournProc },
885 { "AbortProc", AbortProc },
886 { "ResignProc", ResignProc },
887 { "AdjuWhiteProc", AdjuWhiteProc },
888 { "AdjuBlackProc", AdjuBlackProc },
889 { "AdjuDrawProc", AdjuDrawProc },
890 { "EnterKeyProc", EnterKeyProc },
891 { "StopObservingProc", StopObservingProc },
892 { "StopExaminingProc", StopExaminingProc },
893 { "BackwardProc", BackwardProc },
894 { "ForwardProc", ForwardProc },
895 { "ToStartProc", ToStartProc },
896 { "ToEndProc", ToEndProc },
897 { "RevertProc", RevertProc },
898 { "TruncateGameProc", TruncateGameProc },
899 { "MoveNowProc", MoveNowProc },
900 { "RetractMoveProc", RetractMoveProc },
901 { "AlwaysQueenProc", AlwaysQueenProc },
902 { "AnimateDraggingProc", AnimateDraggingProc },
903 { "AnimateMovingProc", AnimateMovingProc },
904 { "AutoflagProc", AutoflagProc },
905 { "AutoflipProc", AutoflipProc },
906 { "AutobsProc", AutobsProc },
907 { "AutoraiseProc", AutoraiseProc },
908 { "AutosaveProc", AutosaveProc },
909 { "BlindfoldProc", BlindfoldProc },
910 { "FlashMovesProc", FlashMovesProc },
911 { "FlipViewProc", FlipViewProc },
912 { "GetMoveListProc", GetMoveListProc },
914 { "HighlightDraggingProc", HighlightDraggingProc },
916 { "HighlightLastMoveProc", HighlightLastMoveProc },
917 { "IcsAlarmProc", IcsAlarmProc },
918 { "MoveSoundProc", MoveSoundProc },
919 { "OldSaveStyleProc", OldSaveStyleProc },
920 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
921 { "PonderNextMoveProc", PonderNextMoveProc },
922 { "PopupExitMessageProc", PopupExitMessageProc },
923 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
924 { "PremoveProc", PremoveProc },
925 { "QuietPlayProc", QuietPlayProc },
926 { "ShowCoordsProc", ShowCoordsProc },
927 { "ShowThinkingProc", ShowThinkingProc },
928 { "HideThinkingProc", HideThinkingProc },
929 { "TestLegalityProc", TestLegalityProc },
930 { "SaveSettingsProc", SaveSettingsProc },
931 { "SaveOnExitProc", SaveOnExitProc },
932 { "InfoProc", InfoProc },
933 { "ManProc", ManProc },
934 { "HintProc", HintProc },
935 { "BookProc", BookProc },
936 { "AboutGameProc", AboutGameProc },
937 { "AboutProc", AboutProc },
938 { "DebugProc", DebugProc },
939 { "NothingProc", NothingProc },
940 { "CommentPopDown", (XtActionProc) CommentPopDown },
941 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
942 { "TagsPopDown", (XtActionProc) TagsPopDown },
943 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
944 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
945 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
946 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
947 { "GameListPopDown", (XtActionProc) GameListPopDown },
948 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
949 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
950 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
951 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
952 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
953 { "EnginePopDown", (XtActionProc) EnginePopDown },
954 { "UciPopDown", (XtActionProc) UciPopDown },
955 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
956 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
957 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
958 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
961 char globalTranslations[] =
962 ":<Key>R: ResignProc() \n \
963 :<Key>r: ResetProc() \n \
964 :<Key>g: LoadGameProc() \n \
965 :<Key>N: LoadNextGameProc() \n \
966 :<Key>P: LoadPrevGameProc() \n \
967 :<Key>Q: QuitProc() \n \
968 :<Key>F: ToEndProc() \n \
969 :<Key>f: ForwardProc() \n \
970 :<Key>B: ToStartProc() \n \
971 :<Key>b: BackwardProc() \n \
972 :<Key>p: PauseProc() \n \
973 :<Key>d: DrawProc() \n \
974 :<Key>t: CallFlagProc() \n \
975 :<Key>i: Iconify() \n \
976 :<Key>c: Iconify() \n \
977 :<Key>v: FlipViewProc() \n \
978 <KeyDown>Control_L: BackwardProc() \n \
979 <KeyUp>Control_L: ForwardProc() \n \
980 <KeyDown>Control_R: BackwardProc() \n \
981 <KeyUp>Control_R: ForwardProc() \n \
982 Shift<Key>1: AskQuestionProc(\"Direct command\",\
983 \"Send to chess program:\",,1) \n \
984 Shift<Key>2: AskQuestionProc(\"Direct command\",\
985 \"Send to second chess program:\",,2) \n";
987 char boardTranslations[] =
988 "<Btn1Down>: HandleUserMove() \n \
989 <Btn1Up>: HandleUserMove() \n \
990 <Btn1Motion>: AnimateUserMove() \n \
991 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
992 PieceMenuPopup(menuB) \n \
993 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
994 PieceMenuPopup(menuW) \n \
995 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
996 PieceMenuPopup(menuW) \n \
997 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
998 PieceMenuPopup(menuB) \n";
1000 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1001 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1003 char ICSInputTranslations[] =
1004 "<Key>Return: EnterKeyProc() \n";
1006 String xboardResources[] = {
1007 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1008 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1009 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1014 /* Max possible square size */
1015 #define MAXSQSIZE 256
1017 static int xpm_avail[MAXSQSIZE];
1019 #ifdef HAVE_DIR_STRUCT
1021 /* Extract piece size from filename */
1023 xpm_getsize(name, len, ext)
1034 if ((p=strchr(name, '.')) == NULL ||
1035 StrCaseCmp(p+1, ext) != 0)
1041 while (*p && isdigit(*p))
1048 /* Setup xpm_avail */
1050 xpm_getavail(dirname, ext)
1058 for (i=0; i<MAXSQSIZE; ++i)
1061 if (appData.debugMode)
1062 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1064 dir = opendir(dirname);
1067 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1068 programName, dirname);
1072 while ((ent=readdir(dir)) != NULL) {
1073 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1074 if (i > 0 && i < MAXSQSIZE)
1084 xpm_print_avail(fp, ext)
1090 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1091 for (i=1; i<MAXSQSIZE; ++i) {
1097 /* Return XPM piecesize closest to size */
1099 xpm_closest_to(dirname, size, ext)
1105 int sm_diff = MAXSQSIZE;
1109 xpm_getavail(dirname, ext);
1111 if (appData.debugMode)
1112 xpm_print_avail(stderr, ext);
1114 for (i=1; i<MAXSQSIZE; ++i) {
1117 diff = (diff<0) ? -diff : diff;
1118 if (diff < sm_diff) {
1126 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1132 #else /* !HAVE_DIR_STRUCT */
1133 /* If we are on a system without a DIR struct, we can't
1134 read the directory, so we can't collect a list of
1135 filenames, etc., so we can't do any size-fitting. */
1137 xpm_closest_to(dirname, size, ext)
1142 fprintf(stderr, _("\
1143 Warning: No DIR structure found on this system --\n\
1144 Unable to autosize for XPM/XIM pieces.\n\
1145 Please report this error to frankm@hiwaay.net.\n\
1146 Include system type & operating system in message.\n"));
1149 #endif /* HAVE_DIR_STRUCT */
1151 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1152 "magenta", "cyan", "white" };
1156 TextColors textColors[(int)NColorClasses];
1158 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1160 parse_color(str, which)
1164 char *p, buf[100], *d;
1167 if (strlen(str) > 99) /* watch bounds on buf */
1172 for (i=0; i<which; ++i) {
1179 /* Could be looking at something like:
1181 .. in which case we want to stop on a comma also */
1182 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1186 return -1; /* Use default for empty field */
1189 if (which == 2 || isdigit(*p))
1192 while (*p && isalpha(*p))
1197 for (i=0; i<8; ++i) {
1198 if (!StrCaseCmp(buf, cnames[i]))
1199 return which? (i+40) : (i+30);
1201 if (!StrCaseCmp(buf, "default")) return -1;
1203 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1208 parse_cpair(cc, str)
1212 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1213 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1218 /* bg and attr are optional */
1219 textColors[(int)cc].bg = parse_color(str, 1);
1220 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1221 textColors[(int)cc].attr = 0;
1227 /* Arrange to catch delete-window events */
1228 Atom wm_delete_window;
1230 CatchDeleteWindow(Widget w, String procname)
1233 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1234 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1235 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1242 XtSetArg(args[0], XtNiconic, False);
1243 XtSetValues(shellWidget, args, 1);
1245 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1248 //---------------------------------------------------------------------------------------------------------
1249 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1252 #define CW_USEDEFAULT (1<<31)
1253 #define ICS_TEXT_MENU_SIZE 90
1254 #define DEBUG_FILE "xboard.debug"
1255 #define SetCurrentDirectory chdir
1256 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1260 // these two must some day move to frontend.h, when they are implemented
1261 Boolean GameListIsUp();
1263 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1266 // front-end part of option handling
1268 // [HGM] This platform-dependent table provides the location for storing the color info
1269 extern char *crWhite, * crBlack;
1273 &appData.whitePieceColor,
1274 &appData.blackPieceColor,
1275 &appData.lightSquareColor,
1276 &appData.darkSquareColor,
1277 &appData.highlightSquareColor,
1278 &appData.premoveHighlightColor,
1291 ParseFont(char *name, int number)
1292 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1294 case 0: // CLOCK_FONT
1295 appData.clockFont = strdup(name);
1297 case 1: // MESSAGE_FONT
1298 appData.font = strdup(name);
1300 case 2: // COORD_FONT
1301 appData.coordFont = strdup(name);
1310 { // only 2 fonts currently
1311 appData.clockFont = CLOCK_FONT_NAME;
1312 appData.coordFont = COORD_FONT_NAME;
1313 appData.font = DEFAULT_FONT_NAME;
1318 { // no-op, until we identify the code for this already in XBoard and move it here
1322 ParseColor(int n, char *name)
1323 { // in XBoard, just copy the color-name string
1324 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1328 ParseTextAttribs(ColorClass cc, char *s)
1330 (&appData.colorShout)[cc] = strdup(s);
1334 ParseBoardSize(void *addr, char *name)
1336 appData.boardSize = strdup(name);
1341 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1345 SetCommPortDefaults()
1346 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1349 // [HGM] args: these three cases taken out to stay in front-end
1351 SaveFontArg(FILE *f, ArgDescriptor *ad)
1354 switch((int)ad->argLoc) {
1355 case 0: // CLOCK_FONT
1356 name = appData.clockFont;
1358 case 1: // MESSAGE_FONT
1359 name = appData.font;
1361 case 2: // COORD_FONT
1362 name = appData.coordFont;
1367 // Do not save fonts for now, as the saved font would be board-size specific
1368 // and not suitable for a re-start at another board size
1369 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1374 { // nothing to do, as the sounds are at all times represented by their text-string names already
1378 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1379 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1380 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1384 SaveColor(FILE *f, ArgDescriptor *ad)
1385 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1386 if(colorVariable[(int)ad->argLoc])
1387 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1391 SaveBoardSize(FILE *f, char *name, void *addr)
1392 { // wrapper to shield back-end from BoardSize & sizeInfo
1393 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1397 ParseCommPortSettings(char *s)
1398 { // no such option in XBoard (yet)
1401 extern Widget engineOutputShell;
1402 extern Widget tagsShell, editTagsShell;
1404 GetActualPlacement(Widget wg, WindowPlacement *wp)
1414 XtSetArg(args[i], XtNx, &x); i++;
1415 XtSetArg(args[i], XtNy, &y); i++;
1416 XtSetArg(args[i], XtNwidth, &w); i++;
1417 XtSetArg(args[i], XtNheight, &h); i++;
1418 XtGetValues(wg, args, i);
1427 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1428 // In XBoard this will have to wait until awareness of window parameters is implemented
1429 GetActualPlacement(shellWidget, &wpMain);
1430 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1431 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1432 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1433 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1434 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1435 else GetActualPlacement(editShell, &wpComment);
1436 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1437 else GetActualPlacement(editTagsShell, &wpTags);
1441 PrintCommPortSettings(FILE *f, char *name)
1442 { // This option does not exist in XBoard
1446 MySearchPath(char *installDir, char *name, char *fullname)
1447 { // just append installDir and name. Perhaps ExpandPath should be used here?
1448 name = ExpandPathName(name);
1449 if(name && name[0] == '/') strcpy(fullname, name); else {
1450 sprintf(fullname, "%s%c%s", installDir, '/', name);
1456 MyGetFullPathName(char *name, char *fullname)
1457 { // should use ExpandPath?
1458 name = ExpandPathName(name);
1459 strcpy(fullname, name);
1464 EnsureOnScreen(int *x, int *y, int minX, int minY)
1471 { // [HGM] args: allows testing if main window is realized from back-end
1472 return xBoardWindow != 0;
1476 PopUpStartupDialog()
1477 { // start menu not implemented in XBoard
1480 ConvertToLine(int argc, char **argv)
1482 static char line[128*1024], buf[1024];
1486 for(i=1; i<argc; i++) {
1487 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1488 && argv[i][0] != '{' )
1489 sprintf(buf, "{%s} ", argv[i]);
1490 else sprintf(buf, "%s ", argv[i]);
1493 line[strlen(line)-1] = NULLCHAR;
1497 //--------------------------------------------------------------------------------------------
1500 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1502 #define BoardSize int
1503 void InitDrawingSizes(BoardSize boardSize, int flags)
1504 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1505 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1507 XtGeometryResult gres;
1510 if(!formWidget) return;
1513 * Enable shell resizing.
1515 shellArgs[0].value = (XtArgVal) &w;
1516 shellArgs[1].value = (XtArgVal) &h;
1517 XtGetValues(shellWidget, shellArgs, 2);
1519 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1520 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1521 XtSetValues(shellWidget, &shellArgs[2], 4);
1523 XtSetArg(args[0], XtNdefaultDistance, &sep);
1524 XtGetValues(formWidget, args, 1);
1526 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1527 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1530 XtSetArg(args[0], XtNwidth, boardWidth);
1531 XtSetArg(args[1], XtNheight, boardHeight);
1532 XtSetValues(boardWidget, args, 2);
1534 timerWidth = (boardWidth - sep) / 2;
1535 XtSetArg(args[0], XtNwidth, timerWidth);
1536 XtSetValues(whiteTimerWidget, args, 1);
1537 XtSetValues(blackTimerWidget, args, 1);
1539 XawFormDoLayout(formWidget, False);
1541 if (appData.titleInWindow) {
1543 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1544 XtSetArg(args[i], XtNheight, &h); i++;
1545 XtGetValues(titleWidget, args, i);
1547 w = boardWidth - 2*bor;
1549 XtSetArg(args[0], XtNwidth, &w);
1550 XtGetValues(menuBarWidget, args, 1);
1551 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1554 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1555 if (gres != XtGeometryYes && appData.debugMode) {
1557 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1558 programName, gres, w, h, wr, hr);
1562 XawFormDoLayout(formWidget, True);
1565 * Inhibit shell resizing.
1567 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1568 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1569 shellArgs[4].value = shellArgs[2].value = w;
1570 shellArgs[5].value = shellArgs[3].value = h;
1571 XtSetValues(shellWidget, &shellArgs[0], 6);
1573 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1576 for(i=0; i<4; i++) {
1578 for(p=0; p<=(int)WhiteKing; p++)
1579 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1580 if(gameInfo.variant == VariantShogi) {
1581 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1582 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1583 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1584 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1585 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1588 if(gameInfo.variant == VariantGothic) {
1589 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1593 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1594 for(p=0; p<=(int)WhiteKing; p++)
1595 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1596 if(gameInfo.variant == VariantShogi) {
1597 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1598 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1599 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1600 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1601 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1604 if(gameInfo.variant == VariantGothic) {
1605 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1611 for(i=0; i<2; i++) {
1613 for(p=0; p<=(int)WhiteKing; p++)
1614 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1615 if(gameInfo.variant == VariantShogi) {
1616 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1617 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1618 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1619 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1620 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1623 if(gameInfo.variant == VariantGothic) {
1624 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1635 void EscapeExpand(char *p, char *q)
1636 { // [HGM] initstring: routine to shape up string arguments
1637 while(*p++ = *q++) if(p[-1] == '\\')
1639 case 'n': p[-1] = '\n'; break;
1640 case 'r': p[-1] = '\r'; break;
1641 case 't': p[-1] = '\t'; break;
1642 case '\\': p[-1] = '\\'; break;
1643 case 0: *p = 0; return;
1644 default: p[-1] = q[-1]; break;
1653 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1654 XSetWindowAttributes window_attributes;
1656 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1657 XrmValue vFrom, vTo;
1658 XtGeometryResult gres;
1661 int forceMono = False;
1663 srandom(time(0)); // [HGM] book: make random truly random
1665 setbuf(stdout, NULL);
1666 setbuf(stderr, NULL);
1669 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1670 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1674 programName = strrchr(argv[0], '/');
1675 if (programName == NULL)
1676 programName = argv[0];
1681 XtSetLanguageProc(NULL, NULL, NULL);
1682 bindtextdomain(PACKAGE, LOCALEDIR);
1683 textdomain(PACKAGE);
1687 XtAppInitialize(&appContext, "XBoard", shellOptions,
1688 XtNumber(shellOptions),
1689 &argc, argv, xboardResources, NULL, 0);
1690 appData.boardSize = "";
1691 InitAppData(ConvertToLine(argc, argv));
1693 if (p == NULL) p = "/tmp";
1694 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1695 gameCopyFilename = (char*) malloc(i);
1696 gamePasteFilename = (char*) malloc(i);
1697 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1698 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1700 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1701 clientResources, XtNumber(clientResources),
1704 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1705 static char buf[MSG_SIZ];
1706 EscapeExpand(buf, appData.initString);
1707 appData.initString = strdup(buf);
1708 EscapeExpand(buf, appData.secondInitString);
1709 appData.secondInitString = strdup(buf);
1710 EscapeExpand(buf, appData.firstComputerString);
1711 appData.firstComputerString = strdup(buf);
1712 EscapeExpand(buf, appData.secondComputerString);
1713 appData.secondComputerString = strdup(buf);
1716 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1719 if (chdir(chessDir) != 0) {
1720 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1726 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1727 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1728 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1729 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1732 setbuf(debugFP, NULL);
1735 /* [HGM,HR] make sure board size is acceptable */
1736 if(appData.NrFiles > BOARD_FILES ||
1737 appData.NrRanks > BOARD_RANKS )
1738 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1741 /* This feature does not work; animation needs a rewrite */
1742 appData.highlightDragging = FALSE;
1746 xDisplay = XtDisplay(shellWidget);
1747 xScreen = DefaultScreen(xDisplay);
1748 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1750 gameInfo.variant = StringToVariant(appData.variant);
1751 InitPosition(FALSE);
1754 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1756 if (isdigit(appData.boardSize[0])) {
1757 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1758 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1759 &fontPxlSize, &smallLayout, &tinyLayout);
1761 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1762 programName, appData.boardSize);
1766 /* Find some defaults; use the nearest known size */
1767 SizeDefaults *szd, *nearest;
1768 int distance = 99999;
1769 nearest = szd = sizeDefaults;
1770 while (szd->name != NULL) {
1771 if (abs(szd->squareSize - squareSize) < distance) {
1773 distance = abs(szd->squareSize - squareSize);
1774 if (distance == 0) break;
1778 if (i < 2) lineGap = nearest->lineGap;
1779 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1780 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1781 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1782 if (i < 6) smallLayout = nearest->smallLayout;
1783 if (i < 7) tinyLayout = nearest->tinyLayout;
1786 SizeDefaults *szd = sizeDefaults;
1787 if (*appData.boardSize == NULLCHAR) {
1788 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1789 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1792 if (szd->name == NULL) szd--;
1793 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1795 while (szd->name != NULL &&
1796 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1797 if (szd->name == NULL) {
1798 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1799 programName, appData.boardSize);
1803 squareSize = szd->squareSize;
1804 lineGap = szd->lineGap;
1805 clockFontPxlSize = szd->clockFontPxlSize;
1806 coordFontPxlSize = szd->coordFontPxlSize;
1807 fontPxlSize = szd->fontPxlSize;
1808 smallLayout = szd->smallLayout;
1809 tinyLayout = szd->tinyLayout;
1812 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1813 if (strlen(appData.pixmapDirectory) > 0) {
1814 p = ExpandPathName(appData.pixmapDirectory);
1816 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1817 appData.pixmapDirectory);
1820 if (appData.debugMode) {
1821 fprintf(stderr, _("\
1822 XBoard square size (hint): %d\n\
1823 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1825 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1826 if (appData.debugMode) {
1827 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1831 /* [HR] height treated separately (hacked) */
1832 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1833 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1834 if (appData.showJail == 1) {
1835 /* Jail on top and bottom */
1836 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1837 XtSetArg(boardArgs[2], XtNheight,
1838 boardHeight + 2*(lineGap + squareSize));
1839 } else if (appData.showJail == 2) {
1841 XtSetArg(boardArgs[1], XtNwidth,
1842 boardWidth + 2*(lineGap + squareSize));
1843 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1846 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1847 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1851 * Determine what fonts to use.
1853 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1854 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1855 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1856 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1857 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1858 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1859 appData.font = FindFont(appData.font, fontPxlSize);
1860 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1861 countFontStruct = XQueryFont(xDisplay, countFontID);
1862 // appData.font = FindFont(appData.font, fontPxlSize);
1864 xdb = XtDatabase(xDisplay);
1865 XrmPutStringResource(&xdb, "*font", appData.font);
1868 * Detect if there are not enough colors available and adapt.
1870 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1871 appData.monoMode = True;
1874 if (!appData.monoMode) {
1875 vFrom.addr = (caddr_t) appData.lightSquareColor;
1876 vFrom.size = strlen(appData.lightSquareColor);
1877 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1878 if (vTo.addr == NULL) {
1879 appData.monoMode = True;
1882 lightSquareColor = *(Pixel *) vTo.addr;
1885 if (!appData.monoMode) {
1886 vFrom.addr = (caddr_t) appData.darkSquareColor;
1887 vFrom.size = strlen(appData.darkSquareColor);
1888 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1889 if (vTo.addr == NULL) {
1890 appData.monoMode = True;
1893 darkSquareColor = *(Pixel *) vTo.addr;
1896 if (!appData.monoMode) {
1897 vFrom.addr = (caddr_t) appData.whitePieceColor;
1898 vFrom.size = strlen(appData.whitePieceColor);
1899 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1900 if (vTo.addr == NULL) {
1901 appData.monoMode = True;
1904 whitePieceColor = *(Pixel *) vTo.addr;
1907 if (!appData.monoMode) {
1908 vFrom.addr = (caddr_t) appData.blackPieceColor;
1909 vFrom.size = strlen(appData.blackPieceColor);
1910 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1911 if (vTo.addr == NULL) {
1912 appData.monoMode = True;
1915 blackPieceColor = *(Pixel *) vTo.addr;
1919 if (!appData.monoMode) {
1920 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1921 vFrom.size = strlen(appData.highlightSquareColor);
1922 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1923 if (vTo.addr == NULL) {
1924 appData.monoMode = True;
1927 highlightSquareColor = *(Pixel *) vTo.addr;
1931 if (!appData.monoMode) {
1932 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1933 vFrom.size = strlen(appData.premoveHighlightColor);
1934 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1935 if (vTo.addr == NULL) {
1936 appData.monoMode = True;
1939 premoveHighlightColor = *(Pixel *) vTo.addr;
1944 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1947 if (appData.bitmapDirectory == NULL ||
1948 appData.bitmapDirectory[0] == NULLCHAR)
1949 appData.bitmapDirectory = DEF_BITMAP_DIR;
1952 if (appData.lowTimeWarning && !appData.monoMode) {
1953 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1954 vFrom.size = strlen(appData.lowTimeWarningColor);
1955 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1956 if (vTo.addr == NULL)
1957 appData.monoMode = True;
1959 lowTimeWarningColor = *(Pixel *) vTo.addr;
1962 if (appData.monoMode && appData.debugMode) {
1963 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1964 (unsigned long) XWhitePixel(xDisplay, xScreen),
1965 (unsigned long) XBlackPixel(xDisplay, xScreen));
1968 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1969 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1970 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1971 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1972 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1973 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1974 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1975 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1976 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1977 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1979 if (appData.colorize) {
1981 _("%s: can't parse color names; disabling colorization\n"),
1984 appData.colorize = FALSE;
1986 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1987 textColors[ColorNone].attr = 0;
1989 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1995 layoutName = "tinyLayout";
1996 } else if (smallLayout) {
1997 layoutName = "smallLayout";
1999 layoutName = "normalLayout";
2001 /* Outer layoutWidget is there only to provide a name for use in
2002 resources that depend on the layout style */
2004 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2005 layoutArgs, XtNumber(layoutArgs));
2007 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2008 formArgs, XtNumber(formArgs));
2009 XtSetArg(args[0], XtNdefaultDistance, &sep);
2010 XtGetValues(formWidget, args, 1);
2013 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2014 XtSetArg(args[0], XtNtop, XtChainTop);
2015 XtSetArg(args[1], XtNbottom, XtChainTop);
2016 XtSetArg(args[2], XtNright, XtChainLeft);
2017 XtSetValues(menuBarWidget, args, 3);
2019 widgetList[j++] = whiteTimerWidget =
2020 XtCreateWidget("whiteTime", labelWidgetClass,
2021 formWidget, timerArgs, XtNumber(timerArgs));
2022 XtSetArg(args[0], XtNfont, clockFontStruct);
2023 XtSetArg(args[1], XtNtop, XtChainTop);
2024 XtSetArg(args[2], XtNbottom, XtChainTop);
2025 XtSetValues(whiteTimerWidget, args, 3);
2027 widgetList[j++] = blackTimerWidget =
2028 XtCreateWidget("blackTime", labelWidgetClass,
2029 formWidget, timerArgs, XtNumber(timerArgs));
2030 XtSetArg(args[0], XtNfont, clockFontStruct);
2031 XtSetArg(args[1], XtNtop, XtChainTop);
2032 XtSetArg(args[2], XtNbottom, XtChainTop);
2033 XtSetValues(blackTimerWidget, args, 3);
2035 if (appData.titleInWindow) {
2036 widgetList[j++] = titleWidget =
2037 XtCreateWidget("title", labelWidgetClass, formWidget,
2038 titleArgs, XtNumber(titleArgs));
2039 XtSetArg(args[0], XtNtop, XtChainTop);
2040 XtSetArg(args[1], XtNbottom, XtChainTop);
2041 XtSetValues(titleWidget, args, 2);
2044 if (appData.showButtonBar) {
2045 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2046 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2047 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2048 XtSetArg(args[2], XtNtop, XtChainTop);
2049 XtSetArg(args[3], XtNbottom, XtChainTop);
2050 XtSetValues(buttonBarWidget, args, 4);
2053 widgetList[j++] = messageWidget =
2054 XtCreateWidget("message", labelWidgetClass, formWidget,
2055 messageArgs, XtNumber(messageArgs));
2056 XtSetArg(args[0], XtNtop, XtChainTop);
2057 XtSetArg(args[1], XtNbottom, XtChainTop);
2058 XtSetValues(messageWidget, args, 2);
2060 widgetList[j++] = boardWidget =
2061 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2062 XtNumber(boardArgs));
2064 XtManageChildren(widgetList, j);
2066 timerWidth = (boardWidth - sep) / 2;
2067 XtSetArg(args[0], XtNwidth, timerWidth);
2068 XtSetValues(whiteTimerWidget, args, 1);
2069 XtSetValues(blackTimerWidget, args, 1);
2071 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2072 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2073 XtGetValues(whiteTimerWidget, args, 2);
2075 if (appData.showButtonBar) {
2076 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2077 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2078 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2082 * formWidget uses these constraints but they are stored
2086 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2087 XtSetValues(menuBarWidget, args, i);
2088 if (appData.titleInWindow) {
2091 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2092 XtSetValues(whiteTimerWidget, args, i);
2094 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2095 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2096 XtSetValues(blackTimerWidget, args, i);
2098 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2099 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2100 XtSetValues(titleWidget, args, i);
2102 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2103 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2104 XtSetValues(messageWidget, args, i);
2105 if (appData.showButtonBar) {
2107 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2108 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2109 XtSetValues(buttonBarWidget, args, i);
2113 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2114 XtSetValues(whiteTimerWidget, args, i);
2116 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2117 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2118 XtSetValues(blackTimerWidget, args, i);
2120 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2121 XtSetValues(titleWidget, args, i);
2123 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2124 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2125 XtSetValues(messageWidget, args, i);
2126 if (appData.showButtonBar) {
2128 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2129 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2130 XtSetValues(buttonBarWidget, args, i);
2135 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2136 XtSetValues(whiteTimerWidget, args, i);
2138 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2139 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2140 XtSetValues(blackTimerWidget, args, i);
2142 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2143 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2144 XtSetValues(messageWidget, args, i);
2145 if (appData.showButtonBar) {
2147 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2148 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2149 XtSetValues(buttonBarWidget, args, i);
2153 XtSetArg(args[0], XtNfromVert, messageWidget);
2154 XtSetArg(args[1], XtNtop, XtChainTop);
2155 XtSetArg(args[2], XtNbottom, XtChainBottom);
2156 XtSetArg(args[3], XtNleft, XtChainLeft);
2157 XtSetArg(args[4], XtNright, XtChainRight);
2158 XtSetValues(boardWidget, args, 5);
2160 XtRealizeWidget(shellWidget);
2163 XtSetArg(args[0], XtNx, wpMain.x);
2164 XtSetArg(args[1], XtNy, wpMain.y);
2165 XtSetValues(shellWidget, args, 2);
2169 * Correct the width of the message and title widgets.
2170 * It is not known why some systems need the extra fudge term.
2171 * The value "2" is probably larger than needed.
2173 XawFormDoLayout(formWidget, False);
2175 #define WIDTH_FUDGE 2
2177 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2178 XtSetArg(args[i], XtNheight, &h); i++;
2179 XtGetValues(messageWidget, args, i);
2180 if (appData.showButtonBar) {
2182 XtSetArg(args[i], XtNwidth, &w); i++;
2183 XtGetValues(buttonBarWidget, args, i);
2184 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2186 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2189 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2190 if (gres != XtGeometryYes && appData.debugMode) {
2191 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2192 programName, gres, w, h, wr, hr);
2195 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2196 /* The size used for the child widget in layout lags one resize behind
2197 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2199 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2200 if (gres != XtGeometryYes && appData.debugMode) {
2201 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2202 programName, gres, w, h, wr, hr);
2205 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2206 XtSetArg(args[1], XtNright, XtChainRight);
2207 XtSetValues(messageWidget, args, 2);
2209 if (appData.titleInWindow) {
2211 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2212 XtSetArg(args[i], XtNheight, &h); i++;
2213 XtGetValues(titleWidget, args, i);
2215 w = boardWidth - 2*bor;
2217 XtSetArg(args[0], XtNwidth, &w);
2218 XtGetValues(menuBarWidget, args, 1);
2219 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2222 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2223 if (gres != XtGeometryYes && appData.debugMode) {
2225 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2226 programName, gres, w, h, wr, hr);
2229 XawFormDoLayout(formWidget, True);
2231 xBoardWindow = XtWindow(boardWidget);
2233 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2234 // not need to go into InitDrawingSizes().
2238 * Create X checkmark bitmap and initialize option menu checks.
2240 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2241 checkmark_bits, checkmark_width, checkmark_height);
2242 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2243 if (appData.alwaysPromoteToQueen) {
2244 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2247 if (appData.animateDragging) {
2248 XtSetValues(XtNameToWidget(menuBarWidget,
2249 "menuOptions.Animate Dragging"),
2252 if (appData.animate) {
2253 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2256 if (appData.autoComment) {
2257 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2260 if (appData.autoCallFlag) {
2261 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2264 if (appData.autoFlipView) {
2265 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2268 if (appData.autoObserve) {
2269 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2272 if (appData.autoRaiseBoard) {
2273 XtSetValues(XtNameToWidget(menuBarWidget,
2274 "menuOptions.Auto Raise Board"), args, 1);
2276 if (appData.autoSaveGames) {
2277 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2280 if (appData.saveGameFile[0] != NULLCHAR) {
2281 /* Can't turn this off from menu */
2282 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2284 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2288 if (appData.blindfold) {
2289 XtSetValues(XtNameToWidget(menuBarWidget,
2290 "menuOptions.Blindfold"), args, 1);
2292 if (appData.flashCount > 0) {
2293 XtSetValues(XtNameToWidget(menuBarWidget,
2294 "menuOptions.Flash Moves"),
2297 if (appData.getMoveList) {
2298 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2302 if (appData.highlightDragging) {
2303 XtSetValues(XtNameToWidget(menuBarWidget,
2304 "menuOptions.Highlight Dragging"),
2308 if (appData.highlightLastMove) {
2309 XtSetValues(XtNameToWidget(menuBarWidget,
2310 "menuOptions.Highlight Last Move"),
2313 if (appData.icsAlarm) {
2314 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2317 if (appData.ringBellAfterMoves) {
2318 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2321 if (appData.oldSaveStyle) {
2322 XtSetValues(XtNameToWidget(menuBarWidget,
2323 "menuOptions.Old Save Style"), args, 1);
2325 if (appData.periodicUpdates) {
2326 XtSetValues(XtNameToWidget(menuBarWidget,
2327 "menuOptions.Periodic Updates"), args, 1);
2329 if (appData.ponderNextMove) {
2330 XtSetValues(XtNameToWidget(menuBarWidget,
2331 "menuOptions.Ponder Next Move"), args, 1);
2333 if (appData.popupExitMessage) {
2334 XtSetValues(XtNameToWidget(menuBarWidget,
2335 "menuOptions.Popup Exit Message"), args, 1);
2337 if (appData.popupMoveErrors) {
2338 XtSetValues(XtNameToWidget(menuBarWidget,
2339 "menuOptions.Popup Move Errors"), args, 1);
2341 if (appData.premove) {
2342 XtSetValues(XtNameToWidget(menuBarWidget,
2343 "menuOptions.Premove"), args, 1);
2345 if (appData.quietPlay) {
2346 XtSetValues(XtNameToWidget(menuBarWidget,
2347 "menuOptions.Quiet Play"), args, 1);
2349 if (appData.showCoords) {
2350 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2353 if (appData.hideThinkingFromHuman) {
2354 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2357 if (appData.testLegality) {
2358 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2361 if (saveSettingsOnExit) {
2362 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2369 ReadBitmap(&wIconPixmap, "icon_white.bm",
2370 icon_white_bits, icon_white_width, icon_white_height);
2371 ReadBitmap(&bIconPixmap, "icon_black.bm",
2372 icon_black_bits, icon_black_width, icon_black_height);
2373 iconPixmap = wIconPixmap;
2375 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2376 XtSetValues(shellWidget, args, i);
2379 * Create a cursor for the board widget.
2381 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2382 XChangeWindowAttributes(xDisplay, xBoardWindow,
2383 CWCursor, &window_attributes);
2386 * Inhibit shell resizing.
2388 shellArgs[0].value = (XtArgVal) &w;
2389 shellArgs[1].value = (XtArgVal) &h;
2390 XtGetValues(shellWidget, shellArgs, 2);
2391 shellArgs[4].value = shellArgs[2].value = w;
2392 shellArgs[5].value = shellArgs[3].value = h;
2393 XtSetValues(shellWidget, &shellArgs[2], 4);
2394 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2395 marginH = h - boardHeight;
2397 CatchDeleteWindow(shellWidget, "QuitProc");
2402 if (appData.bitmapDirectory[0] != NULLCHAR) {
2409 /* Create regular pieces */
2410 if (!useImages) CreatePieces();
2415 if (appData.animate || appData.animateDragging)
2418 XtAugmentTranslations(formWidget,
2419 XtParseTranslationTable(globalTranslations));
2420 XtAugmentTranslations(boardWidget,
2421 XtParseTranslationTable(boardTranslations));
2422 XtAugmentTranslations(whiteTimerWidget,
2423 XtParseTranslationTable(whiteTranslations));
2424 XtAugmentTranslations(blackTimerWidget,
2425 XtParseTranslationTable(blackTranslations));
2427 /* Why is the following needed on some versions of X instead
2428 * of a translation? */
2429 XtAddEventHandler(boardWidget, ExposureMask, False,
2430 (XtEventHandler) EventProc, NULL);
2433 /* [AS] Restore layout */
2434 if( wpMoveHistory.visible ) {
2438 if( wpEvalGraph.visible )
2443 if( wpEngineOutput.visible ) {
2444 EngineOutputPopUp();
2449 if (errorExitStatus == -1) {
2450 if (appData.icsActive) {
2451 /* We now wait until we see "login:" from the ICS before
2452 sending the logon script (problems with timestamp otherwise) */
2453 /*ICSInitScript();*/
2454 if (appData.icsInputBox) ICSInputBoxPopUp();
2458 signal(SIGWINCH, TermSizeSigHandler);
2460 signal(SIGINT, IntSigHandler);
2461 signal(SIGTERM, IntSigHandler);
2462 if (*appData.cmailGameName != NULLCHAR) {
2463 signal(SIGUSR1, CmailSigHandler);
2466 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2469 XtAppMainLoop(appContext);
2470 if (appData.debugMode) fclose(debugFP); // [DM] debug
2477 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2478 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2480 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2481 unlink(gameCopyFilename);
2482 unlink(gamePasteFilename);
2485 RETSIGTYPE TermSizeSigHandler(int sig)
2498 CmailSigHandler(sig)
2504 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2506 /* Activate call-back function CmailSigHandlerCallBack() */
2507 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2509 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2513 CmailSigHandlerCallBack(isr, closure, message, count, error)
2521 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2523 /**** end signal code ****/
2533 f = fopen(appData.icsLogon, "r");
2539 strcat(buf, appData.icsLogon);
2540 f = fopen(buf, "r");
2544 ProcessICSInitScript(f);
2551 EditCommentPopDown();
2566 if (!menuBarWidget) return;
2567 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2569 DisplayError("menuStep.Revert", 0);
2571 XtSetSensitive(w, !grey);
2576 SetMenuEnables(enab)
2580 if (!menuBarWidget) return;
2581 while (enab->name != NULL) {
2582 w = XtNameToWidget(menuBarWidget, enab->name);
2584 DisplayError(enab->name, 0);
2586 XtSetSensitive(w, enab->value);
2592 Enables icsEnables[] = {
2593 { "menuFile.Mail Move", False },
2594 { "menuFile.Reload CMail Message", False },
2595 { "menuMode.Machine Black", False },
2596 { "menuMode.Machine White", False },
2597 { "menuMode.Analysis Mode", False },
2598 { "menuMode.Analyze File", False },
2599 { "menuMode.Two Machines", False },
2601 { "menuHelp.Hint", False },
2602 { "menuHelp.Book", False },
2603 { "menuStep.Move Now", False },
2604 { "menuOptions.Periodic Updates", False },
2605 { "menuOptions.Hide Thinking", False },
2606 { "menuOptions.Ponder Next Move", False },
2611 Enables ncpEnables[] = {
2612 { "menuFile.Mail Move", False },
2613 { "menuFile.Reload CMail Message", False },
2614 { "menuMode.Machine White", False },
2615 { "menuMode.Machine Black", False },
2616 { "menuMode.Analysis Mode", False },
2617 { "menuMode.Analyze File", False },
2618 { "menuMode.Two Machines", False },
2619 { "menuMode.ICS Client", False },
2620 { "menuMode.ICS Input Box", False },
2621 { "Action", False },
2622 { "menuStep.Revert", False },
2623 { "menuStep.Move Now", False },
2624 { "menuStep.Retract Move", False },
2625 { "menuOptions.Auto Comment", False },
2626 { "menuOptions.Auto Flag", False },
2627 { "menuOptions.Auto Flip View", False },
2628 { "menuOptions.Auto Observe", False },
2629 { "menuOptions.Auto Raise Board", False },
2630 { "menuOptions.Get Move List", False },
2631 { "menuOptions.ICS Alarm", False },
2632 { "menuOptions.Move Sound", False },
2633 { "menuOptions.Quiet Play", False },
2634 { "menuOptions.Hide Thinking", False },
2635 { "menuOptions.Periodic Updates", False },
2636 { "menuOptions.Ponder Next Move", False },
2637 { "menuHelp.Hint", False },
2638 { "menuHelp.Book", False },
2642 Enables gnuEnables[] = {
2643 { "menuMode.ICS Client", False },
2644 { "menuMode.ICS Input Box", False },
2645 { "menuAction.Accept", False },
2646 { "menuAction.Decline", False },
2647 { "menuAction.Rematch", False },
2648 { "menuAction.Adjourn", False },
2649 { "menuAction.Stop Examining", False },
2650 { "menuAction.Stop Observing", False },
2651 { "menuStep.Revert", False },
2652 { "menuOptions.Auto Comment", False },
2653 { "menuOptions.Auto Observe", False },
2654 { "menuOptions.Auto Raise Board", False },
2655 { "menuOptions.Get Move List", False },
2656 { "menuOptions.Premove", False },
2657 { "menuOptions.Quiet Play", False },
2659 /* The next two options rely on SetCmailMode being called *after* */
2660 /* SetGNUMode so that when GNU is being used to give hints these */
2661 /* menu options are still available */
2663 { "menuFile.Mail Move", False },
2664 { "menuFile.Reload CMail Message", False },
2668 Enables cmailEnables[] = {
2670 { "menuAction.Call Flag", False },
2671 { "menuAction.Draw", True },
2672 { "menuAction.Adjourn", False },
2673 { "menuAction.Abort", False },
2674 { "menuAction.Stop Observing", False },
2675 { "menuAction.Stop Examining", False },
2676 { "menuFile.Mail Move", True },
2677 { "menuFile.Reload CMail Message", True },
2681 Enables trainingOnEnables[] = {
2682 { "menuMode.Edit Comment", False },
2683 { "menuMode.Pause", False },
2684 { "menuStep.Forward", False },
2685 { "menuStep.Backward", False },
2686 { "menuStep.Forward to End", False },
2687 { "menuStep.Back to Start", False },
2688 { "menuStep.Move Now", False },
2689 { "menuStep.Truncate Game", False },
2693 Enables trainingOffEnables[] = {
2694 { "menuMode.Edit Comment", True },
2695 { "menuMode.Pause", True },
2696 { "menuStep.Forward", True },
2697 { "menuStep.Backward", True },
2698 { "menuStep.Forward to End", True },
2699 { "menuStep.Back to Start", True },
2700 { "menuStep.Move Now", True },
2701 { "menuStep.Truncate Game", True },
2705 Enables machineThinkingEnables[] = {
2706 { "menuFile.Load Game", False },
2707 { "menuFile.Load Next Game", False },
2708 { "menuFile.Load Previous Game", False },
2709 { "menuFile.Reload Same Game", False },
2710 { "menuFile.Paste Game", False },
2711 { "menuFile.Load Position", False },
2712 { "menuFile.Load Next Position", False },
2713 { "menuFile.Load Previous Position", False },
2714 { "menuFile.Reload Same Position", False },
2715 { "menuFile.Paste Position", False },
2716 { "menuMode.Machine White", False },
2717 { "menuMode.Machine Black", False },
2718 { "menuMode.Two Machines", False },
2719 { "menuStep.Retract Move", False },
2723 Enables userThinkingEnables[] = {
2724 { "menuFile.Load Game", True },
2725 { "menuFile.Load Next Game", True },
2726 { "menuFile.Load Previous Game", True },
2727 { "menuFile.Reload Same Game", True },
2728 { "menuFile.Paste Game", True },
2729 { "menuFile.Load Position", True },
2730 { "menuFile.Load Next Position", True },
2731 { "menuFile.Load Previous Position", True },
2732 { "menuFile.Reload Same Position", True },
2733 { "menuFile.Paste Position", True },
2734 { "menuMode.Machine White", True },
2735 { "menuMode.Machine Black", True },
2736 { "menuMode.Two Machines", True },
2737 { "menuStep.Retract Move", True },
2743 SetMenuEnables(icsEnables);
2746 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2747 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2754 SetMenuEnables(ncpEnables);
2760 SetMenuEnables(gnuEnables);
2766 SetMenuEnables(cmailEnables);
2772 SetMenuEnables(trainingOnEnables);
2773 if (appData.showButtonBar) {
2774 XtSetSensitive(buttonBarWidget, False);
2780 SetTrainingModeOff()
2782 SetMenuEnables(trainingOffEnables);
2783 if (appData.showButtonBar) {
2784 XtSetSensitive(buttonBarWidget, True);
2789 SetUserThinkingEnables()
2791 if (appData.noChessProgram) return;
2792 SetMenuEnables(userThinkingEnables);
2796 SetMachineThinkingEnables()
2798 if (appData.noChessProgram) return;
2799 SetMenuEnables(machineThinkingEnables);
2801 case MachinePlaysBlack:
2802 case MachinePlaysWhite:
2803 case TwoMachinesPlay:
2804 XtSetSensitive(XtNameToWidget(menuBarWidget,
2805 ModeToWidgetName(gameMode)), True);
2812 #define Abs(n) ((n)<0 ? -(n) : (n))
2815 * Find a font that matches "pattern" that is as close as
2816 * possible to the targetPxlSize. Prefer fonts that are k
2817 * pixels smaller to fonts that are k pixels larger. The
2818 * pattern must be in the X Consortium standard format,
2819 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2820 * The return value should be freed with XtFree when no
2823 char *FindFont(pattern, targetPxlSize)
2827 char **fonts, *p, *best, *scalable, *scalableTail;
2828 int i, j, nfonts, minerr, err, pxlSize;
2831 char **missing_list;
2833 char *def_string, *base_fnt_lst, strInt[3];
2835 XFontStruct **fnt_list;
2837 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2838 sprintf(strInt, "%d", targetPxlSize);
2839 p = strstr(pattern, "--");
2840 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2841 strcat(base_fnt_lst, strInt);
2842 strcat(base_fnt_lst, strchr(p + 2, '-'));
2844 if ((fntSet = XCreateFontSet(xDisplay,
2848 &def_string)) == NULL) {
2850 fprintf(stderr, _("Unable to create font set.\n"));
2854 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2856 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2858 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2859 programName, pattern);
2867 for (i=0; i<nfonts; i++) {
2870 if (*p != '-') continue;
2872 if (*p == NULLCHAR) break;
2873 if (*p++ == '-') j++;
2875 if (j < 7) continue;
2878 scalable = fonts[i];
2881 err = pxlSize - targetPxlSize;
2882 if (Abs(err) < Abs(minerr) ||
2883 (minerr > 0 && err < 0 && -err == minerr)) {
2889 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2890 /* If the error is too big and there is a scalable font,
2891 use the scalable font. */
2892 int headlen = scalableTail - scalable;
2893 p = (char *) XtMalloc(strlen(scalable) + 10);
2894 while (isdigit(*scalableTail)) scalableTail++;
2895 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2897 p = (char *) XtMalloc(strlen(best) + 1);
2900 if (appData.debugMode) {
2901 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2902 pattern, targetPxlSize, p);
2905 if (missing_count > 0)
2906 XFreeStringList(missing_list);
2907 XFreeFontSet(xDisplay, fntSet);
2909 XFreeFontNames(fonts);
2916 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2917 | GCBackground | GCFunction | GCPlaneMask;
2918 XGCValues gc_values;
2921 gc_values.plane_mask = AllPlanes;
2922 gc_values.line_width = lineGap;
2923 gc_values.line_style = LineSolid;
2924 gc_values.function = GXcopy;
2926 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2927 gc_values.background = XBlackPixel(xDisplay, xScreen);
2928 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2930 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2931 gc_values.background = XWhitePixel(xDisplay, xScreen);
2932 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2933 XSetFont(xDisplay, coordGC, coordFontID);
2935 // [HGM] make font for holdings counts (white on black0
2936 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2937 gc_values.background = XBlackPixel(xDisplay, xScreen);
2938 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2939 XSetFont(xDisplay, countGC, countFontID);
2941 if (appData.monoMode) {
2942 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2943 gc_values.background = XWhitePixel(xDisplay, xScreen);
2944 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2946 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2947 gc_values.background = XBlackPixel(xDisplay, xScreen);
2948 lightSquareGC = wbPieceGC
2949 = XtGetGC(shellWidget, value_mask, &gc_values);
2951 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2952 gc_values.background = XWhitePixel(xDisplay, xScreen);
2953 darkSquareGC = bwPieceGC
2954 = XtGetGC(shellWidget, value_mask, &gc_values);
2956 if (DefaultDepth(xDisplay, xScreen) == 1) {
2957 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2958 gc_values.function = GXcopyInverted;
2959 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2960 gc_values.function = GXcopy;
2961 if (XBlackPixel(xDisplay, xScreen) == 1) {
2962 bwPieceGC = darkSquareGC;
2963 wbPieceGC = copyInvertedGC;
2965 bwPieceGC = copyInvertedGC;
2966 wbPieceGC = lightSquareGC;
2970 gc_values.foreground = highlightSquareColor;
2971 gc_values.background = highlightSquareColor;
2972 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2974 gc_values.foreground = premoveHighlightColor;
2975 gc_values.background = premoveHighlightColor;
2976 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2978 gc_values.foreground = lightSquareColor;
2979 gc_values.background = darkSquareColor;
2980 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2982 gc_values.foreground = darkSquareColor;
2983 gc_values.background = lightSquareColor;
2984 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2986 gc_values.foreground = jailSquareColor;
2987 gc_values.background = jailSquareColor;
2988 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2990 gc_values.foreground = whitePieceColor;
2991 gc_values.background = darkSquareColor;
2992 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2994 gc_values.foreground = whitePieceColor;
2995 gc_values.background = lightSquareColor;
2996 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2998 gc_values.foreground = whitePieceColor;
2999 gc_values.background = jailSquareColor;
3000 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3002 gc_values.foreground = blackPieceColor;
3003 gc_values.background = darkSquareColor;
3004 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3006 gc_values.foreground = blackPieceColor;
3007 gc_values.background = lightSquareColor;
3008 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3010 gc_values.foreground = blackPieceColor;
3011 gc_values.background = jailSquareColor;
3012 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3016 void loadXIM(xim, xmask, filename, dest, mask)
3029 fp = fopen(filename, "rb");
3031 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3038 for (y=0; y<h; ++y) {
3039 for (x=0; x<h; ++x) {
3044 XPutPixel(xim, x, y, blackPieceColor);
3046 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3049 XPutPixel(xim, x, y, darkSquareColor);
3051 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3054 XPutPixel(xim, x, y, whitePieceColor);
3056 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3059 XPutPixel(xim, x, y, lightSquareColor);
3061 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3067 /* create Pixmap of piece */
3068 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3070 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3073 /* create Pixmap of clipmask
3074 Note: We assume the white/black pieces have the same
3075 outline, so we make only 6 masks. This is okay
3076 since the XPM clipmask routines do the same. */
3078 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3080 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3083 /* now create the 1-bit version */
3084 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3087 values.foreground = 1;
3088 values.background = 0;
3090 /* Don't use XtGetGC, not read only */
3091 maskGC = XCreateGC(xDisplay, *mask,
3092 GCForeground | GCBackground, &values);
3093 XCopyPlane(xDisplay, temp, *mask, maskGC,
3094 0, 0, squareSize, squareSize, 0, 0, 1);
3095 XFreePixmap(xDisplay, temp);
3100 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3102 void CreateXIMPieces()
3107 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3112 /* The XSynchronize calls were copied from CreatePieces.
3113 Not sure if needed, but can't hurt */
3114 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3117 /* temp needed by loadXIM() */
3118 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3119 0, 0, ss, ss, AllPlanes, XYPixmap);
3121 if (strlen(appData.pixmapDirectory) == 0) {
3125 if (appData.monoMode) {
3126 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3130 fprintf(stderr, _("\nLoading XIMs...\n"));
3132 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3133 fprintf(stderr, "%d", piece+1);
3134 for (kind=0; kind<4; kind++) {
3135 fprintf(stderr, ".");
3136 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3137 ExpandPathName(appData.pixmapDirectory),
3138 piece <= (int) WhiteKing ? "" : "w",
3139 pieceBitmapNames[piece],
3141 ximPieceBitmap[kind][piece] =
3142 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3143 0, 0, ss, ss, AllPlanes, XYPixmap);
3144 if (appData.debugMode)
3145 fprintf(stderr, _("(File:%s:) "), buf);
3146 loadXIM(ximPieceBitmap[kind][piece],
3148 &(xpmPieceBitmap2[kind][piece]),
3149 &(ximMaskPm2[piece]));
3150 if(piece <= (int)WhiteKing)
3151 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3153 fprintf(stderr," ");
3155 /* Load light and dark squares */
3156 /* If the LSQ and DSQ pieces don't exist, we will
3157 draw them with solid squares. */
3158 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3159 if (access(buf, 0) != 0) {
3163 fprintf(stderr, _("light square "));
3165 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3166 0, 0, ss, ss, AllPlanes, XYPixmap);
3167 if (appData.debugMode)
3168 fprintf(stderr, _("(File:%s:) "), buf);
3170 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3171 fprintf(stderr, _("dark square "));
3172 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3173 ExpandPathName(appData.pixmapDirectory), ss);
3174 if (appData.debugMode)
3175 fprintf(stderr, _("(File:%s:) "), buf);
3177 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3178 0, 0, ss, ss, AllPlanes, XYPixmap);
3179 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3180 xpmJailSquare = xpmLightSquare;
3182 fprintf(stderr, _("Done.\n"));
3184 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3188 void CreateXPMPieces()
3192 u_int ss = squareSize;
3194 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3195 XpmColorSymbol symbols[4];
3197 /* The XSynchronize calls were copied from CreatePieces.
3198 Not sure if needed, but can't hurt */
3199 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3201 /* Setup translations so piece colors match square colors */
3202 symbols[0].name = "light_piece";
3203 symbols[0].value = appData.whitePieceColor;
3204 symbols[1].name = "dark_piece";
3205 symbols[1].value = appData.blackPieceColor;
3206 symbols[2].name = "light_square";
3207 symbols[2].value = appData.lightSquareColor;
3208 symbols[3].name = "dark_square";
3209 symbols[3].value = appData.darkSquareColor;
3211 attr.valuemask = XpmColorSymbols;
3212 attr.colorsymbols = symbols;
3213 attr.numsymbols = 4;
3215 if (appData.monoMode) {
3216 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3220 if (strlen(appData.pixmapDirectory) == 0) {
3221 XpmPieces* pieces = builtInXpms;
3224 while (pieces->size != squareSize && pieces->size) pieces++;
3225 if (!pieces->size) {
3226 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3229 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3230 for (kind=0; kind<4; kind++) {
3232 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3233 pieces->xpm[piece][kind],
3234 &(xpmPieceBitmap2[kind][piece]),
3235 NULL, &attr)) != 0) {
3236 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3240 if(piece <= (int) WhiteKing)
3241 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3245 xpmJailSquare = xpmLightSquare;
3249 fprintf(stderr, _("\nLoading XPMs...\n"));
3252 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3253 fprintf(stderr, "%d ", piece+1);
3254 for (kind=0; kind<4; kind++) {
3255 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3256 ExpandPathName(appData.pixmapDirectory),
3257 piece > (int) WhiteKing ? "w" : "",
3258 pieceBitmapNames[piece],
3260 if (appData.debugMode) {
3261 fprintf(stderr, _("(File:%s:) "), buf);
3263 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3264 &(xpmPieceBitmap2[kind][piece]),
3265 NULL, &attr)) != 0) {
3266 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3267 // [HGM] missing: read of unorthodox piece failed; substitute King.
3268 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3269 ExpandPathName(appData.pixmapDirectory),
3271 if (appData.debugMode) {
3272 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3274 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3275 &(xpmPieceBitmap2[kind][piece]),
3279 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3284 if(piece <= (int) WhiteKing)
3285 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3288 /* Load light and dark squares */
3289 /* If the LSQ and DSQ pieces don't exist, we will
3290 draw them with solid squares. */
3291 fprintf(stderr, _("light square "));
3292 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3293 if (access(buf, 0) != 0) {
3297 if (appData.debugMode)
3298 fprintf(stderr, _("(File:%s:) "), buf);
3300 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3301 &xpmLightSquare, NULL, &attr)) != 0) {
3302 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3305 fprintf(stderr, _("dark square "));
3306 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3307 ExpandPathName(appData.pixmapDirectory), ss);
3308 if (appData.debugMode) {
3309 fprintf(stderr, _("(File:%s:) "), buf);
3311 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3312 &xpmDarkSquare, NULL, &attr)) != 0) {
3313 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3317 xpmJailSquare = xpmLightSquare;
3318 fprintf(stderr, _("Done.\n"));
3320 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3323 #endif /* HAVE_LIBXPM */
3326 /* No built-in bitmaps */
3331 u_int ss = squareSize;
3333 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3336 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3337 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3338 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3339 pieceBitmapNames[piece],
3340 ss, kind == SOLID ? 's' : 'o');
3341 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3342 if(piece <= (int)WhiteKing)
3343 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3347 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3351 /* With built-in bitmaps */
3354 BuiltInBits* bib = builtInBits;
3357 u_int ss = squareSize;
3359 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3362 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3364 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3365 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3366 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3367 pieceBitmapNames[piece],
3368 ss, kind == SOLID ? 's' : 'o');
3369 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3370 bib->bits[kind][piece], ss, ss);
3371 if(piece <= (int)WhiteKing)
3372 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3376 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3381 void ReadBitmap(pm, name, bits, wreq, hreq)
3384 unsigned char bits[];
3390 char msg[MSG_SIZ], fullname[MSG_SIZ];
3392 if (*appData.bitmapDirectory != NULLCHAR) {
3393 strcpy(fullname, appData.bitmapDirectory);
3394 strcat(fullname, "/");
3395 strcat(fullname, name);
3396 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3397 &w, &h, pm, &x_hot, &y_hot);
3398 fprintf(stderr, "load %s\n", name);
3399 if (errcode != BitmapSuccess) {
3401 case BitmapOpenFailed:
3402 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3404 case BitmapFileInvalid:
3405 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3407 case BitmapNoMemory:
3408 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3412 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3416 fprintf(stderr, _("%s: %s...using built-in\n"),
3418 } else if (w != wreq || h != hreq) {
3420 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3421 programName, fullname, w, h, wreq, hreq);
3427 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3436 if (lineGap == 0) return;
3438 /* [HR] Split this into 2 loops for non-square boards. */
3440 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3441 gridSegments[i].x1 = 0;
3442 gridSegments[i].x2 =
3443 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3444 gridSegments[i].y1 = gridSegments[i].y2
3445 = lineGap / 2 + (i * (squareSize + lineGap));
3448 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3449 gridSegments[j + i].y1 = 0;
3450 gridSegments[j + i].y2 =
3451 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3452 gridSegments[j + i].x1 = gridSegments[j + i].x2
3453 = lineGap / 2 + (j * (squareSize + lineGap));
3457 static void MenuBarSelect(w, addr, index)
3462 XtActionProc proc = (XtActionProc) addr;
3464 (proc)(NULL, NULL, NULL, NULL);
3467 void CreateMenuBarPopup(parent, name, mb)
3477 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3480 XtSetArg(args[j], XtNleftMargin, 20); j++;
3481 XtSetArg(args[j], XtNrightMargin, 20); j++;
3483 while (mi->string != NULL) {
3484 if (strcmp(mi->string, "----") == 0) {
3485 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3488 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3489 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3491 XtAddCallback(entry, XtNcallback,
3492 (XtCallbackProc) MenuBarSelect,
3493 (caddr_t) mi->proc);
3499 Widget CreateMenuBar(mb)
3503 Widget anchor, menuBar;
3505 char menuName[MSG_SIZ];
3508 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3509 XtSetArg(args[j], XtNvSpace, 0); j++;
3510 XtSetArg(args[j], XtNborderWidth, 0); j++;
3511 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3512 formWidget, args, j);
3514 while (mb->name != NULL) {
3515 strcpy(menuName, "menu");
3516 strcat(menuName, mb->name);
3518 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3521 shortName[0] = _(mb->name)[0];
3522 shortName[1] = NULLCHAR;
3523 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3526 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3529 XtSetArg(args[j], XtNborderWidth, 0); j++;
3530 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3532 CreateMenuBarPopup(menuBar, menuName, mb);
3538 Widget CreateButtonBar(mi)
3542 Widget button, buttonBar;
3546 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3548 XtSetArg(args[j], XtNhSpace, 0); j++;
3550 XtSetArg(args[j], XtNborderWidth, 0); j++;
3551 XtSetArg(args[j], XtNvSpace, 0); j++;
3552 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3553 formWidget, args, j);
3555 while (mi->string != NULL) {
3558 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3559 XtSetArg(args[j], XtNborderWidth, 0); j++;
3561 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3562 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3563 buttonBar, args, j);
3564 XtAddCallback(button, XtNcallback,
3565 (XtCallbackProc) MenuBarSelect,
3566 (caddr_t) mi->proc);
3573 CreatePieceMenu(name, color)
3580 ChessSquare selection;
3582 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3583 boardWidget, args, 0);
3585 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3586 String item = pieceMenuStrings[color][i];
3588 if (strcmp(item, "----") == 0) {
3589 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3592 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3593 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3595 selection = pieceMenuTranslation[color][i];
3596 XtAddCallback(entry, XtNcallback,
3597 (XtCallbackProc) PieceMenuSelect,
3598 (caddr_t) selection);
3599 if (selection == WhitePawn || selection == BlackPawn) {
3600 XtSetArg(args[0], XtNpopupOnEntry, entry);
3601 XtSetValues(menu, args, 1);
3614 ChessSquare selection;
3616 whitePieceMenu = CreatePieceMenu("menuW", 0);
3617 blackPieceMenu = CreatePieceMenu("menuB", 1);
3619 XtRegisterGrabAction(PieceMenuPopup, True,
3620 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3621 GrabModeAsync, GrabModeAsync);
3623 XtSetArg(args[0], XtNlabel, _("Drop"));
3624 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3625 boardWidget, args, 1);
3626 for (i = 0; i < DROP_MENU_SIZE; i++) {
3627 String item = dropMenuStrings[i];
3629 if (strcmp(item, "----") == 0) {
3630 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3633 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3634 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3636 selection = dropMenuTranslation[i];
3637 XtAddCallback(entry, XtNcallback,
3638 (XtCallbackProc) DropMenuSelect,
3639 (caddr_t) selection);
3644 void SetupDropMenu()
3652 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3653 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3654 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3655 dmEnables[i].piece);
3656 XtSetSensitive(entry, p != NULL || !appData.testLegality
3657 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3658 && !appData.icsActive));
3660 while (p && *p++ == dmEnables[i].piece) count++;
3661 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3663 XtSetArg(args[j], XtNlabel, label); j++;
3664 XtSetValues(entry, args, j);
3668 void PieceMenuPopup(w, event, params, num_params)
3672 Cardinal *num_params;
3675 if (event->type != ButtonPress) return;
3676 if (errorUp) ErrorPopDown();
3680 whichMenu = params[0];
3682 case IcsPlayingWhite:
3683 case IcsPlayingBlack:
3685 case MachinePlaysWhite:
3686 case MachinePlaysBlack:
3687 if (appData.testLegality &&
3688 gameInfo.variant != VariantBughouse &&
3689 gameInfo.variant != VariantCrazyhouse) return;
3691 whichMenu = "menuD";
3697 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3698 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3699 pmFromX = pmFromY = -1;
3703 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3705 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3707 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3710 static void PieceMenuSelect(w, piece, junk)
3715 if (pmFromX < 0 || pmFromY < 0) return;
3716 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3719 static void DropMenuSelect(w, piece, junk)
3724 if (pmFromX < 0 || pmFromY < 0) return;
3725 DropMenuEvent(piece, pmFromX, pmFromY);
3728 void WhiteClock(w, event, prms, nprms)
3734 if (gameMode == EditPosition || gameMode == IcsExamining) {
3735 SetWhiteToPlayEvent();
3736 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3741 void BlackClock(w, event, prms, nprms)
3747 if (gameMode == EditPosition || gameMode == IcsExamining) {
3748 SetBlackToPlayEvent();
3749 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3756 * If the user selects on a border boundary, return -1; if off the board,
3757 * return -2. Otherwise map the event coordinate to the square.
3759 int EventToSquare(x, limit)
3767 if ((x % (squareSize + lineGap)) >= squareSize)
3769 x /= (squareSize + lineGap);
3775 static void do_flash_delay(msec)
3781 static void drawHighlight(file, rank, gc)
3787 if (lineGap == 0 || appData.blindfold) return;
3790 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3791 (squareSize + lineGap);
3792 y = lineGap/2 + rank * (squareSize + lineGap);
3794 x = lineGap/2 + file * (squareSize + lineGap);
3795 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3796 (squareSize + lineGap);
3799 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3800 squareSize+lineGap, squareSize+lineGap);
3803 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3804 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3807 SetHighlights(fromX, fromY, toX, toY)
3808 int fromX, fromY, toX, toY;
3810 if (hi1X != fromX || hi1Y != fromY) {
3811 if (hi1X >= 0 && hi1Y >= 0) {
3812 drawHighlight(hi1X, hi1Y, lineGC);
3814 if (fromX >= 0 && fromY >= 0) {
3815 drawHighlight(fromX, fromY, highlineGC);
3818 if (hi2X != toX || hi2Y != toY) {
3819 if (hi2X >= 0 && hi2Y >= 0) {
3820 drawHighlight(hi2X, hi2Y, lineGC);
3822 if (toX >= 0 && toY >= 0) {
3823 drawHighlight(toX, toY, highlineGC);
3835 SetHighlights(-1, -1, -1, -1);
3840 SetPremoveHighlights(fromX, fromY, toX, toY)
3841 int fromX, fromY, toX, toY;
3843 if (pm1X != fromX || pm1Y != fromY) {
3844 if (pm1X >= 0 && pm1Y >= 0) {
3845 drawHighlight(pm1X, pm1Y, lineGC);
3847 if (fromX >= 0 && fromY >= 0) {
3848 drawHighlight(fromX, fromY, prelineGC);
3851 if (pm2X != toX || pm2Y != toY) {
3852 if (pm2X >= 0 && pm2Y >= 0) {
3853 drawHighlight(pm2X, pm2Y, lineGC);
3855 if (toX >= 0 && toY >= 0) {
3856 drawHighlight(toX, toY, prelineGC);
3866 ClearPremoveHighlights()
3868 SetPremoveHighlights(-1, -1, -1, -1);
3871 static void BlankSquare(x, y, color, piece, dest)
3876 if (useImages && useImageSqs) {
3880 pm = xpmLightSquare;
3885 case 2: /* neutral */
3890 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3891 squareSize, squareSize, x, y);
3901 case 2: /* neutral */
3906 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3911 I split out the routines to draw a piece so that I could
3912 make a generic flash routine.
3914 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3916 int square_color, x, y;
3919 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3920 switch (square_color) {
3922 case 2: /* neutral */
3924 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3925 ? *pieceToOutline(piece)
3926 : *pieceToSolid(piece),
3927 dest, bwPieceGC, 0, 0,
3928 squareSize, squareSize, x, y);
3931 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3932 ? *pieceToSolid(piece)
3933 : *pieceToOutline(piece),
3934 dest, wbPieceGC, 0, 0,
3935 squareSize, squareSize, x, y);
3940 static void monoDrawPiece(piece, square_color, x, y, dest)
3942 int square_color, x, y;
3945 switch (square_color) {
3947 case 2: /* neutral */
3949 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3950 ? *pieceToOutline(piece)
3951 : *pieceToSolid(piece),
3952 dest, bwPieceGC, 0, 0,
3953 squareSize, squareSize, x, y, 1);
3956 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3957 ? *pieceToSolid(piece)
3958 : *pieceToOutline(piece),
3959 dest, wbPieceGC, 0, 0,
3960 squareSize, squareSize, x, y, 1);
3965 static void colorDrawPiece(piece, square_color, x, y, dest)
3967 int square_color, x, y;
3970 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3971 switch (square_color) {
3973 XCopyPlane(xDisplay, *pieceToSolid(piece),
3974 dest, (int) piece < (int) BlackPawn
3975 ? wlPieceGC : blPieceGC, 0, 0,
3976 squareSize, squareSize, x, y, 1);
3979 XCopyPlane(xDisplay, *pieceToSolid(piece),
3980 dest, (int) piece < (int) BlackPawn
3981 ? wdPieceGC : bdPieceGC, 0, 0,
3982 squareSize, squareSize, x, y, 1);
3984 case 2: /* neutral */
3986 XCopyPlane(xDisplay, *pieceToSolid(piece),
3987 dest, (int) piece < (int) BlackPawn
3988 ? wjPieceGC : bjPieceGC, 0, 0,
3989 squareSize, squareSize, x, y, 1);
3994 static void colorDrawPieceImage(piece, square_color, x, y, dest)
3996 int square_color, x, y;
4001 switch (square_color) {
4003 case 2: /* neutral */
4005 if ((int)piece < (int) BlackPawn) {
4013 if ((int)piece < (int) BlackPawn) {
4021 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4022 dest, wlPieceGC, 0, 0,
4023 squareSize, squareSize, x, y);
4026 typedef void (*DrawFunc)();
4028 DrawFunc ChooseDrawFunc()
4030 if (appData.monoMode) {
4031 if (DefaultDepth(xDisplay, xScreen) == 1) {
4032 return monoDrawPiece_1bit;
4034 return monoDrawPiece;
4038 return colorDrawPieceImage;
4040 return colorDrawPiece;
4044 /* [HR] determine square color depending on chess variant. */
4045 static int SquareColor(row, column)
4050 if (gameInfo.variant == VariantXiangqi) {
4051 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4053 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4055 } else if (row <= 4) {
4061 square_color = ((column + row) % 2) == 1;
4064 /* [hgm] holdings: next line makes all holdings squares light */
4065 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4067 return square_color;
4070 void DrawSquare(row, column, piece, do_flash)
4071 int row, column, do_flash;
4074 int square_color, x, y, direction, font_ascent, font_descent;
4077 XCharStruct overall;
4081 /* Calculate delay in milliseconds (2-delays per complete flash) */
4082 flash_delay = 500 / appData.flashRate;
4085 x = lineGap + ((BOARD_WIDTH-1)-column) *
4086 (squareSize + lineGap);
4087 y = lineGap + row * (squareSize + lineGap);
4089 x = lineGap + column * (squareSize + lineGap);
4090 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4091 (squareSize + lineGap);
4094 square_color = SquareColor(row, column);
4096 if ( // [HGM] holdings: blank out area between board and holdings
4097 column == BOARD_LEFT-1 || column == BOARD_RGHT
4098 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4099 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4100 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4102 // [HGM] print piece counts next to holdings
4103 string[1] = NULLCHAR;
4104 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4105 string[0] = '0' + piece;
4106 XTextExtents(countFontStruct, string, 1, &direction,
4107 &font_ascent, &font_descent, &overall);
4108 if (appData.monoMode) {
4109 XDrawImageString(xDisplay, xBoardWindow, countGC,
4110 x + squareSize - overall.width - 2,
4111 y + font_ascent + 1, string, 1);
4113 XDrawString(xDisplay, xBoardWindow, countGC,
4114 x + squareSize - overall.width - 2,
4115 y + font_ascent + 1, string, 1);
4118 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4119 string[0] = '0' + piece;
4120 XTextExtents(countFontStruct, string, 1, &direction,
4121 &font_ascent, &font_descent, &overall);
4122 if (appData.monoMode) {
4123 XDrawImageString(xDisplay, xBoardWindow, countGC,
4124 x + 2, y + font_ascent + 1, string, 1);
4126 XDrawString(xDisplay, xBoardWindow, countGC,
4127 x + 2, y + font_ascent + 1, string, 1);
4131 if (piece == EmptySquare || appData.blindfold) {
4132 BlankSquare(x, y, square_color, piece, xBoardWindow);
4134 drawfunc = ChooseDrawFunc();
4135 if (do_flash && appData.flashCount > 0) {
4136 for (i=0; i<appData.flashCount; ++i) {
4138 drawfunc(piece, square_color, x, y, xBoardWindow);
4139 XSync(xDisplay, False);
4140 do_flash_delay(flash_delay);
4142 BlankSquare(x, y, square_color, piece, xBoardWindow);
4143 XSync(xDisplay, False);
4144 do_flash_delay(flash_delay);
4147 drawfunc(piece, square_color, x, y, xBoardWindow);
4151 string[1] = NULLCHAR;
4152 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4153 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4154 string[0] = 'a' + column - BOARD_LEFT;
4155 XTextExtents(coordFontStruct, string, 1, &direction,
4156 &font_ascent, &font_descent, &overall);
4157 if (appData.monoMode) {
4158 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4159 x + squareSize - overall.width - 2,
4160 y + squareSize - font_descent - 1, string, 1);
4162 XDrawString(xDisplay, xBoardWindow, coordGC,
4163 x + squareSize - overall.width - 2,
4164 y + squareSize - font_descent - 1, string, 1);
4167 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4168 string[0] = ONE + row;
4169 XTextExtents(coordFontStruct, string, 1, &direction,
4170 &font_ascent, &font_descent, &overall);
4171 if (appData.monoMode) {
4172 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4173 x + 2, y + font_ascent + 1, string, 1);
4175 XDrawString(xDisplay, xBoardWindow, coordGC,
4176 x + 2, y + font_ascent + 1, string, 1);
4182 /* Why is this needed on some versions of X? */
4183 void EventProc(widget, unused, event)
4188 if (!XtIsRealized(widget))
4191 switch (event->type) {
4193 if (event->xexpose.count > 0) return; /* no clipping is done */
4194 XDrawPosition(widget, True, NULL);
4202 void DrawPosition(fullRedraw, board)
4203 /*Boolean*/int fullRedraw;
4206 XDrawPosition(boardWidget, fullRedraw, board);
4209 /* Returns 1 if there are "too many" differences between b1 and b2
4210 (i.e. more than 1 move was made) */
4211 static int too_many_diffs(b1, b2)
4217 for (i=0; i<BOARD_HEIGHT; ++i) {
4218 for (j=0; j<BOARD_WIDTH; ++j) {
4219 if (b1[i][j] != b2[i][j]) {
4220 if (++c > 4) /* Castling causes 4 diffs */
4229 /* Matrix describing castling maneuvers */
4230 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4231 static int castling_matrix[4][5] = {
4232 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4233 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4234 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4235 { 7, 7, 4, 5, 6 } /* 0-0, black */
4238 /* Checks whether castling occurred. If it did, *rrow and *rcol
4239 are set to the destination (row,col) of the rook that moved.
4241 Returns 1 if castling occurred, 0 if not.
4243 Note: Only handles a max of 1 castling move, so be sure
4244 to call too_many_diffs() first.
4246 static int check_castle_draw(newb, oldb, rrow, rcol)
4253 /* For each type of castling... */
4254 for (i=0; i<4; ++i) {
4255 r = castling_matrix[i];
4257 /* Check the 4 squares involved in the castling move */
4259 for (j=1; j<=4; ++j) {
4260 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4267 /* All 4 changed, so it must be a castling move */
4276 static int damage[BOARD_RANKS][BOARD_FILES];
4279 * event handler for redrawing the board
4281 void XDrawPosition(w, repaint, board)
4283 /*Boolean*/int repaint;
4287 static int lastFlipView = 0;
4288 static int lastBoardValid = 0;
4289 static Board lastBoard;
4293 if (board == NULL) {
4294 if (!lastBoardValid) return;
4297 if (!lastBoardValid || lastFlipView != flipView) {
4298 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4299 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4304 * It would be simpler to clear the window with XClearWindow()
4305 * but this causes a very distracting flicker.
4308 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4310 /* If too much changes (begin observing new game, etc.), don't
4312 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4314 /* Special check for castling so we don't flash both the king
4315 and the rook (just flash the king). */
4317 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4318 /* Draw rook with NO flashing. King will be drawn flashing later */
4319 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4320 lastBoard[rrow][rcol] = board[rrow][rcol];
4324 /* First pass -- Draw (newly) empty squares and repair damage.
4325 This prevents you from having a piece show up twice while it
4326 is flashing on its new square */
4327 for (i = 0; i < BOARD_HEIGHT; i++)
4328 for (j = 0; j < BOARD_WIDTH; j++)
4329 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4331 DrawSquare(i, j, board[i][j], 0);
4332 damage[i][j] = False;
4335 /* Second pass -- Draw piece(s) in new position and flash them */
4336 for (i = 0; i < BOARD_HEIGHT; i++)
4337 for (j = 0; j < BOARD_WIDTH; j++)
4338 if (board[i][j] != lastBoard[i][j]) {
4339 DrawSquare(i, j, board[i][j], do_flash);
4343 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4344 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4346 for (i = 0; i < BOARD_HEIGHT; i++)
4347 for (j = 0; j < BOARD_WIDTH; j++) {
4348 DrawSquare(i, j, board[i][j], 0);
4349 damage[i][j] = False;
4353 CopyBoard(lastBoard, board);
4355 lastFlipView = flipView;
4357 /* Draw highlights */
4358 if (pm1X >= 0 && pm1Y >= 0) {
4359 drawHighlight(pm1X, pm1Y, prelineGC);
4361 if (pm2X >= 0 && pm2Y >= 0) {
4362 drawHighlight(pm2X, pm2Y, prelineGC);
4364 if (hi1X >= 0 && hi1Y >= 0) {
4365 drawHighlight(hi1X, hi1Y, highlineGC);
4367 if (hi2X >= 0 && hi2Y >= 0) {
4368 drawHighlight(hi2X, hi2Y, highlineGC);
4371 /* If piece being dragged around board, must redraw that too */
4374 XSync(xDisplay, False);
4379 * event handler for redrawing the board
4381 void DrawPositionProc(w, event, prms, nprms)
4387 XDrawPosition(w, True, NULL);
4392 * event handler for parsing user moves
4394 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4395 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4396 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4397 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4398 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4399 // and at the end FinishMove() to perform the move after optional promotion popups.
4400 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4401 void HandleUserMove(w, event, prms, nprms)
4407 if (w != boardWidget || errorExitStatus != -1) return;
4410 if (event->type == ButtonPress) {
4411 XtPopdown(promotionShell);
4412 XtDestroyWidget(promotionShell);
4413 promotionUp = False;
4421 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4422 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4423 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4426 void AnimateUserMove (Widget w, XEvent * event,
4427 String * params, Cardinal * nParams)
4429 DragPieceMove(event->xmotion.x, event->xmotion.y);
4432 Widget CommentCreate(name, text, mutable, callback, lines)
4434 int /*Boolean*/ mutable;
4435 XtCallbackProc callback;
4439 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4444 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4445 XtGetValues(boardWidget, args, j);
4448 XtSetArg(args[j], XtNresizable, True); j++;
4451 XtCreatePopupShell(name, topLevelShellWidgetClass,
4452 shellWidget, args, j);
4455 XtCreatePopupShell(name, transientShellWidgetClass,
4456 shellWidget, args, j);
4459 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4460 layoutArgs, XtNumber(layoutArgs));
4462 XtCreateManagedWidget("form", formWidgetClass, layout,
4463 formArgs, XtNumber(formArgs));
4467 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4468 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4470 XtSetArg(args[j], XtNstring, text); j++;
4471 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4472 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4473 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4474 XtSetArg(args[j], XtNright, XtChainRight); j++;
4475 XtSetArg(args[j], XtNresizable, True); j++;
4476 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4477 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4478 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4479 XtSetArg(args[j], XtNautoFill, True); j++;
4480 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4482 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4486 XtSetArg(args[j], XtNfromVert, edit); j++;
4487 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4488 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4489 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4490 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4492 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4493 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4496 XtSetArg(args[j], XtNfromVert, edit); j++;
4497 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4498 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4499 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4500 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4501 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4503 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4504 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4507 XtSetArg(args[j], XtNfromVert, edit); j++;
4508 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4509 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4510 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4511 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4512 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4514 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4515 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4518 XtSetArg(args[j], XtNfromVert, edit); j++;
4519 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4520 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4521 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4522 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4524 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4525 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4528 XtSetArg(args[j], XtNfromVert, edit); j++;
4529 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4530 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4531 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4532 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4533 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4535 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4536 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4539 XtRealizeWidget(shell);
4541 if (commentX == -1) {
4544 Dimension pw_height;
4545 Dimension ew_height;
4548 XtSetArg(args[j], XtNheight, &ew_height); j++;
4549 XtGetValues(edit, args, j);
4552 XtSetArg(args[j], XtNheight, &pw_height); j++;
4553 XtGetValues(shell, args, j);
4554 commentH = pw_height + (lines - 1) * ew_height;
4555 commentW = bw_width - 16;
4557 XSync(xDisplay, False);
4559 /* This code seems to tickle an X bug if it is executed too soon
4560 after xboard starts up. The coordinates get transformed as if
4561 the main window was positioned at (0, 0).
4563 XtTranslateCoords(shellWidget,
4564 (bw_width - commentW) / 2, 0 - commentH / 2,
4565 &commentX, &commentY);
4567 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4568 RootWindowOfScreen(XtScreen(shellWidget)),
4569 (bw_width - commentW) / 2, 0 - commentH / 2,
4574 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4577 if(wpComment.width > 0) {
4578 commentX = wpComment.x;
4579 commentY = wpComment.y;
4580 commentW = wpComment.width;
4581 commentH = wpComment.height;
4585 XtSetArg(args[j], XtNheight, commentH); j++;
4586 XtSetArg(args[j], XtNwidth, commentW); j++;
4587 XtSetArg(args[j], XtNx, commentX); j++;
4588 XtSetArg(args[j], XtNy, commentY); j++;
4589 XtSetValues(shell, args, j);
4590 XtSetKeyboardFocus(shell, edit);
4595 /* Used for analysis window and ICS input window */
4596 Widget MiscCreate(name, text, mutable, callback, lines)
4598 int /*Boolean*/ mutable;
4599 XtCallbackProc callback;
4603 Widget shell, layout, form, edit;
4605 Dimension bw_width, pw_height, ew_height, w, h;
4611 XtSetArg(args[j], XtNresizable, True); j++;
4614 XtCreatePopupShell(name, topLevelShellWidgetClass,
4615 shellWidget, args, j);
4618 XtCreatePopupShell(name, transientShellWidgetClass,
4619 shellWidget, args, j);
4622 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4623 layoutArgs, XtNumber(layoutArgs));
4625 XtCreateManagedWidget("form", formWidgetClass, layout,
4626 formArgs, XtNumber(formArgs));
4630 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4631 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4633 XtSetArg(args[j], XtNstring, text); j++;
4634 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4635 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4636 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4637 XtSetArg(args[j], XtNright, XtChainRight); j++;
4638 XtSetArg(args[j], XtNresizable, True); j++;
4639 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4640 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4641 XtSetArg(args[j], XtNautoFill, True); j++;
4642 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4644 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4646 XtRealizeWidget(shell);
4649 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4650 XtGetValues(boardWidget, args, j);
4653 XtSetArg(args[j], XtNheight, &ew_height); j++;
4654 XtGetValues(edit, args, j);
4657 XtSetArg(args[j], XtNheight, &pw_height); j++;
4658 XtGetValues(shell, args, j);
4659 h = pw_height + (lines - 1) * ew_height;
4662 XSync(xDisplay, False);
4664 /* This code seems to tickle an X bug if it is executed too soon
4665 after xboard starts up. The coordinates get transformed as if
4666 the main window was positioned at (0, 0).
4668 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4670 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4671 RootWindowOfScreen(XtScreen(shellWidget)),
4672 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4676 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4679 XtSetArg(args[j], XtNheight, h); j++;
4680 XtSetArg(args[j], XtNwidth, w); j++;
4681 XtSetArg(args[j], XtNx, x); j++;
4682 XtSetArg(args[j], XtNy, y); j++;
4683 XtSetValues(shell, args, j);
4689 static int savedIndex; /* gross that this is global */
4691 void EditCommentPopUp(index, title, text)
4700 if (text == NULL) text = "";
4702 if (editShell == NULL) {
4704 CommentCreate(title, text, True, EditCommentCallback, 4);
4705 XtRealizeWidget(editShell);
4706 CatchDeleteWindow(editShell, "EditCommentPopDown");
4708 edit = XtNameToWidget(editShell, "*form.text");
4710 XtSetArg(args[j], XtNstring, text); j++;
4711 XtSetValues(edit, args, j);
4713 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4714 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4715 XtSetValues(editShell, args, j);
4718 XtPopup(editShell, XtGrabNone);
4722 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4723 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4727 void EditCommentCallback(w, client_data, call_data)
4729 XtPointer client_data, call_data;
4737 XtSetArg(args[j], XtNlabel, &name); j++;
4738 XtGetValues(w, args, j);
4740 if (strcmp(name, _("ok")) == 0) {
4741 edit = XtNameToWidget(editShell, "*form.text");
4743 XtSetArg(args[j], XtNstring, &val); j++;
4744 XtGetValues(edit, args, j);
4745 ReplaceComment(savedIndex, val);
4746 EditCommentPopDown();
4747 } else if (strcmp(name, _("cancel")) == 0) {
4748 EditCommentPopDown();
4749 } else if (strcmp(name, _("clear")) == 0) {
4750 edit = XtNameToWidget(editShell, "*form.text");
4751 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4752 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4756 void EditCommentPopDown()
4761 if (!editUp) return;
4763 XtSetArg(args[j], XtNx, &commentX); j++;
4764 XtSetArg(args[j], XtNy, &commentY); j++;
4765 XtSetArg(args[j], XtNheight, &commentH); j++;
4766 XtSetArg(args[j], XtNwidth, &commentW); j++;
4767 XtGetValues(editShell, args, j);
4768 XtPopdown(editShell);
4771 XtSetArg(args[j], XtNleftBitmap, None); j++;
4772 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4776 void ICSInputBoxPopUp()
4781 char *title = _("ICS Input");
4784 if (ICSInputShell == NULL) {
4785 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4786 tr = XtParseTranslationTable(ICSInputTranslations);
4787 edit = XtNameToWidget(ICSInputShell, "*form.text");
4788 XtOverrideTranslations(edit, tr);
4789 XtRealizeWidget(ICSInputShell);
4790 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4793 edit = XtNameToWidget(ICSInputShell, "*form.text");
4795 XtSetArg(args[j], XtNstring, ""); j++;
4796 XtSetValues(edit, args, j);
4798 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4799 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4800 XtSetValues(ICSInputShell, args, j);
4803 XtPopup(ICSInputShell, XtGrabNone);
4804 XtSetKeyboardFocus(ICSInputShell, edit);
4806 ICSInputBoxUp = True;
4808 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4809 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4813 void ICSInputSendText()
4820 edit = XtNameToWidget(ICSInputShell, "*form.text");
4822 XtSetArg(args[j], XtNstring, &val); j++;
4823 XtGetValues(edit, args, j);
4824 SendMultiLineToICS(val);
4825 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4826 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4829 void ICSInputBoxPopDown()
4834 if (!ICSInputBoxUp) return;
4836 XtPopdown(ICSInputShell);
4837 ICSInputBoxUp = False;
4839 XtSetArg(args[j], XtNleftBitmap, None); j++;
4840 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4844 void CommentPopUp(title, text)
4851 if (commentShell == NULL) {
4853 CommentCreate(title, text, False, CommentCallback, 4);
4854 XtRealizeWidget(commentShell);
4855 CatchDeleteWindow(commentShell, "CommentPopDown");
4857 edit = XtNameToWidget(commentShell, "*form.text");
4859 XtSetArg(args[j], XtNstring, text); j++;
4860 XtSetValues(edit, args, j);
4862 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4863 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4864 XtSetValues(commentShell, args, j);
4867 XtPopup(commentShell, XtGrabNone);
4868 XSync(xDisplay, False);
4873 void CommentCallback(w, client_data, call_data)
4875 XtPointer client_data, call_data;
4882 XtSetArg(args[j], XtNlabel, &name); j++;
4883 XtGetValues(w, args, j);
4885 if (strcmp(name, _("close")) == 0) {
4887 } else if (strcmp(name, _("edit")) == 0) {
4894 void CommentPopDown()
4899 if (!commentUp) return;
4901 XtSetArg(args[j], XtNx, &commentX); j++;
4902 XtSetArg(args[j], XtNy, &commentY); j++;
4903 XtSetArg(args[j], XtNwidth, &commentW); j++;
4904 XtSetArg(args[j], XtNheight, &commentH); j++;
4905 XtGetValues(commentShell, args, j);
4906 XtPopdown(commentShell);
4907 XSync(xDisplay, False);
4911 void FileNamePopUp(label, def, proc, openMode)
4918 Widget popup, layout, dialog, edit;
4924 fileProc = proc; /* I can't see a way not */
4925 fileOpenMode = openMode; /* to use globals here */
4928 XtSetArg(args[i], XtNresizable, True); i++;
4929 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4930 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4931 fileNameShell = popup =
4932 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4933 shellWidget, args, i);
4936 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4937 layoutArgs, XtNumber(layoutArgs));
4940 XtSetArg(args[i], XtNlabel, label); i++;
4941 XtSetArg(args[i], XtNvalue, def); i++;
4942 XtSetArg(args[i], XtNborderWidth, 0); i++;
4943 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4946 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4947 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4948 (XtPointer) dialog);
4950 XtRealizeWidget(popup);
4951 CatchDeleteWindow(popup, "FileNamePopDown");
4953 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4954 &x, &y, &win_x, &win_y, &mask);
4956 XtSetArg(args[0], XtNx, x - 10);
4957 XtSetArg(args[1], XtNy, y - 30);
4958 XtSetValues(popup, args, 2);
4960 XtPopup(popup, XtGrabExclusive);
4963 edit = XtNameToWidget(dialog, "*value");
4964 XtSetKeyboardFocus(popup, edit);
4967 void FileNamePopDown()
4969 if (!filenameUp) return;
4970 XtPopdown(fileNameShell);
4971 XtDestroyWidget(fileNameShell);
4976 void FileNameCallback(w, client_data, call_data)
4978 XtPointer client_data, call_data;
4983 XtSetArg(args[0], XtNlabel, &name);
4984 XtGetValues(w, args, 1);
4986 if (strcmp(name, _("cancel")) == 0) {
4991 FileNameAction(w, NULL, NULL, NULL);
4994 void FileNameAction(w, event, prms, nprms)
5006 name = XawDialogGetValueString(w = XtParent(w));
5008 if ((name != NULL) && (*name != NULLCHAR)) {
5010 XtPopdown(w = XtParent(XtParent(w)));
5014 p = strrchr(buf, ' ');
5021 fullname = ExpandPathName(buf);
5023 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5026 f = fopen(fullname, fileOpenMode);
5028 DisplayError(_("Failed to open file"), errno);
5030 (void) (*fileProc)(f, index, buf);
5037 XtPopdown(w = XtParent(XtParent(w)));
5043 void PromotionPopUp()
5046 Widget dialog, layout;
5048 Dimension bw_width, pw_width;
5052 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5053 XtGetValues(boardWidget, args, j);
5056 XtSetArg(args[j], XtNresizable, True); j++;
5057 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5059 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5060 shellWidget, args, j);
5062 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5063 layoutArgs, XtNumber(layoutArgs));
5066 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5067 XtSetArg(args[j], XtNborderWidth, 0); j++;
5068 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5071 if(gameInfo.variant != VariantShogi) {
5072 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5073 (XtPointer) dialog);
5074 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5075 (XtPointer) dialog);
5076 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5077 (XtPointer) dialog);
5078 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5079 (XtPointer) dialog);
5080 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5081 gameInfo.variant == VariantGiveaway) {
5082 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5083 (XtPointer) dialog);
5085 if(gameInfo.variant == VariantCapablanca ||
5086 gameInfo.variant == VariantGothic ||
5087 gameInfo.variant == VariantCapaRandom) {
5088 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5089 (XtPointer) dialog);
5090 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5091 (XtPointer) dialog);
5093 } else // [HGM] shogi
5095 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5096 (XtPointer) dialog);
5097 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5098 (XtPointer) dialog);
5100 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5101 (XtPointer) dialog);
5103 XtRealizeWidget(promotionShell);
5104 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5107 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5108 XtGetValues(promotionShell, args, j);
5110 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5111 lineGap + squareSize/3 +
5112 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5113 0 : 6*(squareSize + lineGap)), &x, &y);
5116 XtSetArg(args[j], XtNx, x); j++;
5117 XtSetArg(args[j], XtNy, y); j++;
5118 XtSetValues(promotionShell, args, j);
5120 XtPopup(promotionShell, XtGrabNone);
5125 void PromotionPopDown()
5127 if (!promotionUp) return;
5128 XtPopdown(promotionShell);
5129 XtDestroyWidget(promotionShell);
5130 promotionUp = False;
5133 void PromotionCallback(w, client_data, call_data)
5135 XtPointer client_data, call_data;
5141 XtSetArg(args[0], XtNlabel, &name);
5142 XtGetValues(w, args, 1);
5146 if (fromX == -1) return;
5148 if (strcmp(name, _("cancel")) == 0) {
5152 } else if (strcmp(name, _("Knight")) == 0) {
5154 } else if (strcmp(name, _("Promote")) == 0) {
5156 } else if (strcmp(name, _("Defer")) == 0) {
5159 promoChar = ToLower(name[0]);
5162 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5164 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5165 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5170 void ErrorCallback(w, client_data, call_data)
5172 XtPointer client_data, call_data;
5175 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5177 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5183 if (!errorUp) return;
5185 XtPopdown(errorShell);
5186 XtDestroyWidget(errorShell);
5187 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5190 void ErrorPopUp(title, label, modal)
5191 char *title, *label;
5195 Widget dialog, layout;
5199 Dimension bw_width, pw_width;
5200 Dimension pw_height;
5204 XtSetArg(args[i], XtNresizable, True); i++;
5205 XtSetArg(args[i], XtNtitle, title); i++;
5207 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5208 shellWidget, args, i);
5210 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5211 layoutArgs, XtNumber(layoutArgs));
5214 XtSetArg(args[i], XtNlabel, label); i++;
5215 XtSetArg(args[i], XtNborderWidth, 0); i++;
5216 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5219 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5221 XtRealizeWidget(errorShell);
5222 CatchDeleteWindow(errorShell, "ErrorPopDown");
5225 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5226 XtGetValues(boardWidget, args, i);
5228 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5229 XtSetArg(args[i], XtNheight, &pw_height); i++;
5230 XtGetValues(errorShell, args, i);
5233 /* This code seems to tickle an X bug if it is executed too soon
5234 after xboard starts up. The coordinates get transformed as if
5235 the main window was positioned at (0, 0).
5237 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5238 0 - pw_height + squareSize / 3, &x, &y);
5240 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5241 RootWindowOfScreen(XtScreen(boardWidget)),
5242 (bw_width - pw_width) / 2,
5243 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5247 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5250 XtSetArg(args[i], XtNx, x); i++;
5251 XtSetArg(args[i], XtNy, y); i++;
5252 XtSetValues(errorShell, args, i);
5255 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5258 /* Disable all user input other than deleting the window */
5259 static int frozen = 0;
5263 /* Grab by a widget that doesn't accept input */
5264 XtAddGrab(messageWidget, TRUE, FALSE);
5268 /* Undo a FreezeUI */
5271 if (!frozen) return;
5272 XtRemoveGrab(messageWidget);
5276 char *ModeToWidgetName(mode)
5280 case BeginningOfGame:
5281 if (appData.icsActive)
5282 return "menuMode.ICS Client";
5283 else if (appData.noChessProgram ||
5284 *appData.cmailGameName != NULLCHAR)
5285 return "menuMode.Edit Game";
5287 return "menuMode.Machine Black";
5288 case MachinePlaysBlack:
5289 return "menuMode.Machine Black";
5290 case MachinePlaysWhite:
5291 return "menuMode.Machine White";
5293 return "menuMode.Analysis Mode";
5295 return "menuMode.Analyze File";
5296 case TwoMachinesPlay:
5297 return "menuMode.Two Machines";
5299 return "menuMode.Edit Game";
5300 case PlayFromGameFile:
5301 return "menuFile.Load Game";
5303 return "menuMode.Edit Position";
5305 return "menuMode.Training";
5306 case IcsPlayingWhite:
5307 case IcsPlayingBlack:
5311 return "menuMode.ICS Client";
5318 void ModeHighlight()
5321 static int oldPausing = FALSE;
5322 static GameMode oldmode = (GameMode) -1;
5325 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5327 if (pausing != oldPausing) {
5328 oldPausing = pausing;
5330 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5332 XtSetArg(args[0], XtNleftBitmap, None);
5334 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5337 if (appData.showButtonBar) {
5338 /* Always toggle, don't set. Previous code messes up when
5339 invoked while the button is pressed, as releasing it
5340 toggles the state again. */
5343 XtSetArg(args[0], XtNbackground, &oldbg);
5344 XtSetArg(args[1], XtNforeground, &oldfg);
5345 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5347 XtSetArg(args[0], XtNbackground, oldfg);
5348 XtSetArg(args[1], XtNforeground, oldbg);
5350 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5354 wname = ModeToWidgetName(oldmode);
5355 if (wname != NULL) {
5356 XtSetArg(args[0], XtNleftBitmap, None);
5357 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5359 wname = ModeToWidgetName(gameMode);
5360 if (wname != NULL) {
5361 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5362 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5366 /* Maybe all the enables should be handled here, not just this one */
5367 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5368 gameMode == Training || gameMode == PlayFromGameFile);
5373 * Button/menu procedures
5375 void ResetProc(w, event, prms, nprms)
5384 int LoadGamePopUp(f, gameNumber, title)
5389 cmailMsgLoaded = FALSE;
5390 if (gameNumber == 0) {
5391 int error = GameListBuild(f);
5393 DisplayError(_("Cannot build game list"), error);
5394 } else if (!ListEmpty(&gameList) &&
5395 ((ListGame *) gameList.tailPred)->number > 1) {
5396 GameListPopUp(f, title);
5402 return LoadGame(f, gameNumber, title, FALSE);
5405 void LoadGameProc(w, event, prms, nprms)
5411 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5414 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5417 void LoadNextGameProc(w, event, prms, nprms)
5426 void LoadPrevGameProc(w, event, prms, nprms)
5435 void ReloadGameProc(w, event, prms, nprms)
5444 void LoadNextPositionProc(w, event, prms, nprms)
5453 void LoadPrevPositionProc(w, event, prms, nprms)
5462 void ReloadPositionProc(w, event, prms, nprms)
5471 void LoadPositionProc(w, event, prms, nprms)
5477 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5480 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5483 void SaveGameProc(w, event, prms, nprms)
5489 FileNamePopUp(_("Save game file name?"),
5490 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5494 void SavePositionProc(w, event, prms, nprms)
5500 FileNamePopUp(_("Save position file name?"),
5501 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5505 void ReloadCmailMsgProc(w, event, prms, nprms)
5511 ReloadCmailMsgEvent(FALSE);
5514 void MailMoveProc(w, event, prms, nprms)
5523 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5524 char *selected_fen_position=NULL;
5527 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5528 Atom *type_return, XtPointer *value_return,
5529 unsigned long *length_return, int *format_return)
5531 char *selection_tmp;
5533 if (!selected_fen_position) return False; /* should never happen */
5534 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5535 /* note: since no XtSelectionDoneProc was registered, Xt will
5536 * automatically call XtFree on the value returned. So have to
5537 * make a copy of it allocated with XtMalloc */
5538 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5539 strcpy(selection_tmp, selected_fen_position);
5541 *value_return=selection_tmp;
5542 *length_return=strlen(selection_tmp);
5543 *type_return=*target;
5544 *format_return = 8; /* bits per byte */
5546 } else if (*target == XA_TARGETS(xDisplay)) {
5547 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5548 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5549 targets_tmp[1] = XA_STRING;
5550 *value_return = targets_tmp;
5551 *type_return = XA_ATOM;
5553 *format_return = 8 * sizeof(Atom);
5554 if (*format_return > 32) {
5555 *length_return *= *format_return / 32;
5556 *format_return = 32;
5564 /* note: when called from menu all parameters are NULL, so no clue what the
5565 * Widget which was clicked on was, or what the click event was
5567 void CopyPositionProc(w, event, prms, nprms)
5574 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5575 * have a notion of a position that is selected but not copied.
5576 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5578 if(gameMode == EditPosition) EditPositionDone(TRUE);
5579 if (selected_fen_position) free(selected_fen_position);
5580 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5581 if (!selected_fen_position) return;
5582 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5584 SendPositionSelection,
5585 NULL/* lose_ownership_proc */ ,
5586 NULL/* transfer_done_proc */);
5587 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5589 SendPositionSelection,
5590 NULL/* lose_ownership_proc */ ,
5591 NULL/* transfer_done_proc */);
5594 /* function called when the data to Paste is ready */
5596 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5597 Atom *type, XtPointer value, unsigned long *len, int *format)
5600 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5601 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5602 EditPositionPasteFEN(fenstr);
5606 /* called when Paste Position button is pressed,
5607 * all parameters will be NULL */
5608 void PastePositionProc(w, event, prms, nprms)
5614 XtGetSelectionValue(menuBarWidget,
5615 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5616 /* (XtSelectionCallbackProc) */ PastePositionCB,
5617 NULL, /* client_data passed to PastePositionCB */
5619 /* better to use the time field from the event that triggered the
5620 * call to this function, but that isn't trivial to get
5628 SendGameSelection(Widget w, Atom *selection, Atom *target,
5629 Atom *type_return, XtPointer *value_return,
5630 unsigned long *length_return, int *format_return)
5632 char *selection_tmp;
5634 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5635 FILE* f = fopen(gameCopyFilename, "r");
5638 if (f == NULL) return False;
5642 selection_tmp = XtMalloc(len + 1);
5643 count = fread(selection_tmp, 1, len, f);
5645 XtFree(selection_tmp);
5648 selection_tmp[len] = NULLCHAR;
5649 *value_return = selection_tmp;
5650 *length_return = len;
5651 *type_return = *target;
5652 *format_return = 8; /* bits per byte */
5654 } else if (*target == XA_TARGETS(xDisplay)) {
5655 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5656 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5657 targets_tmp[1] = XA_STRING;
5658 *value_return = targets_tmp;
5659 *type_return = XA_ATOM;
5661 *format_return = 8 * sizeof(Atom);
5662 if (*format_return > 32) {
5663 *length_return *= *format_return / 32;
5664 *format_return = 32;
5672 /* note: when called from menu all parameters are NULL, so no clue what the
5673 * Widget which was clicked on was, or what the click event was
5675 void CopyGameProc(w, event, prms, nprms)
5683 ret = SaveGameToFile(gameCopyFilename, FALSE);
5687 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5688 * have a notion of a game that is selected but not copied.
5689 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5691 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5694 NULL/* lose_ownership_proc */ ,
5695 NULL/* transfer_done_proc */);
5696 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5699 NULL/* lose_ownership_proc */ ,
5700 NULL/* transfer_done_proc */);
5703 /* function called when the data to Paste is ready */
5705 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5706 Atom *type, XtPointer value, unsigned long *len, int *format)
5709 if (value == NULL || *len == 0) {
5710 return; /* nothing had been selected to copy */
5712 f = fopen(gamePasteFilename, "w");
5714 DisplayError(_("Can't open temp file"), errno);
5717 fwrite(value, 1, *len, f);
5720 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5723 /* called when Paste Game button is pressed,
5724 * all parameters will be NULL */
5725 void PasteGameProc(w, event, prms, nprms)
5731 XtGetSelectionValue(menuBarWidget,
5732 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5733 /* (XtSelectionCallbackProc) */ PasteGameCB,
5734 NULL, /* client_data passed to PasteGameCB */
5736 /* better to use the time field from the event that triggered the
5737 * call to this function, but that isn't trivial to get
5747 SaveGameProc(NULL, NULL, NULL, NULL);
5751 void QuitProc(w, event, prms, nprms)
5760 void PauseProc(w, event, prms, nprms)
5770 void MachineBlackProc(w, event, prms, nprms)
5776 MachineBlackEvent();
5779 void MachineWhiteProc(w, event, prms, nprms)
5785 MachineWhiteEvent();
5788 void AnalyzeModeProc(w, event, prms, nprms)
5796 if (!first.analysisSupport) {
5797 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5798 DisplayError(buf, 0);
5801 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5802 if (appData.icsActive) {
5803 if (gameMode != IcsObserving) {
5804 sprintf(buf,_("You are not observing a game"));
5805 DisplayError(buf, 0);
5807 if (appData.icsEngineAnalyze) {
5808 if (appData.debugMode)
5809 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5815 /* if enable, use want disable icsEngineAnalyze */
5816 if (appData.icsEngineAnalyze) {
5821 appData.icsEngineAnalyze = TRUE;
5822 if (appData.debugMode)
5823 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5825 if (!appData.showThinking)
5826 ShowThinkingProc(w,event,prms,nprms);
5831 void AnalyzeFileProc(w, event, prms, nprms)
5837 if (!first.analysisSupport) {
5839 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5840 DisplayError(buf, 0);
5845 if (!appData.showThinking)
5846 ShowThinkingProc(w,event,prms,nprms);
5849 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5850 AnalysisPeriodicEvent(1);
5853 void TwoMachinesProc(w, event, prms, nprms)
5862 void IcsClientProc(w, event, prms, nprms)
5871 void EditGameProc(w, event, prms, nprms)
5880 void EditPositionProc(w, event, prms, nprms)
5886 EditPositionEvent();
5889 void TrainingProc(w, event, prms, nprms)
5898 void EditCommentProc(w, event, prms, nprms)
5905 EditCommentPopDown();
5911 void IcsInputBoxProc(w, event, prms, nprms)
5917 if (ICSInputBoxUp) {
5918 ICSInputBoxPopDown();
5924 void AcceptProc(w, event, prms, nprms)
5933 void DeclineProc(w, event, prms, nprms)
5942 void RematchProc(w, event, prms, nprms)
5951 void CallFlagProc(w, event, prms, nprms)
5960 void DrawProc(w, event, prms, nprms)
5969 void AbortProc(w, event, prms, nprms)
5978 void AdjournProc(w, event, prms, nprms)
5987 void ResignProc(w, event, prms, nprms)
5996 void AdjuWhiteProc(w, event, prms, nprms)
6002 UserAdjudicationEvent(+1);
6005 void AdjuBlackProc(w, event, prms, nprms)
6011 UserAdjudicationEvent(-1);
6014 void AdjuDrawProc(w, event, prms, nprms)
6020 UserAdjudicationEvent(0);
6023 void EnterKeyProc(w, event, prms, nprms)
6029 if (ICSInputBoxUp == True)
6033 void StopObservingProc(w, event, prms, nprms)
6039 StopObservingEvent();
6042 void StopExaminingProc(w, event, prms, nprms)
6048 StopExaminingEvent();
6052 void ForwardProc(w, event, prms, nprms)
6062 void BackwardProc(w, event, prms, nprms)
6071 void ToStartProc(w, event, prms, nprms)
6080 void ToEndProc(w, event, prms, nprms)
6089 void RevertProc(w, event, prms, nprms)
6098 void TruncateGameProc(w, event, prms, nprms)
6104 TruncateGameEvent();
6106 void RetractMoveProc(w, event, prms, nprms)
6115 void MoveNowProc(w, event, prms, nprms)
6125 void AlwaysQueenProc(w, event, prms, nprms)
6133 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6135 if (appData.alwaysPromoteToQueen) {
6136 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6138 XtSetArg(args[0], XtNleftBitmap, None);
6140 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6144 void AnimateDraggingProc(w, event, prms, nprms)
6152 appData.animateDragging = !appData.animateDragging;
6154 if (appData.animateDragging) {
6155 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6158 XtSetArg(args[0], XtNleftBitmap, None);
6160 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6164 void AnimateMovingProc(w, event, prms, nprms)
6172 appData.animate = !appData.animate;
6174 if (appData.animate) {
6175 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6178 XtSetArg(args[0], XtNleftBitmap, None);
6180 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6184 void AutocommProc(w, event, prms, nprms)
6192 appData.autoComment = !appData.autoComment;
6194 if (appData.autoComment) {
6195 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6197 XtSetArg(args[0], XtNleftBitmap, None);
6199 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6204 void AutoflagProc(w, event, prms, nprms)
6212 appData.autoCallFlag = !appData.autoCallFlag;
6214 if (appData.autoCallFlag) {
6215 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6217 XtSetArg(args[0], XtNleftBitmap, None);
6219 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6223 void AutoflipProc(w, event, prms, nprms)
6231 appData.autoFlipView = !appData.autoFlipView;
6233 if (appData.autoFlipView) {
6234 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6236 XtSetArg(args[0], XtNleftBitmap, None);
6238 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6242 void AutobsProc(w, event, prms, nprms)
6250 appData.autoObserve = !appData.autoObserve;
6252 if (appData.autoObserve) {
6253 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6255 XtSetArg(args[0], XtNleftBitmap, None);
6257 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6261 void AutoraiseProc(w, event, prms, nprms)
6269 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6271 if (appData.autoRaiseBoard) {
6272 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6274 XtSetArg(args[0], XtNleftBitmap, None);
6276 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6280 void AutosaveProc(w, event, prms, nprms)
6288 appData.autoSaveGames = !appData.autoSaveGames;
6290 if (appData.autoSaveGames) {
6291 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6293 XtSetArg(args[0], XtNleftBitmap, None);
6295 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6299 void BlindfoldProc(w, event, prms, nprms)
6307 appData.blindfold = !appData.blindfold;
6309 if (appData.blindfold) {
6310 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6312 XtSetArg(args[0], XtNleftBitmap, None);
6314 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6317 DrawPosition(True, NULL);
6320 void TestLegalityProc(w, event, prms, nprms)
6328 appData.testLegality = !appData.testLegality;
6330 if (appData.testLegality) {
6331 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6333 XtSetArg(args[0], XtNleftBitmap, None);
6335 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6340 void FlashMovesProc(w, event, prms, nprms)
6348 if (appData.flashCount == 0) {
6349 appData.flashCount = 3;
6351 appData.flashCount = -appData.flashCount;
6354 if (appData.flashCount > 0) {
6355 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6357 XtSetArg(args[0], XtNleftBitmap, None);
6359 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6363 void FlipViewProc(w, event, prms, nprms)
6369 flipView = !flipView;
6370 DrawPosition(True, NULL);
6373 void GetMoveListProc(w, event, prms, nprms)
6381 appData.getMoveList = !appData.getMoveList;
6383 if (appData.getMoveList) {
6384 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6387 XtSetArg(args[0], XtNleftBitmap, None);
6389 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6394 void HighlightDraggingProc(w, event, prms, nprms)
6402 appData.highlightDragging = !appData.highlightDragging;
6404 if (appData.highlightDragging) {
6405 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6407 XtSetArg(args[0], XtNleftBitmap, None);
6409 XtSetValues(XtNameToWidget(menuBarWidget,
6410 "menuOptions.Highlight Dragging"), args, 1);
6414 void HighlightLastMoveProc(w, event, prms, nprms)
6422 appData.highlightLastMove = !appData.highlightLastMove;
6424 if (appData.highlightLastMove) {
6425 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6427 XtSetArg(args[0], XtNleftBitmap, None);
6429 XtSetValues(XtNameToWidget(menuBarWidget,
6430 "menuOptions.Highlight Last Move"), args, 1);
6433 void IcsAlarmProc(w, event, prms, nprms)
6441 appData.icsAlarm = !appData.icsAlarm;
6443 if (appData.icsAlarm) {
6444 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6446 XtSetArg(args[0], XtNleftBitmap, None);
6448 XtSetValues(XtNameToWidget(menuBarWidget,
6449 "menuOptions.ICS Alarm"), args, 1);
6452 void MoveSoundProc(w, event, prms, nprms)
6460 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6462 if (appData.ringBellAfterMoves) {
6463 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6465 XtSetArg(args[0], XtNleftBitmap, None);
6467 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6472 void OldSaveStyleProc(w, event, prms, nprms)
6480 appData.oldSaveStyle = !appData.oldSaveStyle;
6482 if (appData.oldSaveStyle) {
6483 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6485 XtSetArg(args[0], XtNleftBitmap, None);
6487 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6491 void PeriodicUpdatesProc(w, event, prms, nprms)
6499 PeriodicUpdatesEvent(!appData.periodicUpdates);
6501 if (appData.periodicUpdates) {
6502 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6504 XtSetArg(args[0], XtNleftBitmap, None);
6506 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6510 void PonderNextMoveProc(w, event, prms, nprms)
6518 PonderNextMoveEvent(!appData.ponderNextMove);
6520 if (appData.ponderNextMove) {
6521 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6523 XtSetArg(args[0], XtNleftBitmap, None);
6525 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6529 void PopupExitMessageProc(w, event, prms, nprms)
6537 appData.popupExitMessage = !appData.popupExitMessage;
6539 if (appData.popupExitMessage) {
6540 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6542 XtSetArg(args[0], XtNleftBitmap, None);
6544 XtSetValues(XtNameToWidget(menuBarWidget,
6545 "menuOptions.Popup Exit Message"), args, 1);
6548 void PopupMoveErrorsProc(w, event, prms, nprms)
6556 appData.popupMoveErrors = !appData.popupMoveErrors;
6558 if (appData.popupMoveErrors) {
6559 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6561 XtSetArg(args[0], XtNleftBitmap, None);
6563 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6567 void PremoveProc(w, event, prms, nprms)
6575 appData.premove = !appData.premove;
6577 if (appData.premove) {
6578 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6580 XtSetArg(args[0], XtNleftBitmap, None);
6582 XtSetValues(XtNameToWidget(menuBarWidget,
6583 "menuOptions.Premove"), args, 1);
6586 void QuietPlayProc(w, event, prms, nprms)
6594 appData.quietPlay = !appData.quietPlay;
6596 if (appData.quietPlay) {
6597 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6599 XtSetArg(args[0], XtNleftBitmap, None);
6601 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6605 void ShowCoordsProc(w, event, prms, nprms)
6613 appData.showCoords = !appData.showCoords;
6615 if (appData.showCoords) {
6616 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6618 XtSetArg(args[0], XtNleftBitmap, None);
6620 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6623 DrawPosition(True, NULL);
6626 void ShowThinkingProc(w, event, prms, nprms)
6632 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6633 ShowThinkingEvent();
6636 void HideThinkingProc(w, event, prms, nprms)
6644 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6645 ShowThinkingEvent();
6647 if (appData.hideThinkingFromHuman) {
6648 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6650 XtSetArg(args[0], XtNleftBitmap, None);
6652 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6656 void SaveOnExitProc(w, event, prms, nprms)
6664 saveSettingsOnExit = !saveSettingsOnExit;
6666 if (saveSettingsOnExit) {
6667 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6669 XtSetArg(args[0], XtNleftBitmap, None);
6671 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6675 void SaveSettingsProc(w, event, prms, nprms)
6681 SaveSettings(settingsFileName);
6684 void InfoProc(w, event, prms, nprms)
6691 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6696 void ManProc(w, event, prms, nprms)
6704 if (nprms && *nprms > 0)
6708 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6712 void HintProc(w, event, prms, nprms)
6721 void BookProc(w, event, prms, nprms)
6730 void AboutProc(w, event, prms, nprms)
6738 char *zippy = " (with Zippy code)";
6742 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6743 programVersion, zippy,
6744 "Copyright 1991 Digital Equipment Corporation",
6745 "Enhancements Copyright 1992-2009 Free Software Foundation",
6746 "Enhancements Copyright 2005 Alessandro Scotti",
6747 PACKAGE, " is free software and carries NO WARRANTY;",
6748 "see the file COPYING for more information.");
6749 ErrorPopUp(_("About XBoard"), buf, FALSE);
6752 void DebugProc(w, event, prms, nprms)
6758 appData.debugMode = !appData.debugMode;
6761 void AboutGameProc(w, event, prms, nprms)
6770 void NothingProc(w, event, prms, nprms)
6779 void Iconify(w, event, prms, nprms)
6788 XtSetArg(args[0], XtNiconic, True);
6789 XtSetValues(shellWidget, args, 1);
6792 void DisplayMessage(message, extMessage)
6793 char *message, *extMessage;
6795 /* display a message in the message widget */
6804 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6809 message = extMessage;
6813 /* need to test if messageWidget already exists, since this function
6814 can also be called during the startup, if for example a Xresource
6815 is not set up correctly */
6818 XtSetArg(arg, XtNlabel, message);
6819 XtSetValues(messageWidget, &arg, 1);
6825 void DisplayTitle(text)
6830 char title[MSG_SIZ];
6833 if (text == NULL) text = "";
6835 if (appData.titleInWindow) {
6837 XtSetArg(args[i], XtNlabel, text); i++;
6838 XtSetValues(titleWidget, args, i);
6841 if (*text != NULLCHAR) {
6843 strcpy(title, text);
6844 } else if (appData.icsActive) {
6845 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6846 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6847 } else if (appData.cmailGameName[0] != NULLCHAR) {
6848 snprintf(icon, sizeof(icon), "%s", "CMail");
6849 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6851 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6852 } else if (gameInfo.variant == VariantGothic) {
6853 strcpy(icon, programName);
6854 strcpy(title, GOTHIC);
6857 } else if (gameInfo.variant == VariantFalcon) {
6858 strcpy(icon, programName);
6859 strcpy(title, FALCON);
6861 } else if (appData.noChessProgram) {
6862 strcpy(icon, programName);
6863 strcpy(title, programName);
6865 strcpy(icon, first.tidy);
6866 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6869 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6870 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6871 XtSetValues(shellWidget, args, i);
6875 void DisplayError(message, error)
6882 if (appData.debugMode || appData.matchMode) {
6883 fprintf(stderr, "%s: %s\n", programName, message);
6886 if (appData.debugMode || appData.matchMode) {
6887 fprintf(stderr, "%s: %s: %s\n",
6888 programName, message, strerror(error));
6890 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6893 ErrorPopUp(_("Error"), message, FALSE);
6897 void DisplayMoveError(message)
6902 DrawPosition(FALSE, NULL);
6903 if (appData.debugMode || appData.matchMode) {
6904 fprintf(stderr, "%s: %s\n", programName, message);
6906 if (appData.popupMoveErrors) {
6907 ErrorPopUp(_("Error"), message, FALSE);
6909 DisplayMessage(message, "");
6914 void DisplayFatalError(message, error, status)
6920 errorExitStatus = status;
6922 fprintf(stderr, "%s: %s\n", programName, message);
6924 fprintf(stderr, "%s: %s: %s\n",
6925 programName, message, strerror(error));
6926 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6929 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6930 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6936 void DisplayInformation(message)
6940 ErrorPopUp(_("Information"), message, TRUE);
6943 void DisplayNote(message)
6947 ErrorPopUp(_("Note"), message, FALSE);
6951 NullXErrorCheck(dpy, error_event)
6953 XErrorEvent *error_event;
6958 void DisplayIcsInteractionTitle(message)
6961 if (oldICSInteractionTitle == NULL) {
6962 /* Magic to find the old window title, adapted from vim */
6963 char *wina = getenv("WINDOWID");
6965 Window win = (Window) atoi(wina);
6966 Window root, parent, *children;
6967 unsigned int nchildren;
6968 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6970 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6971 if (!XQueryTree(xDisplay, win, &root, &parent,
6972 &children, &nchildren)) break;
6973 if (children) XFree((void *)children);
6974 if (parent == root || parent == 0) break;
6977 XSetErrorHandler(oldHandler);
6979 if (oldICSInteractionTitle == NULL) {
6980 oldICSInteractionTitle = "xterm";
6983 printf("\033]0;%s\007", message);
6987 char pendingReplyPrefix[MSG_SIZ];
6988 ProcRef pendingReplyPR;
6990 void AskQuestionProc(w, event, prms, nprms)
6997 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7001 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7004 void AskQuestionPopDown()
7006 if (!askQuestionUp) return;
7007 XtPopdown(askQuestionShell);
7008 XtDestroyWidget(askQuestionShell);
7009 askQuestionUp = False;
7012 void AskQuestionReplyAction(w, event, prms, nprms)
7022 reply = XawDialogGetValueString(w = XtParent(w));
7023 strcpy(buf, pendingReplyPrefix);
7024 if (*buf) strcat(buf, " ");
7027 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7028 AskQuestionPopDown();
7030 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7033 void AskQuestionCallback(w, client_data, call_data)
7035 XtPointer client_data, call_data;
7040 XtSetArg(args[0], XtNlabel, &name);
7041 XtGetValues(w, args, 1);
7043 if (strcmp(name, _("cancel")) == 0) {
7044 AskQuestionPopDown();
7046 AskQuestionReplyAction(w, NULL, NULL, NULL);
7050 void AskQuestion(title, question, replyPrefix, pr)
7051 char *title, *question, *replyPrefix;
7055 Widget popup, layout, dialog, edit;
7061 strcpy(pendingReplyPrefix, replyPrefix);
7062 pendingReplyPR = pr;
7065 XtSetArg(args[i], XtNresizable, True); i++;
7066 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7067 askQuestionShell = popup =
7068 XtCreatePopupShell(title, transientShellWidgetClass,
7069 shellWidget, args, i);
7072 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7073 layoutArgs, XtNumber(layoutArgs));
7076 XtSetArg(args[i], XtNlabel, question); i++;
7077 XtSetArg(args[i], XtNvalue, ""); i++;
7078 XtSetArg(args[i], XtNborderWidth, 0); i++;
7079 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7082 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7083 (XtPointer) dialog);
7084 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7085 (XtPointer) dialog);
7087 XtRealizeWidget(popup);
7088 CatchDeleteWindow(popup, "AskQuestionPopDown");
7090 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7091 &x, &y, &win_x, &win_y, &mask);
7093 XtSetArg(args[0], XtNx, x - 10);
7094 XtSetArg(args[1], XtNy, y - 30);
7095 XtSetValues(popup, args, 2);
7097 XtPopup(popup, XtGrabExclusive);
7098 askQuestionUp = True;
7100 edit = XtNameToWidget(dialog, "*value");
7101 XtSetKeyboardFocus(popup, edit);
7109 if (*name == NULLCHAR) {
7111 } else if (strcmp(name, "$") == 0) {
7112 putc(BELLCHAR, stderr);
7115 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7123 PlaySound(appData.soundMove);
7129 PlaySound(appData.soundIcsWin);
7135 PlaySound(appData.soundIcsLoss);
7141 PlaySound(appData.soundIcsDraw);
7145 PlayIcsUnfinishedSound()
7147 PlaySound(appData.soundIcsUnfinished);
7153 PlaySound(appData.soundIcsAlarm);
7159 system("stty echo");
7165 system("stty -echo");
7169 Colorize(cc, continuation)
7174 int count, outCount, error;
7176 if (textColors[(int)cc].bg > 0) {
7177 if (textColors[(int)cc].fg > 0) {
7178 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7179 textColors[(int)cc].fg, textColors[(int)cc].bg);
7181 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7182 textColors[(int)cc].bg);
7185 if (textColors[(int)cc].fg > 0) {
7186 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7187 textColors[(int)cc].fg);
7189 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7192 count = strlen(buf);
7193 outCount = OutputToProcess(NoProc, buf, count, &error);
7194 if (outCount < count) {
7195 DisplayFatalError(_("Error writing to display"), error, 1);
7198 if (continuation) return;
7201 PlaySound(appData.soundShout);
7204 PlaySound(appData.soundSShout);
7207 PlaySound(appData.soundChannel1);
7210 PlaySound(appData.soundChannel);
7213 PlaySound(appData.soundKibitz);
7216 PlaySound(appData.soundTell);
7218 case ColorChallenge:
7219 PlaySound(appData.soundChallenge);
7222 PlaySound(appData.soundRequest);
7225 PlaySound(appData.soundSeek);
7236 return getpwuid(getuid())->pw_name;
7239 static char *ExpandPathName(path)
7242 static char static_buf[2000];
7243 char *d, *s, buf[2000];
7249 while (*s && isspace(*s))
7258 if (*(s+1) == '/') {
7259 strcpy(d, getpwuid(getuid())->pw_dir);
7264 *strchr(buf, '/') = 0;
7265 pwd = getpwnam(buf);
7268 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7272 strcpy(d, pwd->pw_dir);
7273 strcat(d, strchr(s+1, '/'));
7284 static char host_name[MSG_SIZ];
7286 #if HAVE_GETHOSTNAME
7287 gethostname(host_name, MSG_SIZ);
7289 #else /* not HAVE_GETHOSTNAME */
7290 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7291 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7293 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7295 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7296 #endif /* not HAVE_GETHOSTNAME */
7299 XtIntervalId delayedEventTimerXID = 0;
7300 DelayedEventCallback delayedEventCallback = 0;
7305 delayedEventTimerXID = 0;
7306 delayedEventCallback();
7310 ScheduleDelayedEvent(cb, millisec)
7311 DelayedEventCallback cb; long millisec;
7313 if(delayedEventTimerXID && delayedEventCallback == cb)
7314 // [HGM] alive: replace, rather than add or flush identical event
7315 XtRemoveTimeOut(delayedEventTimerXID);
7316 delayedEventCallback = cb;
7317 delayedEventTimerXID =
7318 XtAppAddTimeOut(appContext, millisec,
7319 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7322 DelayedEventCallback
7325 if (delayedEventTimerXID) {
7326 return delayedEventCallback;
7333 CancelDelayedEvent()
7335 if (delayedEventTimerXID) {
7336 XtRemoveTimeOut(delayedEventTimerXID);
7337 delayedEventTimerXID = 0;
7341 XtIntervalId loadGameTimerXID = 0;
7343 int LoadGameTimerRunning()
7345 return loadGameTimerXID != 0;
7348 int StopLoadGameTimer()
7350 if (loadGameTimerXID != 0) {
7351 XtRemoveTimeOut(loadGameTimerXID);
7352 loadGameTimerXID = 0;
7360 LoadGameTimerCallback(arg, id)
7364 loadGameTimerXID = 0;
7369 StartLoadGameTimer(millisec)
7373 XtAppAddTimeOut(appContext, millisec,
7374 (XtTimerCallbackProc) LoadGameTimerCallback,
7378 XtIntervalId analysisClockXID = 0;
7381 AnalysisClockCallback(arg, id)
7385 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7386 || appData.icsEngineAnalyze) { // [DM]
7387 AnalysisPeriodicEvent(0);
7388 StartAnalysisClock();
7393 StartAnalysisClock()
7396 XtAppAddTimeOut(appContext, 2000,
7397 (XtTimerCallbackProc) AnalysisClockCallback,
7401 XtIntervalId clockTimerXID = 0;
7403 int ClockTimerRunning()
7405 return clockTimerXID != 0;
7408 int StopClockTimer()
7410 if (clockTimerXID != 0) {
7411 XtRemoveTimeOut(clockTimerXID);
7420 ClockTimerCallback(arg, id)
7429 StartClockTimer(millisec)
7433 XtAppAddTimeOut(appContext, millisec,
7434 (XtTimerCallbackProc) ClockTimerCallback,
7439 DisplayTimerLabel(w, color, timer, highlight)
7448 /* check for low time warning */
7449 Pixel foregroundOrWarningColor = timerForegroundPixel;
7452 appData.lowTimeWarning &&
7453 (timer / 1000) < appData.icsAlarmTime)
7454 foregroundOrWarningColor = lowTimeWarningColor;
7456 if (appData.clockMode) {
7457 sprintf(buf, "%s: %s", color, TimeString(timer));
7458 XtSetArg(args[0], XtNlabel, buf);
7460 sprintf(buf, "%s ", color);
7461 XtSetArg(args[0], XtNlabel, buf);
7466 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7467 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7469 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7470 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7473 XtSetValues(w, args, 3);
7477 DisplayWhiteClock(timeRemaining, highlight)
7483 if(appData.noGUI) return;
7484 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7485 if (highlight && iconPixmap == bIconPixmap) {
7486 iconPixmap = wIconPixmap;
7487 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7488 XtSetValues(shellWidget, args, 1);
7493 DisplayBlackClock(timeRemaining, highlight)
7499 if(appData.noGUI) return;
7500 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7501 if (highlight && iconPixmap == wIconPixmap) {
7502 iconPixmap = bIconPixmap;
7503 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7504 XtSetValues(shellWidget, args, 1);
7522 int StartChildProcess(cmdLine, dir, pr)
7529 int to_prog[2], from_prog[2];
7533 if (appData.debugMode) {
7534 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7537 /* We do NOT feed the cmdLine to the shell; we just
7538 parse it into blank-separated arguments in the
7539 most simple-minded way possible.
7542 strcpy(buf, cmdLine);
7545 while(*p == ' ') p++;
7547 if(*p == '"' || *p == '\'')
7548 p = strchr(++argv[i-1], *p);
7549 else p = strchr(p, ' ');
7550 if (p == NULL) break;
7555 SetUpChildIO(to_prog, from_prog);
7557 if ((pid = fork()) == 0) {
7559 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7560 close(to_prog[1]); // first close the unused pipe ends
7561 close(from_prog[0]);
7562 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7563 dup2(from_prog[1], 1);
7564 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7565 close(from_prog[1]); // and closing again loses one of the pipes!
7566 if(fileno(stderr) >= 2) // better safe than sorry...
7567 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7569 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7574 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7576 execvp(argv[0], argv);
7578 /* If we get here, exec failed */
7583 /* Parent process */
7585 close(from_prog[1]);
7587 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7590 cp->fdFrom = from_prog[0];
7591 cp->fdTo = to_prog[1];
7596 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7597 static RETSIGTYPE AlarmCallBack(int n)
7603 DestroyChildProcess(pr, signalType)
7607 ChildProc *cp = (ChildProc *) pr;
7609 if (cp->kind != CPReal) return;
7611 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7612 signal(SIGALRM, AlarmCallBack);
7614 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7615 kill(cp->pid, SIGKILL); // kill it forcefully
7616 wait((int *) 0); // and wait again
7620 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7622 /* Process is exiting either because of the kill or because of
7623 a quit command sent by the backend; either way, wait for it to die.
7632 InterruptChildProcess(pr)
7635 ChildProc *cp = (ChildProc *) pr;
7637 if (cp->kind != CPReal) return;
7638 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7641 int OpenTelnet(host, port, pr)
7646 char cmdLine[MSG_SIZ];
7648 if (port[0] == NULLCHAR) {
7649 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7651 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7653 return StartChildProcess(cmdLine, "", pr);
7656 int OpenTCP(host, port, pr)
7662 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7663 #else /* !OMIT_SOCKETS */
7665 struct sockaddr_in sa;
7667 unsigned short uport;
7670 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7674 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7675 sa.sin_family = AF_INET;
7676 sa.sin_addr.s_addr = INADDR_ANY;
7677 uport = (unsigned short) 0;
7678 sa.sin_port = htons(uport);
7679 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7683 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7684 if (!(hp = gethostbyname(host))) {
7686 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7687 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7688 hp->h_addrtype = AF_INET;
7690 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7691 hp->h_addr_list[0] = (char *) malloc(4);
7692 hp->h_addr_list[0][0] = b0;
7693 hp->h_addr_list[0][1] = b1;
7694 hp->h_addr_list[0][2] = b2;
7695 hp->h_addr_list[0][3] = b3;
7700 sa.sin_family = hp->h_addrtype;
7701 uport = (unsigned short) atoi(port);
7702 sa.sin_port = htons(uport);
7703 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7705 if (connect(s, (struct sockaddr *) &sa,
7706 sizeof(struct sockaddr_in)) < 0) {
7710 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7717 #endif /* !OMIT_SOCKETS */
7722 int OpenCommPort(name, pr)
7729 fd = open(name, 2, 0);
7730 if (fd < 0) return errno;
7732 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7742 int OpenLoopback(pr)
7748 SetUpChildIO(to, from);
7750 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7753 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7760 int OpenRcmd(host, user, cmd, pr)
7761 char *host, *user, *cmd;
7764 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7768 #define INPUT_SOURCE_BUF_SIZE 8192
7777 char buf[INPUT_SOURCE_BUF_SIZE];
7782 DoInputCallback(closure, source, xid)
7787 InputSource *is = (InputSource *) closure;
7792 if (is->lineByLine) {
7793 count = read(is->fd, is->unused,
7794 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7796 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7799 is->unused += count;
7801 while (p < is->unused) {
7802 q = memchr(p, '\n', is->unused - p);
7803 if (q == NULL) break;
7805 (is->func)(is, is->closure, p, q - p, 0);
7809 while (p < is->unused) {
7814 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7819 (is->func)(is, is->closure, is->buf, count, error);
7823 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7830 ChildProc *cp = (ChildProc *) pr;
7832 is = (InputSource *) calloc(1, sizeof(InputSource));
7833 is->lineByLine = lineByLine;
7837 is->fd = fileno(stdin);
7839 is->kind = cp->kind;
7840 is->fd = cp->fdFrom;
7843 is->unused = is->buf;
7846 is->xid = XtAppAddInput(appContext, is->fd,
7847 (XtPointer) (XtInputReadMask),
7848 (XtInputCallbackProc) DoInputCallback,
7850 is->closure = closure;
7851 return (InputSourceRef) is;
7855 RemoveInputSource(isr)
7858 InputSource *is = (InputSource *) isr;
7860 if (is->xid == 0) return;
7861 XtRemoveInput(is->xid);
7865 int OutputToProcess(pr, message, count, outError)
7871 static int line = 0;
7872 ChildProc *cp = (ChildProc *) pr;
7877 if (appData.noJoin || !appData.useInternalWrap)
7878 outCount = fwrite(message, 1, count, stdout);
7881 int width = get_term_width();
7882 int len = wrap(NULL, message, count, width, &line);
7883 char *msg = malloc(len);
7887 outCount = fwrite(message, 1, count, stdout);
7890 dbgchk = wrap(msg, message, count, width, &line);
7891 if (dbgchk != len && appData.debugMode)
7892 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7893 outCount = fwrite(msg, 1, dbgchk, stdout);
7899 outCount = write(cp->fdTo, message, count);
7909 /* Output message to process, with "ms" milliseconds of delay
7910 between each character. This is needed when sending the logon
7911 script to ICC, which for some reason doesn't like the
7912 instantaneous send. */
7913 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7920 ChildProc *cp = (ChildProc *) pr;
7925 r = write(cp->fdTo, message++, 1);
7938 /**** Animation code by Hugh Fisher, DCS, ANU.
7940 Known problem: if a window overlapping the board is
7941 moved away while a piece is being animated underneath,
7942 the newly exposed area won't be updated properly.
7943 I can live with this.
7945 Known problem: if you look carefully at the animation
7946 of pieces in mono mode, they are being drawn as solid
7947 shapes without interior detail while moving. Fixing
7948 this would be a major complication for minimal return.
7951 /* Masks for XPM pieces. Black and white pieces can have
7952 different shapes, but in the interest of retaining my
7953 sanity pieces must have the same outline on both light
7954 and dark squares, and all pieces must use the same
7955 background square colors/images. */
7957 static int xpmDone = 0;
7960 CreateAnimMasks (pieceDepth)
7967 unsigned long plane;
7970 /* Need a bitmap just to get a GC with right depth */
7971 buf = XCreatePixmap(xDisplay, xBoardWindow,
7973 values.foreground = 1;
7974 values.background = 0;
7975 /* Don't use XtGetGC, not read only */
7976 maskGC = XCreateGC(xDisplay, buf,
7977 GCForeground | GCBackground, &values);
7978 XFreePixmap(xDisplay, buf);
7980 buf = XCreatePixmap(xDisplay, xBoardWindow,
7981 squareSize, squareSize, pieceDepth);
7982 values.foreground = XBlackPixel(xDisplay, xScreen);
7983 values.background = XWhitePixel(xDisplay, xScreen);
7984 bufGC = XCreateGC(xDisplay, buf,
7985 GCForeground | GCBackground, &values);
7987 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7988 /* Begin with empty mask */
7989 if(!xpmDone) // [HGM] pieces: keep using existing
7990 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7991 squareSize, squareSize, 1);
7992 XSetFunction(xDisplay, maskGC, GXclear);
7993 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7994 0, 0, squareSize, squareSize);
7996 /* Take a copy of the piece */
8001 XSetFunction(xDisplay, bufGC, GXcopy);
8002 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8004 0, 0, squareSize, squareSize, 0, 0);
8006 /* XOR the background (light) over the piece */
8007 XSetFunction(xDisplay, bufGC, GXxor);
8009 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8010 0, 0, squareSize, squareSize, 0, 0);
8012 XSetForeground(xDisplay, bufGC, lightSquareColor);
8013 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8016 /* We now have an inverted piece image with the background
8017 erased. Construct mask by just selecting all the non-zero
8018 pixels - no need to reconstruct the original image. */
8019 XSetFunction(xDisplay, maskGC, GXor);
8021 /* Might be quicker to download an XImage and create bitmap
8022 data from it rather than this N copies per piece, but it
8023 only takes a fraction of a second and there is a much
8024 longer delay for loading the pieces. */
8025 for (n = 0; n < pieceDepth; n ++) {
8026 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8027 0, 0, squareSize, squareSize,
8033 XFreePixmap(xDisplay, buf);
8034 XFreeGC(xDisplay, bufGC);
8035 XFreeGC(xDisplay, maskGC);
8039 InitAnimState (anim, info)
8041 XWindowAttributes * info;
8046 /* Each buffer is square size, same depth as window */
8047 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8048 squareSize, squareSize, info->depth);
8049 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8050 squareSize, squareSize, info->depth);
8052 /* Create a plain GC for blitting */
8053 mask = GCForeground | GCBackground | GCFunction |
8054 GCPlaneMask | GCGraphicsExposures;
8055 values.foreground = XBlackPixel(xDisplay, xScreen);
8056 values.background = XWhitePixel(xDisplay, xScreen);
8057 values.function = GXcopy;
8058 values.plane_mask = AllPlanes;
8059 values.graphics_exposures = False;
8060 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8062 /* Piece will be copied from an existing context at
8063 the start of each new animation/drag. */
8064 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8066 /* Outline will be a read-only copy of an existing */
8067 anim->outlineGC = None;
8073 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8074 XWindowAttributes info;
8076 if (xpmDone && gameInfo.variant == old) return;
8077 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8078 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8080 InitAnimState(&game, &info);
8081 InitAnimState(&player, &info);
8083 /* For XPM pieces, we need bitmaps to use as masks. */
8085 CreateAnimMasks(info.depth);
8091 static Boolean frameWaiting;
8093 static RETSIGTYPE FrameAlarm (sig)
8096 frameWaiting = False;
8097 /* In case System-V style signals. Needed?? */
8098 signal(SIGALRM, FrameAlarm);
8105 struct itimerval delay;
8107 XSync(xDisplay, False);
8110 frameWaiting = True;
8111 signal(SIGALRM, FrameAlarm);
8112 delay.it_interval.tv_sec =
8113 delay.it_value.tv_sec = time / 1000;
8114 delay.it_interval.tv_usec =
8115 delay.it_value.tv_usec = (time % 1000) * 1000;
8116 setitimer(ITIMER_REAL, &delay, NULL);
8117 while (frameWaiting) pause();
8118 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8119 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8120 setitimer(ITIMER_REAL, &delay, NULL);
8130 XSync(xDisplay, False);
8132 usleep(time * 1000);
8137 /* Convert board position to corner of screen rect and color */
8140 ScreenSquare(column, row, pt, color)
8141 int column; int row; XPoint * pt; int * color;
8144 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8145 pt->y = lineGap + row * (squareSize + lineGap);
8147 pt->x = lineGap + column * (squareSize + lineGap);
8148 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8150 *color = SquareColor(row, column);
8153 /* Convert window coords to square */
8156 BoardSquare(x, y, column, row)
8157 int x; int y; int * column; int * row;
8159 *column = EventToSquare(x, BOARD_WIDTH);
8160 if (flipView && *column >= 0)
8161 *column = BOARD_WIDTH - 1 - *column;
8162 *row = EventToSquare(y, BOARD_HEIGHT);
8163 if (!flipView && *row >= 0)
8164 *row = BOARD_HEIGHT - 1 - *row;
8169 #undef Max /* just in case */
8171 #define Max(a, b) ((a) > (b) ? (a) : (b))
8172 #define Min(a, b) ((a) < (b) ? (a) : (b))
8175 SetRect(rect, x, y, width, height)
8176 XRectangle * rect; int x; int y; int width; int height;
8180 rect->width = width;
8181 rect->height = height;
8184 /* Test if two frames overlap. If they do, return
8185 intersection rect within old and location of
8186 that rect within new. */
8189 Intersect(old, new, size, area, pt)
8190 XPoint * old; XPoint * new;
8191 int size; XRectangle * area; XPoint * pt;
8193 if (old->x > new->x + size || new->x > old->x + size ||
8194 old->y > new->y + size || new->y > old->y + size) {
8197 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8198 size - abs(old->x - new->x), size - abs(old->y - new->y));
8199 pt->x = Max(old->x - new->x, 0);
8200 pt->y = Max(old->y - new->y, 0);
8205 /* For two overlapping frames, return the rect(s)
8206 in the old that do not intersect with the new. */
8209 CalcUpdateRects(old, new, size, update, nUpdates)
8210 XPoint * old; XPoint * new; int size;
8211 XRectangle update[]; int * nUpdates;
8215 /* If old = new (shouldn't happen) then nothing to draw */
8216 if (old->x == new->x && old->y == new->y) {
8220 /* Work out what bits overlap. Since we know the rects
8221 are the same size we don't need a full intersect calc. */
8223 /* Top or bottom edge? */
8224 if (new->y > old->y) {
8225 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8227 } else if (old->y > new->y) {
8228 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8229 size, old->y - new->y);
8232 /* Left or right edge - don't overlap any update calculated above. */
8233 if (new->x > old->x) {
8234 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8235 new->x - old->x, size - abs(new->y - old->y));
8237 } else if (old->x > new->x) {
8238 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8239 old->x - new->x, size - abs(new->y - old->y));
8246 /* Generate a series of frame coords from start->mid->finish.
8247 The movement rate doubles until the half way point is
8248 reached, then halves back down to the final destination,
8249 which gives a nice slow in/out effect. The algorithmn
8250 may seem to generate too many intermediates for short
8251 moves, but remember that the purpose is to attract the
8252 viewers attention to the piece about to be moved and
8253 then to where it ends up. Too few frames would be less
8257 Tween(start, mid, finish, factor, frames, nFrames)
8258 XPoint * start; XPoint * mid;
8259 XPoint * finish; int factor;
8260 XPoint frames[]; int * nFrames;
8262 int fraction, n, count;
8266 /* Slow in, stepping 1/16th, then 1/8th, ... */
8268 for (n = 0; n < factor; n++)
8270 for (n = 0; n < factor; n++) {
8271 frames[count].x = start->x + (mid->x - start->x) / fraction;
8272 frames[count].y = start->y + (mid->y - start->y) / fraction;
8274 fraction = fraction / 2;
8278 frames[count] = *mid;
8281 /* Slow out, stepping 1/2, then 1/4, ... */
8283 for (n = 0; n < factor; n++) {
8284 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8285 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8287 fraction = fraction * 2;
8292 /* Draw a piece on the screen without disturbing what's there */
8295 SelectGCMask(piece, clip, outline, mask)
8296 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8300 /* Bitmap for piece being moved. */
8301 if (appData.monoMode) {
8302 *mask = *pieceToSolid(piece);
8303 } else if (useImages) {
8305 *mask = xpmMask[piece];
8307 *mask = ximMaskPm[piece];
8310 *mask = *pieceToSolid(piece);
8313 /* GC for piece being moved. Square color doesn't matter, but
8314 since it gets modified we make a copy of the original. */
8316 if (appData.monoMode)
8321 if (appData.monoMode)
8326 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8328 /* Outline only used in mono mode and is not modified */
8330 *outline = bwPieceGC;
8332 *outline = wbPieceGC;
8336 OverlayPiece(piece, clip, outline, dest)
8337 ChessSquare piece; GC clip; GC outline; Drawable dest;
8342 /* Draw solid rectangle which will be clipped to shape of piece */
8343 XFillRectangle(xDisplay, dest, clip,
8344 0, 0, squareSize, squareSize);
8345 if (appData.monoMode)
8346 /* Also draw outline in contrasting color for black
8347 on black / white on white cases */
8348 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8349 0, 0, squareSize, squareSize, 0, 0, 1);
8351 /* Copy the piece */
8356 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8358 0, 0, squareSize, squareSize,
8363 /* Animate the movement of a single piece */
8366 BeginAnimation(anim, piece, startColor, start)
8374 /* The old buffer is initialised with the start square (empty) */
8375 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8376 anim->prevFrame = *start;
8378 /* The piece will be drawn using its own bitmap as a matte */
8379 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8380 XSetClipMask(xDisplay, anim->pieceGC, mask);
8384 AnimationFrame(anim, frame, piece)
8389 XRectangle updates[4];
8394 /* Save what we are about to draw into the new buffer */
8395 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8396 frame->x, frame->y, squareSize, squareSize,
8399 /* Erase bits of the previous frame */
8400 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8401 /* Where the new frame overlapped the previous,
8402 the contents in newBuf are wrong. */
8403 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8404 overlap.x, overlap.y,
8405 overlap.width, overlap.height,
8407 /* Repaint the areas in the old that don't overlap new */
8408 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8409 for (i = 0; i < count; i++)
8410 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8411 updates[i].x - anim->prevFrame.x,
8412 updates[i].y - anim->prevFrame.y,
8413 updates[i].width, updates[i].height,
8414 updates[i].x, updates[i].y);
8416 /* Easy when no overlap */
8417 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8418 0, 0, squareSize, squareSize,
8419 anim->prevFrame.x, anim->prevFrame.y);
8422 /* Save this frame for next time round */
8423 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8424 0, 0, squareSize, squareSize,
8426 anim->prevFrame = *frame;
8428 /* Draw piece over original screen contents, not current,
8429 and copy entire rect. Wipes out overlapping piece images. */
8430 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8431 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8432 0, 0, squareSize, squareSize,
8433 frame->x, frame->y);
8437 EndAnimation (anim, finish)
8441 XRectangle updates[4];
8446 /* The main code will redraw the final square, so we
8447 only need to erase the bits that don't overlap. */
8448 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8449 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8450 for (i = 0; i < count; i++)
8451 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8452 updates[i].x - anim->prevFrame.x,
8453 updates[i].y - anim->prevFrame.y,
8454 updates[i].width, updates[i].height,
8455 updates[i].x, updates[i].y);
8457 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8458 0, 0, squareSize, squareSize,
8459 anim->prevFrame.x, anim->prevFrame.y);
8464 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8466 ChessSquare piece; int startColor;
8467 XPoint * start; XPoint * finish;
8468 XPoint frames[]; int nFrames;
8472 BeginAnimation(anim, piece, startColor, start);
8473 for (n = 0; n < nFrames; n++) {
8474 AnimationFrame(anim, &(frames[n]), piece);
8475 FrameDelay(appData.animSpeed);
8477 EndAnimation(anim, finish);
8480 /* Main control logic for deciding what to animate and how */
8483 AnimateMove(board, fromX, fromY, toX, toY)
8492 XPoint start, finish, mid;
8493 XPoint frames[kFactor * 2 + 1];
8494 int nFrames, startColor, endColor;
8496 /* Are we animating? */
8497 if (!appData.animate || appData.blindfold)
8500 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8501 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8502 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8504 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8505 piece = board[fromY][fromX];
8506 if (piece >= EmptySquare) return;
8511 hop = (piece == WhiteKnight || piece == BlackKnight);
8514 if (appData.debugMode) {
8515 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8516 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8517 piece, fromX, fromY, toX, toY); }
8519 ScreenSquare(fromX, fromY, &start, &startColor);
8520 ScreenSquare(toX, toY, &finish, &endColor);
8523 /* Knight: make diagonal movement then straight */
8524 if (abs(toY - fromY) < abs(toX - fromX)) {
8525 mid.x = start.x + (finish.x - start.x) / 2;
8529 mid.y = start.y + (finish.y - start.y) / 2;
8532 mid.x = start.x + (finish.x - start.x) / 2;
8533 mid.y = start.y + (finish.y - start.y) / 2;
8536 /* Don't use as many frames for very short moves */
8537 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8538 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8540 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8541 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8543 /* Be sure end square is redrawn */
8544 damage[toY][toX] = True;
8548 DragPieceBegin(x, y)
8551 int boardX, boardY, color;
8554 /* Are we animating? */
8555 if (!appData.animateDragging || appData.blindfold)
8558 /* Figure out which square we start in and the
8559 mouse position relative to top left corner. */
8560 BoardSquare(x, y, &boardX, &boardY);
8561 player.startBoardX = boardX;
8562 player.startBoardY = boardY;
8563 ScreenSquare(boardX, boardY, &corner, &color);
8564 player.startSquare = corner;
8565 player.startColor = color;
8566 /* As soon as we start dragging, the piece will jump slightly to
8567 be centered over the mouse pointer. */
8568 player.mouseDelta.x = squareSize/2;
8569 player.mouseDelta.y = squareSize/2;
8570 /* Initialise animation */
8571 player.dragPiece = PieceForSquare(boardX, boardY);
8573 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8574 player.dragActive = True;
8575 BeginAnimation(&player, player.dragPiece, color, &corner);
8576 /* Mark this square as needing to be redrawn. Note that
8577 we don't remove the piece though, since logically (ie
8578 as seen by opponent) the move hasn't been made yet. */
8579 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8580 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8581 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8582 corner.x, corner.y, squareSize, squareSize,
8583 0, 0); // [HGM] zh: unstack in stead of grab
8584 damage[boardY][boardX] = True;
8586 player.dragActive = False;
8596 /* Are we animating? */
8597 if (!appData.animateDragging || appData.blindfold)
8601 if (! player.dragActive)
8603 /* Move piece, maintaining same relative position
8604 of mouse within square */
8605 corner.x = x - player.mouseDelta.x;
8606 corner.y = y - player.mouseDelta.y;
8607 AnimationFrame(&player, &corner, player.dragPiece);
8609 if (appData.highlightDragging) {
8611 BoardSquare(x, y, &boardX, &boardY);
8612 SetHighlights(fromX, fromY, boardX, boardY);
8621 int boardX, boardY, color;
8624 /* Are we animating? */
8625 if (!appData.animateDragging || appData.blindfold)
8629 if (! player.dragActive)
8631 /* Last frame in sequence is square piece is
8632 placed on, which may not match mouse exactly. */
8633 BoardSquare(x, y, &boardX, &boardY);
8634 ScreenSquare(boardX, boardY, &corner, &color);
8635 EndAnimation(&player, &corner);
8637 /* Be sure end square is redrawn */
8638 damage[boardY][boardX] = True;
8640 /* This prevents weird things happening with fast successive
8641 clicks which on my Sun at least can cause motion events
8642 without corresponding press/release. */
8643 player.dragActive = False;
8646 /* Handle expose event while piece being dragged */
8651 if (!player.dragActive || appData.blindfold)
8654 /* What we're doing: logically, the move hasn't been made yet,
8655 so the piece is still in it's original square. But visually
8656 it's being dragged around the board. So we erase the square
8657 that the piece is on and draw it at the last known drag point. */
8658 BlankSquare(player.startSquare.x, player.startSquare.y,
8659 player.startColor, EmptySquare, xBoardWindow);
8660 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8661 damage[player.startBoardY][player.startBoardX] = TRUE;
8664 #include <sys/ioctl.h>
8665 int get_term_width()
8667 int fd, default_width;
8670 default_width = 79; // this is FICS default anyway...
8672 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8674 if (!ioctl(fd, TIOCGSIZE, &win))
8675 default_width = win.ts_cols;
8676 #elif defined(TIOCGWINSZ)
8678 if (!ioctl(fd, TIOCGWINSZ, &win))
8679 default_width = win.ws_col;
8681 return default_width;
8684 void update_ics_width()
8686 static int old_width = 0;
8687 int new_width = get_term_width();
8689 if (old_width != new_width)
8690 ics_printf("set width %d\n", new_width);
8691 old_width = new_width;
8694 void NotifyFrontendLogin()